1.問題描述
在使用定時器的過程中最令人苦惱的就是,定義flag,holdtime,每用一次定義就會導(dǎo)致中斷函數(shù)中標(biāo)志位滿天飛,時間變量在程序中隨處可見。在想要移植,又不敢隨便刪除。程序處于高耦合狀態(tài),失去了一個.c 一個 .h的意義。
2.如何解決這種問題
引入注冊機(jī)制。為了方便說明注冊機(jī)制,舉一個例子:手機(jī)在使用相機(jī)這個功能時,有一個操作:將拍攝的照片發(fā)送出去。以程序來實(shí)現(xiàn)這一過程,最容易想到的方法如下:
在相機(jī)的發(fā)送模塊添加以下代碼:
if(選擇發(fā)送)
{
if(選擇微信發(fā)送)
{
獲取發(fā)送人;
選擇發(fā)送人;
}
elseif(選擇qq發(fā)送)
{
獲取發(fā)送人;
選擇發(fā)送人;
}
elseif(選擇微博發(fā)送)
{
獲取發(fā)送人;
選擇發(fā)送人;
}
.
.此處省略一萬行
.
}
這是最容易想到的實(shí)現(xiàn)方式,就如上面定時器的實(shí)現(xiàn)方式,哪里要用了,再定義一系列變量就是了?;氐较鄼C(jī)例子,假設(shè)某一天一個比微信還火的聊天軟件出現(xiàn)了,用戶安裝了,想要發(fā)送圖片,這時該怎么做 ?當(dāng)然,只能在上面相機(jī)的發(fā)送發(fā)送模塊中添加else if(。。。。)和它的實(shí)現(xiàn)方式了,也就意味著,每更新一個需要使用圖片功能的軟件,就必須去修改相機(jī)模塊,是不是覺得和我們的定時器很像?
注冊的精髓:解耦各個模塊。程序講究高內(nèi)聚,低耦合。我目前對這句話的理解是:高內(nèi)聚:每一個功能模塊(c文件,h文件),內(nèi)部不和其他模塊相互調(diào)用,比如障礙物函數(shù)里面不應(yīng)該有狀態(tài)這一個變量存在,更不應(yīng)該擁有零地標(biāo)恢復(fù)運(yùn)行這一操作。它只做一件事,處理IO口信息,產(chǎn)生相應(yīng)的障礙物狀態(tài)。低耦合:障礙物函數(shù)與其他模塊的耦合,僅僅為產(chǎn)生的障礙物狀態(tài)。下面深入探討注冊機(jī)制。
何謂注冊:我目前這樣理解的,相機(jī)要發(fā)送圖片,面臨著多種發(fā)送方式,每一種發(fā)送方式肯定會調(diào)用不同的函數(shù)。反過來想,就是我有很多的應(yīng)用,要使用相機(jī)這個模塊(此處對比定時器)。既然這樣,相機(jī)模塊定義一個注冊函數(shù),供其他模塊調(diào)用,以告訴相機(jī),允許使用對應(yīng)的發(fā)送方式。
#definenum_max20//最大設(shè)備數(shù)
typedefstruct
{
u8 num;//當(dāng)前注冊設(shè)備數(shù)
u8list_name[num_max];//用于保存注冊設(shè)備列表
void(*click[num_max])(u8*temp);//存放不同模塊(微信qq)的發(fā)送函數(shù)地址
}Equiment;
EquimentCOM;
/**************************注冊函數(shù)****************************************/
voidPhoto_Register(void(*a)(u8*temp),u8list)//提供給外部的接口
{
if(COM.num
微信中若要使用,在安裝過程中,提示打開相機(jī)權(quán)限,便是調(diào)用上述注冊函數(shù)。將微信本身自集成的發(fā)送函數(shù)地址傳給相機(jī),相機(jī)每次發(fā)送只需判斷哪些設(shè)備注冊了,選擇對應(yīng)的方式即可。如此一來,出現(xiàn)再多的新應(yīng)用要使用相機(jī),只需注冊一次即可。相機(jī)與微信QQ微博等模塊之間完美解耦!類似的,定時器的解耦也能這樣處理。
定時器運(yùn)用注冊機(jī)制
首先,要想解耦,必須去掉胡亂定義的標(biāo)志位與時間變量,只允許一個時間變量。因此定義一個32位的時間變量,不要任何條件限制,讓他一直自加。
參考arduino 中定時處理的方法:定義一個函數(shù)獲取當(dāng)前時間,保存下當(dāng)前時間,運(yùn)行一段時間后,再次查詢當(dāng)前時間,兩次做差,便得出運(yùn)行的時間。從以上不難看出,關(guān)鍵點(diǎn)在于:獲取當(dāng)前時間的函數(shù),當(dāng)前時間的存放,做差后的時間。以下是實(shí)現(xiàn)方法:
time.h
#include"stm32f10x.h"
#ifndef__TIME_H
#define__TIME_H
#defineTimerID_max20//最大注冊設(shè)備數(shù)
#defineRunOutOf_time(ID,ms)(systime.now-systime.last[ID-1]
time.c
#include"time.h"
/*********提供給外部的API*******************/
voidTimer_Init(u16CountData,u16FreqData);
unsignedcharsystime_get(void);
voidRefresh(u8ID);
/***********************************************/
SYSTIMEsystime=定義SYSTIME類型變量,并初始化函數(shù)指針
{
.get_id=systime_get,
.refresh=Refresh,
.timer_init=Timer_Init
};
/****************************************************/
//函數(shù)名:Timer_init
//描述:初始化定時器
//輸入:中斷時間相關(guān)
//輸出:null
/****************************************************/
voidTimer_Init(u16CountData,u16FreqData)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
NVIC_InitTypeDefNVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel=TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=4;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure;
TIM_DeInit(TIM4);
TIM_TimeBaseStructure.TIM_Prescaler=FreqData;
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure);
TIM_ClearFlag(TIM4,TIM_FLAG_Update);
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM4,ENABLE);
}
/****************************************************/
//函數(shù)名:systime_get
//描述:獲取當(dāng)前時間,并產(chǎn)生一個注冊
//輸入:null
//輸出:null
/****************************************************/
unsignedcharsystime_get()
{
if(systime.ID
在.c與.h實(shí)現(xiàn)了以上后,面向外部的只有三個函數(shù)
/*********提供給外部的API*******************/
voidTimer_Init(u16CountData,u16FreqData);
unsignedcharsystime_get(void);
voidRefresh(u8ID);
/***********************************************/
定時器的使用方法
1./*初始化*/
2.
/**********任務(wù)1實(shí)現(xiàn)運(yùn)行等閃爍,頻率1s**********/
voidtask1()
{
staticu8Task1_ID;
if(!Task1_ID)
Task1_ID=systime.get_id();
if(RunOutOf_time(Task1_ID,1000))
RUN_LED()=1;
elseif(RunOutOf_time(Task1_ID,2000))
RUN_LED()=0;
elseif(RunOutOf_time(Task1_ID,3000))
RUN_LED()=1;
elseif(RunOutOf_time(Task1_ID,4000))
RUN_LED()=0;
elseif(RunOutOf_time(Task1_ID,5000)
RUN_LED()=1;
else
systime.refresh(Task1_ID);
}
/*******************任務(wù)2實(shí)現(xiàn)運(yùn)行等閃爍,頻率100ms**********************/
voidtask2()
{
staticu8Task1_ID;
if(!Task1_ID)
Task1_ID=systime.get_id();
if(RunOutOf_time(Task1_ID,100))
RUN_LED()=1;
elseif(RunOutOf_time(Task1_ID,200))
RUN_LED()=0;
elseif(RunOutOf_time(Task1_ID,300))
RUN_LED()=1;
elseif(RunOutOf_time(Task1_ID,400))
RUN_LED()=0;
elseif(RunOutOf_time(Task1_ID,500))
RUN_LED()=1;
else
systime.refresh(Task1_ID);
}
/***************main函數(shù)實(shí)現(xiàn)任務(wù)1運(yùn)行10s,任務(wù)2運(yùn)行10s****************/
intmain(void)
{
staticu8main_ID;
System_Init();
while(1)
{
if(!main_ID)
main_ID=systime.get_id();
if(RunOutOf_time(main_ID,10000))
task1();
elseif(RunOutOf_time(main_ID,20000))
task2();
else
systime.refresh(main_ID);
}
}
以上,任何函數(shù)想要使用定時器,只需要按要求,設(shè)立一個ID存儲變量,以存儲注冊時分配的ID,便可調(diào)用定時器,且在任何平臺上均可方便的移植,只需修改硬件初始化。
此程序無法實(shí)現(xiàn)時刻任務(wù)執(zhí)行,例如某任務(wù)要100ms執(zhí)行一次,只能用作時間段內(nèi)執(zhí)行。原因在于程序主循環(huán)會耗時,導(dǎo)致輪詢時無法精準(zhǔn)捕捉到100ms時刻,想要達(dá)到此效果,還需改進(jìn)或者完全換一種思路來寫,例如捕捉放到中斷中,主循環(huán)來查詢100ms使能位。
審核編輯:劉清
-
存儲器
+關(guān)注
關(guān)注
39文章
7758瀏覽量
172283 -
定時器
+關(guān)注
關(guān)注
23文章
3375瀏覽量
124685 -
嵌入式軟件
+關(guān)注
關(guān)注
4文章
252瀏覽量
28180 -
Arduino
+關(guān)注
關(guān)注
190文章
6527瀏覽量
197521
原文標(biāo)題:嵌入式軟件開發(fā)中的注冊機(jī)制
文章出處:【微信號:技術(shù)讓夢想更偉大,微信公眾號:技術(shù)讓夢想更偉大】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
嵌入式軟件開發(fā)與非嵌入式軟件開發(fā)的區(qū)別?
如何學(xué)習(xí)嵌入式軟件開發(fā)
什么是嵌入式軟件開發(fā)
嵌入式軟件開發(fā)的優(yōu)缺點(diǎn)淺談
嵌入式軟件開發(fā)與Embedded-GIS
嵌入式軟件開發(fā)的優(yōu)勢分析
嵌入式軟件開發(fā)做什么?嵌入式開發(fā)培訓(xùn)學(xué)哪些
嵌入式軟件開發(fā)入門
嵌入式軟件開發(fā)與AI整合
嵌入式軟件開發(fā)是什么意思
評論