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

PIC16F877A搭配HC-SR04测距控制LED闪烁异常问题排查

PIC16F877A测距项目LED闪烁问题修复

问题根因

代码中存在4个直接导致LED闪烁的错误:

  • 条件判断逻辑错误:所有if判断相互独立,末尾的else仅与最后一个if(dist==4)绑定。当距离匹配1/2/3档位时,前面的if会点亮对应LED,但后续所有if判断不满足后,最终会执行else分支将PORTB清零,LED亮灭快速切换就会出现闪烁。
  • 定时器未重置:每次测距前没有将TMR1寄存器清零,上一次测距的计数值会残留,导致距离计算结果错误。
  • 冗余测距调用:主循环中连续调用两次calc_distance(),第一次的计算结果未被使用,不仅浪费资源,还会打乱超声波传感器的测距时序,增加读数误差概率。
  • 无超时退出机制:calc_distance()函数中等待echo引脚电平变化的while循环没有超时判断,若传感器未检测到回波,程序会卡死在循环中,导致LED状态异常。

修复后完整代码

#include <xc.h>
#include <pic16f877a.h> 
#pragma config FOSC = XT        // 振荡器选择位(XT振荡器)
#pragma config WDTE = OFF       // 看门狗定时器禁用
#pragma config PWRTE = OFF      // 上电定时器禁用
#pragma config BOREN = OFF      // 掉电复位禁用
#pragma config LVP = OFF        // 低电压编程禁用,RB3作为数字IO
#pragma config CPD = OFF        // 数据EEPROM代码保护关闭
#pragma config WRT = OFF        // Flash程序存储器写保护关闭
#pragma config CP = OFF         // Flash程序存储器代码保护关闭
#define _XTAL_FREQ 4000000
#define trigger RC2
#define echo RC3

int calc_distance();

int calc_distance()
{
    int distance=0;
    TMR1 = 0; // 每次测距前清空定时器计数值,修复残留值问题
    // 增加超时判断变量,避免卡死
    unsigned int timeout = 60000; // 对应最大测距约34cm,覆盖20cm量程需求
     
    trigger=1;
    __delay_us(10);
    trigger=0;
    
    // 等待echo变高,增加超时
    while(!echo && timeout--); 
    if(timeout == 0) return 0; // 超时返回0,触发熄灭逻辑
    TMR1ON=1;
    
    timeout = 60000;
    // 等待echo变低,增加超时
    while(echo && timeout--);
    TMR1ON=0;
    if(timeout == 0) return 0; // 超时返回0
 
    distance=TMR1/58;
    return distance;
}

void main(void)
{
    int dist=0; 
  
    TRISB = 0x00;  // PORTB设为输出
    PORTB = 0x00;  // 初始PORTB全低

    TRISC2 = 0;     // RC2(Trigger)设为输出
    RC2 = 0;
    TRISC3 = 1;     // RC3(Echo)设为输入
  
    // 配置定时器1
    T1CKPS0=0;
    T1CKPS1=0;
    TMR1CS=0; // 选择内部时钟作为时钟源
  
  
    while(1)
    {
        // 去掉冗余的calc_distance()调用,只保留一次
        dist = calc_distance()/5;
        // 将独立if改为else if串联,只有所有条件都不满足时才执行else
        if(dist==1)
        {
            PORTB = 0x01; 
        }
        else if(dist==2)
        {
            PORTB = 0x03; 
        }
        else if(dist==3)
        {
            PORTB = 0x07; 
        }
        else if(dist==4)
        {
            PORTB = 0x0F; 
        }
        else
        {
            PORTB = 0x00; 
        }
        __delay_ms(50); // 延时统一放最后,避免每个分支重复写
    }
    return;
}

可选优化建议

如果仍存在偶尔的读数抖动导致LED闪烁,可以增加简单的滑动滤波:连续读取3-5次距离值,取中间值或者平均值作为最终测距结果,过滤传感器的偶然误差。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 23:36:03