0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何解決引入注冊(cè)機(jī)制問題

STM32嵌入式開發(fā) ? 來源:STM32嵌入式開發(fā) ? 2023-08-16 09:17 ? 次閱讀

問題描述 在使用定時(shí)器的過程中最令人苦惱的就是,定義flag,holdtime,每用一次定義就會(huì)導(dǎo)致中斷函數(shù)中標(biāo)志位滿天飛,時(shí)間變量在程序中隨處可見。在想要移植,又不敢隨便刪除。程序處于高耦合狀態(tài),失去了一個(gè).c 一個(gè) .h的意義。

如何解決這種問題

引入注冊(cè)機(jī)制。為了方便說明注冊(cè)機(jī)制,舉一個(gè)例子:手機(jī)在使用相機(jī)這個(gè)功能時(shí),有一個(gè)操作:將拍攝的照片發(fā)送出去。以程序來實(shí)現(xiàn)這一過程,最容易想到的方法如下:

在相機(jī)的發(fā)送模塊添加以下代碼:

if (選擇發(fā)送)
{
     if(選擇微信發(fā)送)
     {
         獲取發(fā)送人;
         選擇發(fā)送人;
     }
     else if(選擇qq發(fā)送)
     {
         獲取發(fā)送人;
         選擇發(fā)送人;
     }
     else if(選擇微博發(fā)送)
     {
         獲取發(fā)送人;
         選擇發(fā)送人;
     }
    .
    .此處省略一萬行
    .
}

這是最容易想到的實(shí)現(xiàn)方式,就如上面定時(shí)器的實(shí)現(xiàn)方式,哪里要用了,再定義一系列變量就是了。回到相機(jī)例子,假設(shè)某一天一個(gè)比微信還火的聊天軟件出現(xiàn)了,用戶安裝了,想要發(fā)送圖片,這時(shí)該怎么做 ?當(dāng)然,只能在上面相機(jī)的發(fā)送發(fā)送模塊中添加else if(。。。。)和它的實(shí)現(xiàn)方式了,也就意味著,每更新一個(gè)需要使用圖片功能的軟件,就必須去修改相機(jī)模塊,是不是覺得和我們的定時(shí)器很像? 注冊(cè)的精髓: 解耦各個(gè)模塊。程序講究高內(nèi)聚,低耦合。我目前對(duì)這句話的理解是:高內(nèi)聚:每一個(gè)功能模塊(c文件,h文件),內(nèi)部不和其他模塊相互調(diào)用,比如障礙物函數(shù)里面不應(yīng)該有狀態(tài)這一個(gè)變量存在,更不應(yīng)該擁有零地標(biāo)恢復(fù)運(yùn)行這一操作。它只做一件事,處理IO口信息,產(chǎn)生相應(yīng)的障礙物狀態(tài)。低耦合:障礙物函數(shù)與其他模塊的耦合,僅僅為產(chǎn)生的障礙物狀態(tài)。下面深入探討注冊(cè)機(jī)制。 何謂注冊(cè):

我目前這樣理解的,相機(jī)要發(fā)送圖片,面臨著多種發(fā)送方式,每一種發(fā)送方式肯定會(huì)調(diào)用不同的函數(shù)。反過來想,就是我有很多的應(yīng)用,要使用相機(jī)這個(gè)模塊(此處對(duì)比定時(shí)器)。既然這樣,相機(jī)模塊定義一個(gè)注冊(cè)函數(shù),供其他模塊調(diào)用,以告訴相機(jī),允許使用對(duì)應(yīng)的發(fā)送方式。


#define num_max 20                        //最大設(shè)備數(shù)


typedef struct
{
  u8 num;//當(dāng)前注冊(cè)設(shè)備數(shù)
  u8 list_ name[num _max];                //用于保存注冊(cè)設(shè)備列表
  void (*click[num _max])(u8 * temp);  //存放不同模塊(微信qq)的發(fā)送函數(shù)地址
}Equiment;
Equiment  COM;            


