前言
前不久,裸機(jī)我有位做測試的程序朋友轉(zhuǎn)去做開發(fā)的工作,面試遇到了一個問題,框架他沒明白,片機(jī)打電話問了我。裸機(jī)題目大概就是程序:
在單片機(jī)裸機(jī)開發(fā)時,單片機(jī)要處理多個任務(wù),此時你的程序框架是怎樣的呢?
這其實是個經(jīng)典面試問題,我以前面試也被問過。
答案一:輪詢系統(tǒng)
代碼結(jié)構(gòu)如:
左右滑動查看全部代碼>>>
int?main(void)
{
?init_something();
?
?while(1)
?{
??do_something1();
????????do_something2();
????????do_something3();
?}
}
這種結(jié)構(gòu)大概是我們初學(xué)單片機(jī)的時候的代碼結(jié)構(gòu)。在沒有外部事件驅(qū)動時,可以較好使用。
只答出了這種情況,印象分估計會比較低,多半涼涼。
答案二:前后臺系統(tǒng)
代碼結(jié)構(gòu)如(該代碼來自 《RT-Thread內(nèi)核實現(xiàn)與應(yīng)用開發(fā)實踐指南》 ):
左右滑動查看全部代碼>>>
int?flag1?=?0;
int?flag2?=?0;
int?flag3?=?0;
int?main(void)
{
?/*?硬件相關(guān)初始化?*/
?HardWareInit();
?/*?無限循環(huán)?*/
?for?(;;)?{
???if?(flag1)?{
?????/*?處理事情?1?*/
?????DoSomething1();
???}
???if?(flag2)?{
?????/*?處理事情?2?*/
?????DoSomethingg2();
???}
???if?(flag3)?{
?????/*?處理事情?3?*/
?????DoSomethingg3();
???}
?}
}
void?ISR1(void)
{
?/*?置位標(biāo)志位?*/
?flag1?=?1;
?/*?如果事件處理時間很短,則在中斷里面處理
?如果事件處理時間比較長,在回到后臺處理?*/
?DoSomething1();
}
void?ISR2(void)
{
?/*?置位標(biāo)志位?*/
?flag2?=?2;
?/*?如果事件處理時間很短,則在中斷里面處理
?如果事件處理時間比較長,在回到后臺處理?*/
?DoSomething2();
}
void?ISR3(void)
{
?/*?置位標(biāo)志位?*/
?flag3?=?1;
?/*?如果事件處理時間很短,則在中斷里面處理
?如果事件處理時間比較長,在回到后臺處理?*/
?DoSomething3();
}
此處,中斷稱為前臺,main中的while循環(huán)稱為后臺。相比于循環(huán)系統(tǒng),這種方式相對可以提高外部事件的實時響應(yīng)能力。
可以回答出這種情況,印象分大概一半以上,會再細(xì)問。
答案三:升級版前后臺系統(tǒng)(軟件定時器法)
以前,學(xué)C語言時,常常聽到有人說:指針是C語言的靈魂,沒學(xué)會指針就是沒學(xué)會C語言。。
后來,學(xué)單片機(jī)時,又聽到有人說:中斷和定時器是單片機(jī)的靈魂,沒掌握中斷與定時器就沒學(xué)會單片機(jī)。。
大佬們都那么說了,那就拿定時器來搞點事情。定時器渾身都是寶,本篇筆記我們來介紹使用定時器(系統(tǒng)滴答定時器或者其它定時器)來做的裸機(jī)框架。軟件定時器法也有另一種說法:時間片輪詢法。
可以回答出這種情況,這場面試多半穩(wěn)了。
下面以STM32單片機(jī)為例看看這種方法的使用。
站在巨人的肩膀上
開源項目—— MultiTimer ,項目倉庫地址:
https://github.com/0x1abin/MultiTimer
1、MultiTimer 簡介
MultiTimer 是一個軟件定時器擴(kuò)展模塊,可無限擴(kuò)展你所需的定時器任務(wù),取代傳統(tǒng)的標(biāo)志位判斷方式, 更優(yōu)雅更便捷地管理程序的時間觸發(fā)時序。
2、MultiTimer 的demo
左右滑動查看全部代碼>>>
#include?"multi_timer.h"
struct?Timer?timer1;
struct?Timer?timer2;
void?timer1_callback()
{
????printf("timer1?timeout!\r\n");
}
void?timer2_callback()
{
????printf("timer2?timeout!\r\n");
}
int?main()
{
????timer_init(&timer1,?timer1_callback,?1000,?1000);?//1s?loop
????timer_start(&timer1);
????
????timer_init(&timer2,?timer2_callback,?50,?0);?//50ms?delay
????timer_start(&timer2);
????
????while(1)?{
????????
????????timer_loop();
????}
}
void?HAL_SYSTICK_Callback(void)
{
????timer_ticks();?//1ms?ticks
}
3、MultiTimer 的移植、剖析
想要對MultiTimer 進(jìn)行深入學(xué)習(xí)可閱讀項目源碼及如下這篇文章:
第6期 | MultiTimer,一款可無限擴(kuò)展的軟件定時器
自己動手,豐衣足食
1、代碼模板
準(zhǔn)備一個定時器,可以是系統(tǒng)滴答定時器,也可以是TIM定時器,使用這個定時器拓展出多個軟件定時器。
比如我們系統(tǒng)中有三個任務(wù):LED翻轉(zhuǎn)、溫度采集、溫度顯示。此時我們可以使用一個硬件定時器拓展出3個軟件定時器,定義如下宏定義:
左右滑動查看全部代碼>>>
#define??MAX_TIMER????????????3????????????//?最大定時器個數(shù)
EXT?volatile?unsigned?long????g_Timer1[MAX_TIMER];?
#define??LedTimer?????????????g_Timer1[0]??//?LED翻轉(zhuǎn)定時器
#define??GetTemperatureTimer??g_Timer1[1]??//?溫度采集定時器
#define??SendToLcdTimer???????g_Timer1[2]??//?溫度顯示定時器
#define??TIMER1_SEC????????(1)??????????????//?秒
#define??TIMER1_MIN????????(TIMER1_SEC*60)??//?分
在定時器初始化的時候也順便給三個軟件定時器進(jìn)行初始化操作:
左右滑動查看全部代碼>>>
/