精妙的微控制器非阻塞延時程式設計
http://blog.chinaunix.net/uid-29673749-id-4425603.html
對於每個微控制器愛好者及工程開發設計人員,在剛接觸微控制器的那最初的青蔥歲月裡,都有過點亮跑馬燈的經歷。從看到那一排排小燈按著我們的想法在跳動時激動心情。到隨著經驗越多,越來又會感覺到這個小燈是個好東西,尤其是在除錯資源有限的環境中,有時會幫上大忙。
但對於絕大多數人,我們在最最初讓燈閃爍起來時大約都會用到阻塞延時實現,會像如下程式碼的樣子:
-
while(1)
-
{
-
LED =OFF;
-
Delay_ms(500);
-
LED = ON;
-
Delay_ms(500)
- }
這時我們就會慢慢意識到,第一種(阻塞延時)方法效率很低,讓晶片在那兒空執行幾百毫米,什麼也不做,真是莫大的浪費,尤其在晶片頻率較高,任務又很多時,這樣做就像在平坦寬闊的高速公路上挖了一大坑,出現事故可想而知。
但一個微控制器中的定時器畢竟有限,如果我需要幾十個或者更多不同時間的定時中斷,每一個時間到都完成不同的處理動作,如何去做呢。一般我們會想到在一個定時中斷函式中再定義static 變數繼續定時,到了所需時間,做不同的動作。而這樣又會導致在一箇中斷裡做了很多不同的事情,會搶佔主輪詢更多時間,有時甚至喧賓奪主,並也不是很如的思維邏輯。
那麼有沒有更好的方法來實現呢,答案是肯定的。下面介紹我在一個專案中偶遇,一個精妙設計的非阻塞定時延時軟體的設計(此設計主要針對於無作業系統的裸機程式)。
在上篇文章中有對systick的介紹,比如我要設定其10ms中斷一次,如何實現呢?
也很簡單,只需呼叫 core_cm3.h檔案中 SysTick_Config 函式 ,當系統時鐘為72MHZ,則設定成如下即可SysTick_Config(720000 ); (遞減計數720000次後中斷一次) 。此時SysTick_Handler中斷函式就會10ms進入一次;
任務定時用軟體是如何設計的呢 ?
且先看其資料結構,這也是精妙所在之處,在此作自頂向下的介紹:
其定義結構體型別如:
-
typedef struct
-
{
-
uint8_t Tick10Msec;
-
Char_Field Status;
- } Timer_Struct;
-
typedef union
-
{
-
unsigned char byte;
-
Timer_Bit field;
- } Char_Field
-
typedef struct
-
{
-
unsigned char bit0: 1;
-
unsigned char bit1: 1;
-
unsigned char bit2: 1;
-
unsigned char bit3: 1;
-
unsigned char bit4: 1;
-
unsigned char bit5: 1;
-
unsigned char bit6: 1;
-
unsigned char bit7: 1;
- } Timer_Bit
如此結構體的設計就完成了。
然後我們定義的一全域性變數,Timer_Struct gTimer;
並在標頭檔案中巨集定義如下:
-
#define bSystem10Msec gTimer.Status.field.bit0
-
#define bSystem50Msec gTimer.Status.field.bit1
-
#define bSystem100Msec gTimer.Status.field.bit2
-
#define bSystem1Sec gTimer.Status.field.bit3
-
#define bTemp10Msec gTimer.Status.field.bit4
-
#define bTemp50Msec gTimer.Status.field.bit5
-
#define bTemp100Msec gTimer.Status.field.bit6
- #define bTemp1Sec gTimer.Status.field.bit
-
typedef enum
-
{
-
TIMER_RESET = 0,
-
TIMER_SET = 1,
- } TimerStatus;
首先,10ms定時中斷處理函式如,可以看出,每到達10ms 將把bTemp10Msec置1,每50ms 將把bTemp50Msec 置1,每100ms 將把bTemp100Msec 置1,每1s 將把bTemp1Sec 置1,
-
void SysTick_Handler(void)
-
{
-
bTemp10Msec = TIMER_SET;
-
++gTimer.Tick10Msec;
-
if (0 == (gTimer.Tick10Msec % 5))
-
{
-
bTemp50Msec = TIMER_SET;
-
}
-
if (0 == (gTimer.Tick10Msec % 10))
-
{
-
bTemp100Msec = TIMER_SET;
-
}
-
if (100 == gTimer.Tick10Msec)
-
{
-
gTimer.Tick10Msec = 0;
-
bTemp1Sec = TIMER_SET;
-
}
- }
這時,我們需在主輪詢while(1)內最開始呼叫一個定時處理函式如下:
-
void SysTimer _Process(void)
-
{
-
gTimer.Status.byte &= 0xF0;
-
if (bTemp10Msec)
-
{
-
bSystem10Msec = TIMER_SET;
-
}
-
if (bTemp50Msec)
-
{
-
bSystem50Msec = TIMER_SET;
-
}
-
if (bTemp100Msec)
-
{
-
bSystem100Msec = TIMER_SET;
-
}
-
if (bTemp1Sec)
-
{
-
bSystem1Sec = TIMER_SET;
-
}
-
gTimer.Status.byte &= 0x0F;
- }
-
gTimer.Status.byte &= 0xF0;
- gTimer.Status.byte &= 0x0F
但要保證while(1)輪詢時間要遠小於10ms,否則將導致定時延時不準確。這樣,在每輪詢一次,就先把bSystemXXX ,再根據bTempXXX判斷是否時間到達,並把對應的bSystemXXX 置1,而後面所有的任務就都可以通過bSystemXXX 來進行定時延時,在最後函式退出時,又會把bTempXXX清零,為下一次時間到達後查詢判斷作好了準備。
說了這麼多,舉例說明一下如何應用:
-
void Task_A_Processing(void)
-
{
-
if(TIMER_SET == bSystem50Msec){
-
//do something
-
}
-
}
-
void Task_B_Processing(void)
-
{
-
if(TIMER_SET == bSystem100Msec){
-
//do something
-
}
-
}
-
void Task_C_Processing(void)
-
{
-
static uint8_t ticks = 0;
-
if(TIMER_SET == bSystem100Msec){
-
ticks ++ ;
-
}
-
if(5 == ticks){
-
ticks = 0;
-
//do something
-
}
-
}
-
void Task_D_Processing(void)
-
{
-
if(TIMER_SET == bSystem1Sec){
-
//do something
-
}
- }
在主輪詢裡可進行如下處理:
-
int main(void)
-
{
-
while(1)
-
{
-
SysTimer _Process();
-
Task_A_Processing();
-
Task_B_Processing();
-
Task_C_Processing();
-
Task_D_Processing();
-
}
- }
相關推薦
精妙的微控制器非阻塞延時程式設計
http://blog.chinaunix.net/uid-29673749-id-4425603.html 對於每個微控制器愛好者及工程開發設計人員,在剛接觸微控制器的那最初的青蔥歲月裡,都有過點亮跑馬燈的經歷。從看到那一排排小燈按著我們的想法在跳動時激動心情。到
Qt阻塞延時與非阻塞延時(四種方法之個人筆記)
/***************************************************************************************** * 功能描述: 毫秒級非阻塞延時函式 * 引數: 延時毫秒數 * 其他說明: 已試驗,
Qt 非阻塞和阻塞延時
ecs ati ddms cat 應該 oid 名稱 set 情況 一般情況下,延時大概分為兩類,一個是非阻塞延時,一個是阻塞延時,但從名稱上應該都可以看出來具體的含義,下面針對這兩類延時方法,做一個具體的說明和代碼實現:一、關於Qt實現非阻塞延時的方法:void QSle
使用FreeRTOS在SD卡驅動使用非系統延時導致上電重啟不工作的情況
new i開啟 ask 函數 fault 思想 初始化 font 是否 一、問題描述在一個使用FreeRTOS的工程中,只做了SD卡的驅動,由於RTOS使用了Systick,故非系統延時函數使用的是 DWT中的時鐘周期(CYCCNT)計數功能,但是在SD卡驅動中使用了這個非
51微控制器 Keil C 延時程式的簡單(晶振12MHz,一個機器週期1us.)
一. 500ms延時子程式 void delay500ms(void) { unsigned char i,j,k; for(i=15;i>0;i--) for(j=202;j>0;j--) for(k=81;k>0;k--); } 產生的彙
對MSP430微控制器__delay_cycles精確延時的說明及改正
在這裡, 我來討論一下關於MSP430微控制器使用__delay_cycles延時的問題. IAR for MSP430編譯器提供了一個編譯器內聯的精確延時函式(並非真正的 函式)以提供使用者精確延時使用, 該函式原型是: __intrinsic void __delay_cy
微控制器兩大延時方法總結
實現延時通常有兩種方法:一種是硬體延時,要用到定時器/計數器,這種方法可以提高CPU的工作效率,也能做到精確延時;另一種是軟體延時,這種方法主要採用迴圈體進行。 1 使用定時器/計數器實現精確延時 微控制器系統一般常選用11.059 2 MHz、12 MHz
【MPI學習4】MPI並行程式設計模式:非阻塞通訊MPI程式設計
這一章講了MPI非阻塞通訊的原理和一些函式介面,最後再用非阻塞通訊方式實現Jacobi迭代,記錄學習中的一些知識。 (1)阻塞通訊與非阻塞通訊 阻塞通訊呼叫時,整個程式只能執行通訊相關的內容,而無法執行計算相關的內容; 非阻塞呼叫的初衷是儘量讓通訊和計算重疊進行,提高程式整體執行效率。 整體對比見下圖:
python:非阻塞或非同步程式設計
例如,對於一個聊天室來說,因為有多個連線需要同時被處理,所以很顯然,阻塞或同步的方法是不合適的,這就像買票只開了一個視窗,佷多人排隊等一樣。那麼我們如何解決這個問題呢?主要有三種方法:forking、threading、非同步I/O。 Forking和threading的方
非阻塞模式WinSock程式設計入門 使用 WSAAsyncSelect模型
非阻塞模式WinSock程式設計入門 介紹 WinSock是Windows提供的包含了一系列網路程式設計介面的套接字程式庫。在這篇文章中,我們將介紹如何把它的非阻塞模式引入到應用程式中。文章中所討論的通訊均為面向連線的通訊(TCP),為清晰起見,文章對程式碼中的一些細枝末
51微控制器C語言延時函式
C程式中可使用不同型別的變數來進行延時設計。經實驗測試,使用unsigned char型別具有比unsigned int更優化的程式碼,在使用時應該使用unsigned char作為延時變數。 以某晶振為12MHz的微控制器為例,晶振為12MHz即一個機器週期為1us。 一. 500ms延時子程
iOS開發——Swift字串替換 + HTML標籤正則過濾 + 主執行緒非阻斷延時
一.字串替換 單獨替換: //原始字串 let str1 = "LCL中金公司iOS" //替換後的字串 let str2 = str1.replacingOccurrences
非阻塞賦值的內部延時和外部延時
學習verilog有一段時間了,從字面上理解,阻塞和非阻塞的區別很直白。 前者是序列,主要用於描述組合邏輯,和軟體中的賦值類似;後者是並行,主要用於描述時序邏輯。 但是和內部延時、外部延時混用在一起的時候,各種意想不到的情況就會發生。 下面將介紹,對於非阻塞賦值,內部延遲和
FIFO 非阻塞寫+非阻塞讀+延時迴圈讀的一種方法
用mkfifo在當前目錄下建立一個myfifo的有名管道 只執行非阻塞寫的程式 open引數為O_WRONLY | O_NONBLOCK write失敗,這是man手冊裡面說明了的情況 如果open引數為O_RDWR | O_NONBLOCK 寫程式則可以立即返回 但是當執
C/C++網路程式設計在windows和linux中將socket設定為阻塞和非阻塞
C/C++網路程式設計在windows和linux中將socket設定為阻塞和非阻塞 在 socket程式設計中,對於socket的讀寫預設都是阻塞的,但有的情況我們需要將其設定為非阻塞,比如做多
Python併發程式設計之同步\非同步and阻塞\非阻塞
一、什麼是程序 程序: 正在進行的一個過程或者說一個任務。而負責執行任務則是cpu。 程序和程式的區別: 程式僅僅只是一堆程式碼而已,而程序指的是程式的執行過程。 需要強調的是:同一個程式執行兩次,那也是兩個程序,比如開啟暴風影音,雖然都是同一個軟體,但是一個可以播郭德綱,一個可以播高曉鬆。 二、並行
微控制器 軟體延時時間控制
微控制器 軟體延時時間控制 一、簡述 記--通過程式碼方式實現軟體延時(不精確延時)。 二、指令週期 微控制器需要一個時鐘訊號送給內部各個電路,才能使它們有節拍地協同工作。時鐘訊號的頻率是由
併發程式設計學習筆記之原子變數與非阻塞同步機制(十二)
概述 java.util.concurrent包中的許多類,比如Semaphore和ConcurrentLinkedQueue,都提供了比使用Synchronized更好的效能和可伸縮性.這是因為它們的內部實現使用了原子變數和非阻塞的同步機制. 近年來很多關於併發演算法的研究都聚焦在非阻塞演算法(nonb
Windows網路程式設計(八):非阻塞模式(非同步模式)
前面幾篇文章介紹的無論是TCP通訊還是UDP通訊都是阻塞式的,它們在執行recv或recvfrom時會線上程中等待,直到接收到資訊為止,所以在應用的時候一般都需要開闢子執行緒,在子執行緒裡專門做這類事情,不然它會影響主執行緒的執行。 系統提供三種網路模型
Qt:Qt實現Winsock網路程式設計—非阻塞模式下的簡單遠端控制的開發(WSAAsyncSelect)
Qt實現Winsock網路程式設計—非阻塞模式下的簡單遠端控制的開發(WSAAsyncSelect) 前言 這邊部落格應該是 Qt實現Winsock網路程式設計—TCP服務端和客戶端通訊(多執行緒) 的姐妹篇,上篇部落格中的socket通訊中所用的Windows api函式 都是