HC-SR04超声波传感器与PIC24Fj64GA002单片机代码调试求助
基于PIC24Fj64GA002与HC-SR04的距离计算问题调试方案
问题背景
使用主频16MHz的PIC24Fj64GA002搭配HC-SR04开发项目,经逻辑分析仪确认硬件正常、输入捕获ISR能被正确触发,但计算出的距离值不符合预期且不随物体距离变化;将RB4与RB5短接测试10us脉冲对应的finalTime时,结果不符合预期,已确认代码计算公式存在问题。
现有代码
#include "xc.h" #include <stdbool.h> bool stopMotion = 0; volatile uint32_t finalTime = 0; volatile int overflowtmr = 0; int distanceThreshold = 1; void setup(){ CLKDIVbits.RCDIV = 0; TRISBbits.TRISB4 = 1; //input for echo TRISBbits.TRISB5 = 0; //output for trig LATBbits.LATB5 = 0; //IC1 setup IC1CONbits.ICTMR = 0; //timer 3 IC1CONbits.ICM = 1; //PPS for IC1 __builtin_write_OSCCONL(OSCCON & 0xbf);// unlock PPS RPINR7bits.IC1R = 4; // RP4 (pin 11) __builtin_write_OSCCONL(OSCCON | 0x40); // lock PPS T3CON = 0; TMR3 = 0; T3CONbits.TCKPS = 0; _T3IF = 0; //a prescaler of 1 for TMR3 PR3 = 65535; T3CONbits.TON = 1; IFS0bits.T3IF = 0; IEC0bits.T3IE = 1; IPC2bits.T3IP = 3; IFS0bits.IC1IF = 0; IEC0bits.IC1IE = 1; IPC0bits.IC1IP = 3; //TIMER1 setup T1CON = 0; TMR1 = 0; T1CONbits.TCKPS = 0; _T1IF = 0; PR1 = 160; //for a delay of 10uS T1CONbits.TON = 0; IFS0bits.T1IF = 0; IEC0bits.T1IE = 1; IPC0bits.T1IP = 5; //higher priority than the input capture interrupt } void __attribute__((interrupt, auto_psv)) _IC1Interrupt(){ IFS0bits.IC1IF = 0; if(PORTBbits.RB4 == 1){ //reset both TMR3 and overflowtmr TMR3 = 0; overflowtmr = 0; } else{ finalTime = (TMR3)*625 + overflowtmr*625*65536; overflowtmr = 0; TMR3 = 0; uint16_t distance = finalTime/((58)*(10000/10)); if(distance <= distanceThreshold) stopMotion = 1; else stopMotion = 0; } } void __attribute__((interrupt, auto_psv)) _T3Interrupt(){ IFS0bits.T3IF = 0; overflowtmr++; } void __attribute__((interrupt, auto_psv)) _T1Interrupt(){ _T1IF = 0; T1CONbits.TON = 0; TMR1 = 0; LATBbits.LATB5 = 0; } void sendTrig(){ LATBbits.LATB5 = 1; T1CONbits.TON = 1; } void delay_ms(unsigned int ms){ while(ms-- > 0){ asm("repeat #15999"); asm("nop"); } } int main(void) { setup(); while(1){ sendTrig(); delay_ms(2000); //delay for 2 seconds before sending another trig signal. } }
调试步骤
1. 修正定时器计数与时间转换公式
- 16MHz主频下,TMR3预分频器为1时,定时器时钟周期是62.5ns(1/16MHz),而非代码中的625。当前代码中
(TMR3)*625实际计算的是625ns,比真实值大10倍,这是核心错误。 - 修正
finalTime计算:finalTime = (uint32_t)TMR3 * 62 + overflowtmr * (uint32_t)65536 * 62;(或用浮点运算(uint32_t)TMR3 * 62.5,需确保编译器支持)。 - 短接RB4/RB5时,10us脉冲对应的
finalTime应为10000(10us=10000ns),验证修正后数值是否符合预期。
2. 修正距离计算逻辑
HC-SR04的标准距离公式为:距离(cm) = 脉冲宽度(us) / 58,代码中((58)*(10000/10))是错误的,简化后为58000,会导致距离被严重缩小。
- 修正距离计算逻辑:
uint16_t pulse_us = finalTime / 1000; // 将ns转换为us uint16_t distance = pulse_us / 58;
3. 验证定时器溢出计数的正确性
- 将
overflowtmr的类型从int改为volatile uint16_t,避免符号位导致的计数异常。 - 通过调试器观察
overflowtmr的数值,确认每次T3溢出时计数正确累加。
4. 优化输入捕获模式
当前IC1CONbits.ICM=1仅捕获上升沿,建议改为ICM=3(同时捕获上升沿和下降沿),无需在ISR中读取PORTB电平判断边沿类型,减少误判概率。
5. 增加调试观察点
- 在主循环中添加代码,通过UART或调试器定时输出
finalTime、pulse_us、distance的数值,直观跟踪计算过程中的变化。 - 短接RB4/RB5时,观察
finalTime是否接近10000,确认时间转换逻辑正确。
6. 检查中断优先级与冲突
- 当前T1中断优先级高于IC1,需确认T1中断处理时间是否过短(当前代码符合要求),可临时降低T1优先级测试是否影响IC1的捕获精度。
内容的提问来源于stack exchange,提问作者Moon
相关产品推荐
相关产品推荐

