问题描述
我尝试了几个小时来点亮一个简单的 LED 按钮,但没有成功。由于某种原因,引脚似乎随机变低和变高。
我使用的是 MPLAB X IDE v5.54 和 PIC12F1822。 谁能发现我的错误?
代码如下:
// CONfig1
#pragma config FOSC = ECH // Oscillator Selection (ECH,External Clock,High Power Mode (4-32 MHz): device clock supplied to CLKIN pin)
#pragma config WDTE = ON // Watchdog Timer Enable (WDT enabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // brown-out Reset Enable (brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FcmeN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
// CONfig2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // brown-out Reset Voltage Selection (brown-out Reset Voltage (Vbor),low trip point selected.)
#pragma config LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled)
#include <xc.h>
#define _XTAL_FREQ 8000000 // SET frequency as 8000000 bit because of the 8 MHz clock
int main(int argc,char** argv) {
OSCCON = 0xF0; // Internal oscillator 8MHz and PLL enabled
ADCON0 = 0; // disable ADC module
ANSELAbits.ANSA2 = 0; // SET LED PIN to Digital
ANSELAbits.ANSA4 = 0; // SET Button pin to Digital
TRISAbits.TRISA2 = 0; // LED bit is output
TRISAbits.TRISA4 = 1; // Button bit is input
PORTAbits.RA4 = 0; // Button bit low initial
PORTAbits.RA2 = 0; // LED bit low initial
while (1) {
while (PORTAbits.RA4 == 0); // Wait until button is pressed
__delay_ms(100); // wait 100ms
PORTAbits.RA2 = 1; // Light up the LED
__delay_ms(100); // wait 100ms
while (PORTAbits.RA4 == 1); // Wait until button release
__delay_ms(100); // wait 100ms
PORTAbits.RA2 = 0; // Turn off the LED
__delay_ms(100); // wait 100ms
}
return (EXIT_SUCCESS);
}
我尝试了很多事情,例如:
- 天知道要调整配置多少次
- 使所有引脚一一输入、输出、数字、模拟等。
我想不出别的了。
任何帮助将不胜感激。
编辑 1
这是我拥有的最新代码。这一个随机打开和关闭 LED。我还禁用了看门狗定时器:
// CONfig1
#pragma config FOSC = ECH // Oscillator Selection (ECH,High Power Mode (4-32 MHz): device clock supplied to CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // brown-out Reset Enable (brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FcmeN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
// CONfig2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // brown-out Reset Voltage Selection (brown-out Reset Voltage (Vbor),low trip point selected.)
#pragma config LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled)
#include <xc.h> // include standard header file
// DeFinitions
#define _XTAL_FREQ 16000000 // this is used by the __delay_ms(xx) and __delay_us(xx) functions
void main() {
// set up oscillator control register
OSCCONbits.SPLLEN = 0; // PLL is disabled
OSCCONbits.IRCF = 0x0F; //set OSCCON IRCF bits to select OSC frequency=16Mhz
OSCCONbits.SCS = 0x02; //set the SCS bits to select internal oscillator block
ANSELAbits.ANSA0 = 0; // Set to digital
ANSELAbits.ANSA1 = 0; // Set to digital
ANSELAbits.ANSA2 = 0; // Set to digital
ANSELAbits.ANSA4 = 0; // Set to digital
// Set up I/O pins
// PORT A Assignments
TRISAbits.TRISA0 = 0; // RA0 = Digital Voltage out
TRISAbits.TRISA1 = 0; // RA1 = Digital Voltage out
TRISAbits.TRISA2 = 0; // RA2 = Digital Voltage out
TRISAbits.TRISA3 = 0; // RA3 = Digital Voltage out
TRISAbits.TRISA4 = 1; // RA4 = Digital Voltage in
TRISAbits.TRISA5 = 0; // RA0 = Digital Voltage out
PORTAbits.RA0 = 0;
PORTAbits.RA1 = 0;
PORTAbits.RA2 = 0;
PORTAbits.RA3 = 0;
PORTAbits.RA4 = 0;
PORTAbits.RA5 = 0;
// Set up ADC
ADCON0 = 0; // ADC is off
for (;;) {
__delay_ms(100); // wait 100ms
if (PORTAbits.RA4 == 0) {
LATAbits.LATA2 = 0;
} else {
LATAbits.LATA2 = 1;
}
}
}
好的,这是我观察到的。按下按钮时 LED 永不熄灭,但未按下按钮时,LED 随机亮起或熄灭。
解决方法
在输入上观察到的随机值问题通常是由浮动输入引起的。如果输入不是由输出或某种源驱动的,则它被视为处于 浮动 状态。在这种情况下,浮动输入就像天线一样,它可以随机获得任何电压电平,并且连接到它的逻辑在 1 和 0 之间随机切换。
似乎大多数时候,电子和 uC 初学者在尝试按钮时都是第一次了解它们。我的经历很相似。当我将手指靠近按钮时,输入就被触发,但在我实际按下或什至触摸它之前。后来我观察到也可以通过uC相邻输出引脚的变化来触发。
幸运的是,解决方案很简单。只需增加一个上拉或下拉电阻,即使没有按下按钮,输出也由 VDD 或 GND 驱动。上拉似乎更受欢迎(我不知道为什么),所以你通常以这样的方式连接按钮,当按下按钮时它会将输入引脚拉到地,并在两个按钮之间提供一个上拉电阻引脚和 VDD。在这种情况下,您的程序逻辑在按下按钮时将输入读取为 0。
顺便说一句,您可以将引脚直接连接到 VDD 以防止其浮动。但在这种情况下,按下按钮会使 VDD 与 GND 短路,破坏 VDD 并重置 uC。这也会损坏电源调节器(实际上它们中的大多数都有热关断以保护自己)、按钮本身或电线(或 PCB 上的走线)。这就是您需要电阻器的原因。
大多数 uC 还提供可以由软件激活的内部弱上拉。在这里,弱意味着这些电阻器具有很高的值(如 100k 欧姆)并且它们不会强力拉动引脚。如果您需要更强大的功能(例如拉起通信线路),您可能需要使用外部功能。
一些较新的 uC 也可能提供内部弱下拉电阻。 STM32 uC 具有此功能。您的 PIC12F1822 只有上拉电阻,但幸运的是它们可以单独控制。在一些较旧的 PIC 型号中,您有一个开关来激活 PORTB 的所有引脚上的上拉。
要在 RA4 上激活内部弱上拉:
OPTION_REGbits.nWPUEN = 0; // Global pull-up enable bit (inverted)
WPUAbits.WPUA4 = 1; // Individual pin pull-up enable bit