PIC 端口的行为是随机的

问题描述

我尝试了几个小时来点亮一个简单的 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