純C語言設計的執行緒,讓微控制器不用作業系統的情況下,支援執行緒和事件

Xyz0763發表於2019-02-08

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();
    }
}

 

相關文章