PIC 端口行为随机

PIC ports behaves randomly

我已经尝试了几个小时来点亮按钮上的简单 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, External Clock, 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 永远不会关闭,但当按钮未按下时,它会随机打开或关闭。

在输入上观察到的随机值问题通常是由浮动输入引起的。如果输入不是由输出或某种源驱动,则认为输入处于 浮动 状态。在这种情况下,浮动输入就像天线一样,它可以随机获得任何电压电平,并且连接到它的逻辑在 1 和 0 之间随机切换。

似乎大多数时候,电子学和 uC 初学者是在尝试使用按钮时才第一次了解它们。我的经历很相似。当我的手指靠近按钮时输入被触发,但在我真正按下甚至触摸它之前。后来观察到uC的相邻输出管脚变化也能触发

幸运的是,解决方案很简单。只需加一个上拉或下拉电阻,即使按键未按下,输出也由VDD或GND驱动。上拉似乎更受欢迎(我不确定为什么),因此您通常以这样的方式连接按钮,即在按下按钮时将输入引脚拉至地面,并在按钮之间提供一个上拉电阻引脚和 VDD。在这种情况下,您的程序逻辑在按下按钮时将输入读取为 0。

顺便说一句,您可以将引脚直接连接到 VDD 以防止其悬空。但在这种情况下,按下按钮会将 VDD 短路到 GND,使 VDD 崩溃并重置 uC。这也会损坏电源调节器(实际上它们中的大多数都有热关断保护自己)、按钮本身或电线(或 PCB 上的走线)。这就是为什么你需要一个电阻。

大多数微控制器还提供内部弱上拉,可以通过软件激活。在这里,weak 意味着这些电阻器具有高值(如 100k 欧姆)并且它们不会 strongly 拉动引脚。如果您需要更强大的(例如拉起通信线路),您可能需要使用外部的。

一些较新的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