/**************************注冊(cè)函數(shù)****************************************/
void  Photo_Register ( void(*a)(u8 * temp),u8 list )  //提供給外部的接口
{
   if(COM.num < num.max)
  {
      COM. click[COM. num]=a;          //保存函數(shù)地址
      COM. List _name [ COM. num ]=list;   //保存設(shè)備名至列表
      COM. num++;
  }
  else
  {
     /****超過最大設(shè)備數(shù)報(bào)錯(cuò)******/
  }
}


/*相機(jī)中的發(fā)送函數(shù)*/
void Click(u8 temp)           // 最終實(shí)現(xiàn)圖片發(fā)送調(diào)用此函數(shù)即可
{
   u8 i,NUM;
   for(i=0; i<= COM.num ; i++)
   {
    printf(“打印列表,顯示已經(jīng)注冊(cè)的設(shè)備”)
   } 
   NUM =Get(選擇的發(fā)送方式);
   if(!NUM)
   COM.click[NUM](temp);
}
/*******************以上在相機(jī)中實(shí)現(xiàn)************************************/

微信中若要使用,在安裝過程中,提示打開相機(jī)權(quán)限,便是調(diào)用上述注冊(cè)函數(shù)。將微信本身自集成的發(fā)送函數(shù)地址傳給相機(jī),相機(jī)每次發(fā)送只需判斷哪些設(shè)備注冊(cè)了,選擇對(duì)應(yīng)的方式即可。如此一來,出現(xiàn)再多的新應(yīng)用要使用相機(jī),只需注冊(cè)一次即可。相機(jī)與微信QQ微博等模塊之間完美解耦!類似的,定時(shí)器的解耦也能這樣處理。

定時(shí)器運(yùn)用注冊(cè)機(jī)制

首先,要想解耦,必須去掉胡亂定義的標(biāo)志位與時(shí)間變量,只允許一個(gè)時(shí)間變量。因此定義一個(gè)32位的時(shí)間變量,不要任何條件限制,讓他一直自加。 參考arduino 中定時(shí)處理的方法:定義一個(gè)函數(shù)獲取當(dāng)前時(shí)間,保存下當(dāng)前時(shí)間,運(yùn)行一段時(shí)間后,再次查詢當(dāng)前時(shí)間,兩次做差,便得出運(yùn)行的時(shí)間。從以上不難看出,關(guān)鍵點(diǎn)在于:獲取當(dāng)前時(shí)間的函數(shù),當(dāng)前時(shí)間的存放,做差后的時(shí)間。以下是實(shí)現(xiàn)方法:

time.h :

#include "stm32f10x.h"
#ifndef __TIME_H
#define __TIME_H


#define TimerID_max 20          //最大注冊(cè)設(shè)備數(shù)
#define RunOutOf_time(ID , ms)   ( systime.no w-systime.last[ID -1]< ms ) 


typedef struct
{
     u8 ID;                     //設(shè)備ID
     u32 now;                   //當(dāng)前時(shí)間
     u32 last[TimerID_max];     //存放抓取到的時(shí)間


     void (*timer_init)(u16 countdata,u16 freqData);   //指向初始化函數(shù)
     u8 (*get_id)(void);                               //指向獲取ID函數(shù)
     void (*refresh)(u8 ID);                           //指向更新時(shí)間函數(shù)


}SYSTIME;
extern SYSTIME systime;
#endif


time.c
#include "time.h"


/*********提供給外部的API*******************/
void Timer_Init(u16 CountData,u16 FreqData);
unsigned char systime_get(void);
void Refresh(u8 ID);
/***********************************************/
 SYSTIME systime =        定義SYSTIME類型變量,并初始化函數(shù)指針
{
     .get_id=systime_get,
     .refresh=Refresh,
     .timer_init=Timer_Init
};


/****************************************************/
//函數(shù)名:Timer_init
//描述:初始化定時(shí)器
//輸入:中斷時(shí)間相關(guān)
//輸出:null
/****************************************************/
void Timer_Init(u16 CountData,u16 FreqData)
{
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);         
 NVIC_InitTypeDef NVIC_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_TimeBaseInitTypeDef  TIM_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)前時(shí)間,并產(chǎn)生一個(gè)注冊(cè)
