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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 22:49:53