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
相关产品推荐
相关产品推荐