//輸入:null
//輸出:null
/****************************************************/
unsigned char systime_get()
{
    if(systime.ID

在.c與.h實(shí)現(xiàn)了以上后,面向外部的只有三個(gè)函數(shù):

/*********提供給外部的API*******************/
void Timer_Init(u16 CountData,u16 FreqData);    
unsigned char systime_get(void);
void Refresh(u8 ID);
/***********************************************/

定時(shí)器的使用方法


1

/*初始化*/
2
  /**********任務(wù)1實(shí)現(xiàn)運(yùn)行等閃爍,頻率1s **********/    
void task1()
{
        static u8 Task1_ID;
 if(!Task1_ID)
    Task1_ID=systime.get_id();
        if(RunOutOf_time(Task1_ID,1000))
    RUN_LED()=1; 
 else if(RunOutOf_time(Task1_ID,2000))
    RUN_LED()=0; 
 else if(RunOutOf_time(Task1_ID,3000))
    RUN_LED()=1; 
 else if(RunOutOf_time(Task1_ID,4000))
    RUN_LED()=0; 
 else if(RunOutOf_time(Task1_ID,5000)
            RUN_LED()=1; 
 else
    systime.refresh(Task1_ID);   
}


/*******************任務(wù)2實(shí)現(xiàn)運(yùn)行等閃爍,頻率100ms**********************/  
void task2()
{
 static u8 Task1_ID;
 if(!Task1_ID)
   Task1_ID=systime.get_id();
 if(RunOutOf_time(Task1_ID,100))
   RUN_LED()=1; 
 else if(RunOutOf_time(Task1_ID,200))
          RUN_LED()=0; 
 else if(RunOutOf_time(Task1_ID,300))
   RUN_LED()=1; 
 else if(RunOutOf_time(Task1_ID,400))
   RUN_LED()=0; 
        else if(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****************/
int main(void)
{
        static u8 main_ID;
        System_Init();
        while(1)
        {   
    if(!main_ID)
       main_ID=systime.get_id();
    if(RunOutOf_time(main_ID,10000))
       task1();
    else if(RunOutOf_time(main_ID,20000))
       task2();
    else
             systime.refresh(main_ID); 
        }
}

以上,任何函數(shù)想要使用定時(shí)器,只需要按要求,設(shè)立一個(gè)ID存儲(chǔ)變量,以存儲(chǔ)注冊(cè)時(shí)分配的ID,便可調(diào)用定時(shí)器,且在任何平臺(tái)上均可方便的移植,只需修改硬件初始化。 此程序無法實(shí)現(xiàn)時(shí)刻任務(wù)執(zhí)行,例如某任務(wù)要100ms執(zhí)行一次,只能用作時(shí)間段內(nèi)執(zhí)行。原因在于程序主循環(huán)會(huì)耗時(shí),導(dǎo)致輪詢時(shí)無法精準(zhǔn)捕捉到100ms時(shí)刻,想要達(dá)到此效果,還需改進(jìn)或者完全換一種思路來寫,例如捕捉放到中斷中,主循環(huán)來查詢100ms使能位。

責(zé)任編輯:彭菁

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 相機(jī)
    +關(guān)注

    關(guān)注

    4

    文章

    1337

    瀏覽量

    53438
  • 定時(shí)器
    +關(guān)注

    關(guān)注

    23

    文章

    3232

    瀏覽量

    114329
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4284

    瀏覽量

    62325
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4723

    瀏覽量

    68236
  • 注冊(cè)
    +關(guān)注

    關(guān)注

    2

    文章

    7

    瀏覽量

    11240

原文標(biāo)題:簡單介紹一下嵌入式軟件開發(fā)中的注冊(cè)機(jī)制!

文章出處:【微信號(hào):c-stm32,微信公眾號(hào):STM32嵌入式開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    注冊(cè)機(jī) MDK注冊(cè)機(jī) MDK注冊(cè)機(jī)

    MDK注冊(cè)機(jī)MDK注冊(cè)機(jī) MDK注冊(cè)機(jī)MDK注冊(cè)機(jī)
    發(fā)表于 12-30 15:37

    力控注冊(cè)機(jī)

    電子發(fā)燒友網(wǎng)站提供《力控注冊(cè)機(jī).rar》資料免費(fèi)下載
    發(fā)表于 11-16 19:37 ?44次下載

    AutoCAD 2015 注冊(cè)機(jī)

    auto cad 2015 注冊(cè)機(jī) 需要的拿去 。
    發(fā)表于 10-29 15:19 ?13次下載

    注冊(cè)機(jī)UltraEdit

    注冊(cè)機(jī)UltraEdit注冊(cè)機(jī)UltraEdit注冊(cè)機(jī)UltraEdit
    發(fā)表于 12-28 14:30 ?6次下載

    KeiluVision4_p注冊(cè)機(jī)

    KeiluVision4_p注冊(cè)機(jī)jKeiluVision4_p注冊(cè)機(jī)jKeiluVision4_p注冊(cè)機(jī)jKeiluVision4_p注冊(cè)機(jī)j
    發(fā)表于 02-19 14:58 ?11次下載

    Delphi教程之軟件注冊(cè)機(jī)制的建立

    Delphi教程之軟件注冊(cè)機(jī)制的建立,很好的Delphi資料,快來下載吧。
    發(fā)表于 04-11 16:09 ?5次下載

    C#教程之注冊(cè)注冊(cè)機(jī)制

    C#教程之注冊(cè)注冊(cè)機(jī)制,很好的C#資料,快來學(xué)習(xí)吧。
    發(fā)表于 04-21 09:52 ?17次下載

    keygen注冊(cè)機(jī)

    keygen注冊(cè)機(jī),感興趣的可以下載看看。
    發(fā)表于 06-21 16:42 ?32次下載

    AutoCAD 2017注冊(cè)機(jī)使用方法

    AutoCAD 2017注冊(cè)機(jī)使用方法。
    發(fā)表于 08-17 10:36 ?0次下載

    autocad2007注冊(cè)機(jī)以及cad2007注冊(cè)機(jī)使用方法免費(fèi)分享

    電子發(fā)燒友網(wǎng)站提供《autocad2007注冊(cè)機(jī)以及cad2007注冊(cè)機(jī)使用方法免費(fèi)分享.zip》資料免費(fèi)下載
    發(fā)表于 12-20 12:31 ?6次下載

    Keil C51 9.0應(yīng)用程序和注冊(cè)機(jī)注冊(cè)機(jī)使用方法免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是Keil C51 9.0應(yīng)用程序和注冊(cè)機(jī)注冊(cè)機(jī)使用方法免費(fèi)下載。
    發(fā)表于 05-20 08:00 ?47次下載
    Keil C51 9.0應(yīng)用程序和<b class='flag-5'>注冊(cè)機(jī)</b>及<b class='flag-5'>注冊(cè)機(jī)</b>使用方法免費(fèi)下載

    CAD激活注冊(cè)機(jī)

    CAD注冊(cè)機(jī)
    發(fā)表于 06-09 15:04 ?11次下載

    keil注冊(cè)機(jī)下載

    keil注冊(cè)機(jī)
    發(fā)表于 07-21 17:01 ?257次下載

    嵌入式函數(shù)回調(diào)注冊(cè)機(jī)制的實(shí)現(xiàn)

    嵌入式函數(shù)回調(diào)注冊(cè)機(jī)制是一種常用的解耦技術(shù),它通過在應(yīng)用程序中注冊(cè)回調(diào)函數(shù)的方式來實(shí)現(xiàn)模塊之間的通信,從而使系統(tǒng)更加靈活、可擴(kuò)展和易于維護(hù)。函數(shù)回調(diào)注冊(cè)機(jī)制可以通過函數(shù)指針和回調(diào)函數(shù)來實(shí)現(xiàn)。
    的頭像 發(fā)表于 04-13 15:52 ?1321次閱讀

    什么是函數(shù)回調(diào)注冊(cè)機(jī)制?實(shí)現(xiàn)的大致步驟介紹

    嵌入式函數(shù)回調(diào)注冊(cè)機(jī)制是一種常用的解耦技術(shù),它通過在應(yīng)用程序中注冊(cè)回調(diào)函數(shù)的方式來實(shí)現(xiàn)模塊之間的通信
    的頭像 發(fā)表于 05-20 16:43 ?4235次閱讀