C语言项目中用到的一些技巧,写出来与大家分享。
情形一
碰到过这样的需求:
1) 检测到某种事件时,让1号灯闪烁三次(亮100ms,灭200ms),再关掉灯;
2) 2号灯是运行指示灯,需要亮一秒,灭一秒,一直重复下去;
如何实现呢?
如果有操作系统,开多个线程去做,代码写起来会非常完美。
但如果不用操作系统,只有一个线程,该怎么办呢?
情形二
硬件资源必须互斥访问:
多个任务使用同一个串口发送数据。
这里需要考虑的是:
1) 串口发送完一帧数据后,需要空闲几毫秒时间才能开启下一次发送。否则,会造成接收方粘包,给接收方解包带来麻烦。甚至有些协议强制要求空闲时间。
2) 如果A任务正在发送中,B任务插进来发送,会导致严重问题。
如果大家有遇到过上述两个情形,以下的参考代码,会是不错的解决方案:
#include <stdint.h>
#define EVENT0 (1UL<<0)
#define EVENT1 (1UL<<1)
uint32_t __EVENTS__ = 0;
uint32_t SysTimeMS;//系统时间,单位毫秒.
static void PollThread(void){
#define __abs(x) ((x)>0 ? (x):(-x))
#define Thread_Begin() do{ static unsigned int __lc; switch(__lc){ case 0:
#define Thread_Switch() __lc = 0
#define Thread_WaitUntil(cond) __lc = __LINE__; case __LINE__: if(!(cond)) goto __out
#define Thread_msSleep(t) do{\
static int msDelay;\
msDelay = SysTimeMS;\
Thread_WaitUntil(__abs(SysTimeMS - msDelay)>(t));\
}while(0)
#define Thread_End() }__out:}while(0)
Thread_Begin();
//最多支持32个事件.
if ( __EVENTS__ & EVENT0 ){
/*
todo:处理0#事件.
例如串口发送任务,发送完毕后延时,防止粘包。
*/
__EVENTS__ = (__EVENTS__ ^ EVENT0);//返回未处理的事件.
Thread_msSleep(10);
Thread_Switch();//切换任务.
}
if ( __EVENTS__ & EVENT1 ){
//循环10次,每次等待3ms.
static int i;
for(i=0; i<10; i++){
/*
todo:处理1#事件.
例如模拟IIC输出时,需要翻转IO口,并延时.
例如模拟串口输出时,需要翻转IO口,并延时.
例如读模拟串口输入时,需要读IO口,可能需要延时.
*/
//不阻塞延时3ms.
Thread_msSleep(3);
}
__EVENTS__ = (__EVENTS__ ^ EVENT1);//返回未处理的事件.
Thread_Switch();//切换任务.
}
Thread_End();
}
void main(void){
//提交事件
__EVENTS__ |= (EVENT0|EVENT1);
//响应事件
while(1){
if(__EVENTS__)
PollThread();
}
}