嵌入式测试脚本:如何在按键触发前持续执行周期性动作
问题
我正在为嵌入式控制器编写测试脚本,部分测试需用户执行操作后方可继续。例如,我会在屏幕打印如下指令:
printf("Turn switch A to ON position then press any key");
随后希望脚本等待用户按下按键后,再执行后续测试步骤:
ExpectedSwitchState = ON; CheckSwitch(01);
我可以通过以下方式轻松实现等待(但需按下回车键):
printf("\nPress Enter to continue"); getChar();
当前面临的问题是:必须确保工具在无其他命令传输时,每4秒发送一次tester present消息;且希望按键后立即恢复执行,无需等待剩余的4秒周期。
我更熟悉嵌入式C语言,对电脑输入相关的常用命令不太了解。目前仅找到暂停程序的方法,尚未知晓如何实现“持续执行动作直到按键按下”的逻辑。我曾考虑编写一个while循环,每1ms递增计数器,当计数器达到4000时发送tester present消息,同时检测到按键则退出循环,但该方案略显繁琐,且我不清楚检测按键的具体命令。
解决方案
1. 实现非阻塞按键检测
标准C没有内置非阻塞键盘检测函数,需基于平台实现:
- Windows平台:直接用
<conio.h>里的_kbhit()(检测按键是否按下,非阻塞)和_getch()(读取按键且不回显)。 - Linux/macOS平台:通过修改终端属性实现非阻塞检测,示例代码如下:
#include <stdio.h> #include <termios.h> #include <unistd.h> // 非阻塞检测按键是否按下 int kbhit(void) { struct termios oldt, newt; int ch; int oldf; // 保存终端原有属性 tcgetattr(STDIN_FILENO, &oldt); newt = oldt; // 关闭规范模式和回显 newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); // 设置终端为非阻塞模式 oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); ch = getchar(); // 恢复终端原有属性 tcsetattr(STDIN_FILENO, TCSANOW, &oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); if(ch != EOF) { ungetc(ch, stdin); // 将字符放回输入流,供后续读取 return 1; } return 0; }
2. 结合定时器实现核心逻辑
基于非阻塞按键检测,编写循环逻辑,同时满足每4秒发送tester present、按键立即退出的需求:
#include <stdio.h> #include <unistd.h> // Linux下用于usleep,Windows用Sleep() #define TESTER_INTERVAL_MS 4000 // 4秒间隔,单位毫秒 void WaitForUserAndSendTester(void) { unsigned int elapsed_ms = 0; printf("Turn switch A to ON position then press any key\n"); while(1) { // 检测到按键则退出循环 if(kbhit()) { getchar(); // 读取按键,清除输入缓存 break; } // 1ms延时(根据平台调整:Windows用Sleep(1),Linux用usleep(1000)) usleep(1000); elapsed_ms++; // 达到4秒间隔,发送tester present if(elapsed_ms >= TESTER_INTERVAL_MS) { printf("Sending tester present message...\n"); // 替换为实际发送tester present的函数调用 // SendTesterPresent(); elapsed_ms = 0; } } // 执行后续测试步骤 ExpectedSwitchState = ON; CheckSwitch(01); }
3. 优化建议
- 不要依赖固定延时(如
usleep(1000)),建议用系统高精度定时器(比如Linux的clock_gettime、Windows的QueryPerformanceCounter)计算时间差,避免系统负载高时导致间隔不准。 - 跨平台场景用条件编译区分不同平台的代码,比如:
#ifdef _WIN32 #include <conio.h> #include <windows.h> #define DELAY_MS(ms) Sleep(ms) #else #include <unistd.h> #define DELAY_MS(ms) usleep(ms*1000) #endif
内容的提问来源于stack exchange,提问作者Shaf
相关产品推荐
相关产品推荐

