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

如何调试BeagleBone Black上程序停止打印输出的问题

调试方法建议

1. 给轮询循环添加超时机制

你的代码中两个while循环会一直等待ECHO引脚状态变化,一旦传感器无响应(比如检测范围内无物体、接线松动),程序会直接挂死在循环里。给循环加上超时逻辑,既避免挂死,还能输出错误信息定位问题:

while(1)
{
    std::chrono::high_resolution_clock::time_point start,end;
    long long delay_count=0;

    // Trigger
    outGPIO.setValue(HIGH);
    usleep(10);
    outGPIO.setValue(LOW);

    // Poll for Echo HIGH with timeout (1s)
    auto timeout_start = std::chrono::high_resolution_clock::now();
    bool echo_triggered = false;
    while(inGPIO.getValue() == 0)
    {
        usleep(1000);
        auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - timeout_start).count();
        if(elapsed > 1000) {
            printf("\n[ERROR] Timeout waiting for ECHO HIGH");
            goto next_cycle;
        }
        start = std::chrono::high_resolution_clock::now();
    }
    echo_triggered = true;

    // Poll for Echo LOW with timeout (2s, adjust based on sensor max range)
    timeout_start = std::chrono::high_resolution_clock::now();
    while(inGPIO.getValue() == 1)
    {
        end = std::chrono::high_resolution_clock::now();
        usleep(delay_us);
        delay_count +=delay_us;
        auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - timeout_start).count();
        if(elapsed > 2000) {
            printf("\n[ERROR] Timeout waiting for ECHO LOW");
            goto next_cycle;
        }
    }

    // Calculate distance
    long long microseconds = std::chrono::duration_cast<std::chrono::microseconds>(end-start).count();
    printf("\nDuration: %lld, delay: %lld dist:%f",microseconds,delay_count,(microseconds+delay_count)*0.034*0.5);

next_cycle:
    usleep(1000*100);
}

2. 实时打印GPIO状态,定位挂死节点

在挂死发生前,打印ECHO引脚的实时状态,确认程序卡在哪个阶段:

// 在等待ECHO HIGH的循环中添加
while(inGPIO.getValue() == 0)
{
    int current_val = inGPIO.getValue();
    printf("\nWaiting for ECHO HIGH, current value: %d", current_val);
    usleep(1000);
    start = std::chrono::high_resolution_clock::now();
}

// 在等待ECHO LOW的循环中同理添加打印
while(inGPIO.getValue() == 1)
{
    int current_val = inGPIO.getValue();
    printf("\nWaiting for ECHO LOW, current value: %d", current_val);
    end = std::chrono::high_resolution_clock::now();
    usleep(delay_us);
    delay_count +=delay_us;
}

同时可以手动执行cat /sys/class/gpio/gpio45/value,在程序挂起时直接读取引脚状态,验证是传感器无输出还是代码读取异常。

3. 优化GPIO读取逻辑,避免文件IO异常

原代码使用的GPIO库每次调用getValue()都会打开/关闭GPIO值文件,频繁IO操作可能导致文件句柄泄漏或权限问题。改用文件流持续读取:

int main(){
    GPIO outGPIO(44), inGPIO(45);
    outGPIO.setDirection(OUTPUT);
    inGPIO.setDirection(INPUT);

    // 预打开ECHO引脚的value文件
    std::ifstream echo_pin_file("/sys/class/gpio/gpio45/value");
    if(!echo_pin_file.is_open()){
        perror("Failed to open ECHO pin file");
        return 1;
    }

    int delay_us = 50;
    while(1)
    {
        // ... 触发代码不变 ...

        // 读取ECHO状态时直接从流中读取
        int val;
        echo_pin_file.seekg(0); // 重置文件指针
        echo_pin_file >> val;
        while(val == 0)
        {
            usleep(1000);
            echo_pin_file.seekg(0);
            echo_pin_file >> val;
            // ... 超时逻辑不变 ...
        }
        // ... 后续逻辑同理修改 ...
    }
}

4. 添加信号处理,捕获挂起时的程序栈

给程序添加信号处理函数,当程序挂起时,通过kill -SIGUSR1 <进程ID>发送信号,打印调用栈和当前状态:

#include <signal.h>
#include <execinfo.h>

// 把inGPIO设为全局变量,方便信号处理函数访问
GPIO inGPIO(45);

void signal_handler(int sig) {
    void *callstack[10];
    size_t stack_size;

    // 打印调用栈
    stack_size = backtrace(callstack, 10);
    fprintf(stderr, "\nSignal %d received, call stack:\n", sig);
    backtrace_symbols_fd(callstack, stack_size, STDERR_FILENO);

    // 打印当前ECHO引脚状态
    printf("\nCurrent ECHO pin value: %d", inGPIO.getValue());
    exit(1);
}

int main(){
    // 注册信号处理
    signal(SIGUSR1, signal_handler);
    signal(SIGINT, signal_handler);

    GPIO outGPIO(44);
    outGPIO.setDirection(OUTPUT);
    inGPIO.setDirection(INPUT);

    // ... 原有代码 ...
}

编译时需要添加-rdynamic参数,让调用栈显示函数名:

g++ simple.cpp GPIO.cpp -o simple -pthread -rdynamic

5. 硬件层面排查

  • 检查传感器供电:BeagleBone GPIO引脚供电能力有限,若传感器需要大电流,需外接独立电源。
  • 验证接线:确认TRIG(GPIO44)、ECHO(GPIO45)接线无松动,GND连接可靠。
  • 用示波器/逻辑分析仪观测TRIG和ECHO引脚波形,确认触发信号正常,且ECHO信号在检测时能正常返回。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 08:25:36