You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PIC16F877A C语言编写0-36循环计数器代码报错问题求助

PIC16F877A数码管计数器功能异常排查

问题背景

  • 开发环境:MPLAB-X + Proteus,C语言开发,主控芯片为PIC16F877A
  • 预期功能:按键触发累加计数,从0开始计数到36后自动归零循环,两位数码管显示当前数值
  • 异常情况:归零逻辑未按预期生效,已附芯片位配置、运行报错截图供参考

原实现代码

#include <xc.h>
#define _XTAL_FREQ 4000000

// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)


int ar = 0;
int de = 0, un = 0, A = 0;
int Display[10] = {0XC0, 0XF9, 0XA4, 0XB0, 0X99, 0X92, 0X82, 0XF8, 0X80, 0X98};
void visualizacion(void);
void incremento(void);

void main(void)
{
    TRISC = 0X00;         // PUERTO C COMO SALIDA
    TRISB = 0X00;         // PUERTO B SALIDA
    TRISDbits.TRISD0 = 1; // PUERTO D0 COMO ENTRADA
    
    while (1)
    {
        if (PORTDbits.RD0 == 1)
        {
            ar = 1;
        }
        if (PORTDbits.RD0 == 0 && ar == 1)
        {
            un = un+1;
            ar = 0;
        }
        visualizacion();
        incremento();
    }
}

void visualizacion(void)
{
    PORTC = 0X01;
    PORTB = Display[un];
    __delay_us (500);
    
    PORTC = 0X02;
    PORTB = Display[de];
    __delay_us (500);
    
}

void incremento(void)
{
    if (un >= 10)
    {
        un = 0;
        de = de+1;
    }
    if(de >= 3 && un >= 6)
    {
        de = 0;
    }
}

问题根因

  1. 归零逻辑错误
    原计数处理函数中归零判断条件为de >=3 && un >=6,存在两个缺陷:一是使用>=判断会导致十位为3时,个位为6/7/8/9都会触发归零,不符合计数到36才复位的要求;二是触发判断后仅将十位de置0,未复位个位un,触发后会直接显示06而非0,逻辑不完整。
  2. 进位与归零逻辑时序冲突
    原逻辑先处理个位进位,再判断归零:当计数到39后再次触发计数,un先自增到10,触发进位逻辑将un置0、de自增为4,此时un为0永远无法满足un>=6的判断条件,会出现十位数值溢出、数码管显示乱码的问题。
  3. 硬件配置隐患
    配置位中FOSC = HS适配4MHz以上高速晶振,若使用4MHz晶振应选择XT模式,否则可能出现晶振不起振、程序完全不运行的问题;关闭上电延时PWRTE = OFF也会增加上电启动失败的概率。
  4. 编译失败诱因
    代码中定义了变量A但全程未使用,若MPLAB-X开启了"警告视为错误"的编译选项,会直接触发编译报错。
  5. 按键无消抖处理
    现有按键检测逻辑未做消抖,机械按键的触点抖动会导致一次按压触发多次计数,数值跳变不符合预期。

修正后可运行代码

#include <xc.h>
#define _XTAL_FREQ 4000000

// 配置位修正:4MHz晶振适配XT模式,开启上电延时、掉电复位提升稳定性
#pragma config FOSC = XT
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config BOREN = ON
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF

unsigned char key_flag = 0;
unsigned char de = 0, un = 0;
// 段码表加const修饰,存入Flash节省RAM
const unsigned char Display[10] = {0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X98};

void display_scan(void);
void count_proc(void);

void main(void)
{
    TRISC = 0X00;
    TRISB = 0X00;
    TRISDbits.TRISD0 = 1;
    PORTC = 0;
    PORTB = 0;
    
    while (1)
    {
        // 按键检测+10ms软件消抖
        if (PORTDbits.RD0 == 1 && key_flag == 0)
        {
            __delay_ms(10);
            if(PORTDbits.RD0 == 1)
            {
                key_flag = 1;
                un++;
            }
        }
        // 松手检测
        if (PORTDbits.RD0 == 0 && key_flag == 1)
        {
            __delay_ms(10);
            if(PORTDbits.RD0 == 0)
            {
                key_flag = 0;
            }
        }
        
        count_proc();
        display_scan();
    }
}

void display_scan(void)
{
    PORTC = 0X01;
    PORTB = Display[un];
    __delay_us(500);
    
    PORTC = 0X02;
    PORTB = Display[de];
    __delay_us(500);
}

void count_proc(void)
{
    // 个位进位处理
    if (un >= 10)
    {
        un = 0;
        de++;
    }
    // 直接通过总数值判断归零,逻辑简单不易出错
    if(de*10 + un >= 36)
    {
        de = 0;
        un = 0;
    }
}

优化建议

  • 主循环中可连续执行2-3次数码管扫描,避免逻辑处理占用时间导致数码管亮度低、闪烁
  • 若需要显示36后下次按键再归零,只需将归零判断的阈值从36改为37即可
  • PIC16F877A为8位单片机,优先使用unsigned char类型存储0-255范围的变量,比int类型运行效率更高、更节省RAM
  • RD口无内部上拉,按键硬件电路建议外接10k下拉电阻,避免引脚悬空导致电平检测异常

内容的提问来源于stack exchange,提问作者boogiemane908

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 21:39:16