最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊

嵌入式軟件開發(fā)常用的3種架構(gòu)

2022-09-15 20:54 作者:Linux遠(yuǎn)航者  | 我要投稿

摘要:對于單片機(jī)程序來說,大家都不陌生,但是真正使用架構(gòu),考慮架構(gòu)的恐怕并不多,隨著程序開發(fā)的不斷增多,架構(gòu)是非常必要的。

應(yīng)用程序的架構(gòu)大致有三種:

  • 1、簡單的前后臺順序執(zhí)行程序,這類寫法是大多數(shù)人使用的方法,不需用思考程序的具體架構(gòu),直接通過執(zhí)行順序編寫應(yīng)用程序即可。

  • 2、時(shí)間片輪詢法,此方法是介于順序執(zhí)行與操作系統(tǒng)之間的一種方法。

  • 3、操作系統(tǒng),此法應(yīng)該是應(yīng)用程序編寫的最高境界。

一、程序框架設(shè)計(jì)

1、前后臺順序執(zhí)行法

這是初學(xué)者們常用的程序框架設(shè)計(jì)方案,不用考慮太多東西,代碼簡單,或者對系統(tǒng)的整體實(shí)時(shí)性和并發(fā)性要求不高;初始化后通過while(1){}for(;;){}`循環(huán)不斷調(diào)用自己編寫完成的函數(shù),也基本不考慮每個(gè)函數(shù)執(zhí)行所需要的時(shí)間,大部分情況下函數(shù)中或多或少都存在毫秒級別的延時(shí)等待。

  • 優(yōu)點(diǎn):對于初學(xué)者來說,這是最容易也是最直觀的程序架構(gòu),邏輯簡單明了,適用于邏輯簡單,復(fù)雜度比較低的軟件開發(fā)。

  • 缺點(diǎn):實(shí)時(shí)性低,由于每個(gè)函數(shù)或多或少存在毫秒級別的延時(shí),即使是1ms,也會(huì)造成其他函數(shù)間隔執(zhí)行時(shí)間的不同,雖然可通過定時(shí)器中斷的方式,但是前提是中斷執(zhí)行函數(shù)花的時(shí)間必須短。當(dāng)程序邏輯復(fù)雜度提升時(shí),會(huì)導(dǎo)致后來維護(hù)人員的大腦混亂,很難理清楚該程序的運(yùn)行狀態(tài)。

【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【865977150】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。?/p>

以下是在校期間做的寢室防盜系統(tǒng)的部分代碼(當(dāng)時(shí)也存在部分BUG,沒有解決?,F(xiàn)在再看,其實(shí)很多問題,而且比較嚴(yán)重,比如中斷服務(wù)函數(shù)內(nèi)竟然有3000ms延時(shí),這太可怕了,還有串口發(fā)送等等;由于實(shí)時(shí)性要求不算太高,因此主函數(shù)中的毫秒級別延時(shí)對系統(tǒng)運(yùn)行沒有多大影響,當(dāng)然除BUG外;若是后期需要維護(hù),那就是一個(gè)大工程,還不如推翻重寫):

int main(void) { ?u8 temperature; ? ? ? ?u8 humidity; ? int a; delay_init(); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); ?I2c_init(); uart2_Init(9600); uart_init(9600);//串口初始化為115200 ? TIM3_Int_Init(4999,7199); ds1302_init(); while(DHT11_Init())//DHT11初始化 { ?led2=0; } a1602_init(); ? ?Ds1302Init(); EXTIX_Init(); ? GPIOX_Init(); lcd12864_INIT(); LcdInit(); beep_init(); RED_Init(); led1=1; beep=0; while(1) { ?for(a=0;a<11;a++) ?{ ? num[a+3]=At24c02Read(a+2)-208; ? delay_us(10); ? ? ?} ?for(a=0;a<6;a++) ?{ ? shuru[a]=At24c02Read(a+13)-208; ? delay_us(10); ? ? ?} ? ?delay_ms(10); ? ?RED_Scan(); ?Ds1302ReadTime(); ?//讀取ds1302的日期時(shí)間 ?shi=At24c02Read(0); //讀取鬧鐘保存的數(shù)據(jù) ?delay_ms(10); ?fen=At24c02Read(1); //讀取鬧鐘保存的數(shù)據(jù) ? ?usart2_scan(); ? //藍(lán)牙數(shù)據(jù)掃描 ?usart2_bian(); ? //藍(lán)牙處理數(shù)據(jù) ?usart2_gai(); ?nao_scan(); ?k++; ?if(k<20) ?{ ? if(k==1) ? ?LcdWriteCom(0x01);//清屏 ? ?LcdDisplay(); ? ? //顯示日期時(shí)間 ?} ?if(RED==0) ? ? RED_Scan(); ? ? ?if(k>=20&&k<30) ?{ ? if(k==20) ? ?LcdWriteCom(0x01); //清屏 ? Lcddisplay(); //顯示溫濕度 ? LcdWriteCom(0x80+6); ? DHT11_Read_Data(&temperature,&humidity); //讀取溫濕度值 ? Temp=temperature;Humi=humidity; ? LcdWriteData('0'+temperature/10); ? LcdWriteData('0'+temperature%10); ? LcdWriteCom(0x80+0X40+6); ? LcdWriteData('0'+humidity/10); ? LcdWriteData('0'+humidity%10); ?} ?if(k==30) ? k=0; ?lcd12864(); //顯示防盜鬧鐘狀態(tài) } ? } //定時(shí)器3中斷服務(wù)程序 void TIM3_IRQHandler(void)//TIM3中斷 { int i; if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //檢查TIM3更新中斷發(fā)生與否 { ?TIM_ClearITPendingBit(TIM3, TIM_IT_Update);//清除TIMx更新中斷標(biāo)志 ?if(key1==1&&FEN-fen==0&&SHI-shi==0)//時(shí)間一到鬧鐘響起 ?{ ? ?f=1; ? ? ? ?} ?if(key1==0||FEN-fen!=0||SHI-shi!=0) ?else ?{ ? ?f=0; ?} ? if(USART_RX_BUF[0]=='R'&&USART_RX_BUF[1]=='I'&&USART_RX_BUF[2]=='N'&&USART_RX_BUF[3]=='G') ?{ ? key0=1; ? for(i=0;i<17;i++) ? { ? ?USART_SendData(USART1, num[i]);//向串口1發(fā)送數(shù)據(jù) ? ?while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待發(fā)送結(jié)束 ? ?USART_RX_STA=0; ? } ? delay_ms(3000); ? for(i=0;i<3;i++) ? { ? ?USART_SendData(USART1, num1[i]);//向串口1發(fā)送數(shù)據(jù) ? ?while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待發(fā)送結(jié)束 ? ?USART_RX_STA=0; ? } ? ?} } }

二、時(shí)間片論法

介于前后臺順序執(zhí)行法操作系統(tǒng)之間的一種程序架構(gòu)設(shè)計(jì)方案。該設(shè)計(jì)方案需能幫助嵌入式軟件開發(fā)者更上一層樓,在嵌入式軟件開發(fā)過程中,若遇到以下幾點(diǎn),那么該設(shè)計(jì)方案可以說是最優(yōu)選擇,適用于程序較復(fù)雜的嵌入式系統(tǒng);

  • 目前的需求設(shè)計(jì)需要完全沒有必要上操作系統(tǒng)。

  • 任務(wù)函數(shù)無需時(shí)刻執(zhí)行,存在間隔時(shí)間(比如按鍵,一般情況下,都需要軟件防抖,初學(xué)者的做法通常是延時(shí)10ms左右再去判斷,但10ms極大浪費(fèi)了CPU的資源,在這段時(shí)間內(nèi)CPU完全可以處理很多其他事情)

  • 實(shí)時(shí)性有一定的要求。

該設(shè)計(jì)方案需要使用一個(gè)定時(shí)器,一般情況下定時(shí)1ms即可(定時(shí)時(shí)間可隨意定,但中斷過于頻繁效率就低,中斷太長,實(shí)時(shí)性差),因此需要考慮到每個(gè)任務(wù)函數(shù)的執(zhí)行時(shí)間,建議不能超過1ms(能通過程序優(yōu)化縮短執(zhí)行時(shí)間則最好優(yōu)化,如果不能優(yōu)化的,則必須保證該任務(wù)的執(zhí)行周期必須遠(yuǎn)大于任務(wù)所執(zhí)行的耗時(shí)時(shí)間),同時(shí)要求主循環(huán)或任務(wù)函數(shù)中不能存在毫秒級別的延時(shí)。

“如何確定每個(gè)函數(shù)的任務(wù)周期呢?根據(jù)任務(wù)的耗時(shí)和效果決定、如按鍵掃描任務(wù)周期為 10ms(為了提高響應(yīng)),指示燈控制任務(wù)周期為 100ms(通常情況下最高100ms的閃爍頻率正好,特殊需求除外),LCD/OLED 顯示周期為 100ms(通過這種通過SPI/IIC等接口的方式耗時(shí)大約在 1~10ms,甚至更長,所以任務(wù)周期必須遠(yuǎn)大于耗時(shí),同時(shí)為了滿足人眼所能接受的刷屏效果,也不能太長,100ms 的任務(wù)周期比較合適)等。

以下介紹兩種不同的實(shí)現(xiàn)方案,分別針對無函數(shù)指針概念的朋友和想進(jìn)一步學(xué)習(xí)的朋友。

1、無函數(shù)指針的設(shè)計(jì)方式

/** ?* @brief ? ? ?主函數(shù). ?* @param ? ? ?None. ?* @return ? ? None. ?*/int main(void){ ? ?System_Init(); ? ? ? ?while (1) ? ?{ ? ? ? ?if (TIM_1msFlag)// 1ms ? ? ? ?{ ? ? ? ? ? ?CAN_CommTask(); // CAN發(fā)送/接收通信任務(wù) ? ? ? ? ? ? ? ? ? ? ? ?TIM_1msFlag = 0; ? ? ? ?} ? ? ? ? ? ? ? ?if (TIM_10msFlag) ?// 10ms ? ? ? ?{ ? ? ? ? ? ?KEY_ScanTask(); // 按鍵掃描處理任務(wù) ? ? ? ? ? ? ? ? ? ? ? ?TIM_10msFlag = 0; ? ? ? ?} ? ? ? ? ? ? ? ?if (TIM_20msFlag) // 20ms ? ? ? ?{ ? ? ? ? ? ?LOGIC_HandleTask();// 邏輯處理任務(wù) ? ? ? ? ? ?TIM_20msFlag = 0; ? ? ? ?} ? ? ? ? ? ? ? ?if (TIM_100msFlag) // 100ms ? ? ? ?{ ? ? ? ? ? ?LED_CtrlTask(); // 指示燈控制任務(wù) ? ? ? ? ? ? ? ? ? ? ? ?TIM_100msFlag = 0; ? ? ? ?} ? ? ? ? ? ? ?if (TIM_500msFlag)// 500ms ? ? ? ?{ ? ? ? ? ? ?TIM_500msFlag = 0; ? ? ? ?} ? ? ? ? ? ? ? ?if (TIM_1secFlag) // 1s ? ? ? ?{ ? ? ? ? ? ?WDog_Task(); // 喂狗任務(wù) ? ? ? ? ? ? ? ? ? ? ? ?TIM_1secFlag = 0; ? ? ? ?} ? ? ?}} /** ?* @brief ? ? ?定時(shí)器3中斷服務(wù)函數(shù). ?* @param ? ? ?None. ?* @return ? ? None. ?*/void TIM3_IRQHandler(void){ ? ?if(TIM_GetITStatus(TIM3,TIM_IT_Update) == SET) //溢出中斷 ? ?{ ? ? ? ?sg_1msTic++; ? ? ? ? ? ? ? ?sg_1msTic % 1 == 0 ? TIM_1msFlag = 1 : 0; ? ? ? ? ? ? ? ?sg_1msTic % 10 == 0 ? TIM_10msFlag = 1 : 0; ? ? ? ? ? ? ? ?sg_1msTic % 20 == 0 ? TIM_20msFlag = 1 : 0; ? ? ? ? ? ? ? ?sg_1msTic % 100 == 0 ? TIM_100msFlag = 1 : 0; ? ? ? ? ? ? ?sg_1msTic % 500 == 0 ? TIM_500msFlag = 1 : 0; ? ? ? ? ? ? ?sg_1msTic % 1000 == 0 ? (TIM_1secFlag ?= 1, sg_1msTic = 0) : 0; ? ?} ? ? ? ?TIM_ClearITPendingBit(TIM3,TIM_IT_Update); ?// 清除中斷標(biāo)志位}

2、含函數(shù)指針的設(shè)計(jì)方式

/** ?* @brief 任務(wù)函數(shù)相關(guān)信息結(jié)構(gòu)體定義. ?*/ typedef struct{ ? ?uint8 m_runFlag; ? ? ? ? ? ? ? ? /*!< 程序運(yùn)行標(biāo)記:0-不運(yùn)行,1運(yùn)行 */ ? ?uint16 m_timer; ? ? ? ? ? ? ? ? ?/*!< 計(jì)時(shí)器 */ ? ?uint16 m_itvTime; ? ? ? ? ? ? ? ?/*!< 任務(wù)運(yùn)行間隔時(shí)間 */ ? ?void (*m_pTaskHook)(void); ? ? ? /*!< 要運(yùn)行的任務(wù)函數(shù) */ } TASK_InfoType; #define TASKS_MAX ? ? 5 ? ? ? ? ? ? ?// 定義任務(wù)數(shù)目 /** 任務(wù)函數(shù)相關(guān)信息 */ static TASK_InfoType sg_tTaskInfo[TASKS_MAX] = { ? ?{0, 1, 1, CAN_CommTask}, ? ? ? ? // CAN通信任務(wù) ? ?{0, 10, 10, KEY_ScanTask}, ? ? ? // 按鍵掃描任務(wù) ? ?{0, 20, 20, LOGIC_HandleTask}, ? // 邏輯處理任務(wù) ? ?{0, 100, 100, LED_CtrlTask}, ? ? // 指示燈控制任務(wù) ? ?{0, 1000, 1000, WDog_Task}, ? ? ?// 喂狗任務(wù) }; /** ?* @brief ? ? ?任務(wù)函數(shù)運(yùn)行標(biāo)志處理. ?* @note ? ? ? 該函數(shù)由1ms定時(shí)器中斷調(diào)用 ?* @param ? ? ?None. ?* @return ? ? None. ?*/ void TASK_Remarks(void) { ? ?uint8 i; ? ?for (i = 0; i < TASKS_MAX; i++) ? ?{ ? ? ? ?if (sg_tTaskInfo[i].m_timer) ? ? ? ?{ ? ? ? ? ? ?sg_tTaskInfo[i].m_timer--; ? ? ? ? ? ?if (0 == sg_tTaskInfo[i].m_timer) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? sg_tTaskInfo[i].m_timer = sg_tTaskInfo[i].m_itvTime; ? ? ? ? ? ? ? ? sg_tTaskInfo[i].m_runFlag = 1; ? ? ? ? ? ?} ? ? ? ?} ? } } /** ?* @brief ? ? ?任務(wù)函數(shù)運(yùn)行處理. ?* @note ? ? ? 該函數(shù)由主循環(huán)調(diào)用 ?* @param ? ? ?None. ?* @return ? ? None. ?*/ void TASK_Process(void) { ? ?uint8 i; ? ?for (i = 0; i < TASKS_MAX; i++) ? ?{ ? ? ? ?if (sg_tTaskInfo[i].m_runFlag) ? ? ? ?{ ? ? ? ? ? ? sg_tTaskInfo[i].m_pTaskHook(); ? ? ? ? // 運(yùn)行任務(wù) ? ? ? ? ? ? sg_tTaskInfo[i].m_runFlag = 0; ? ? ? ? // 標(biāo)志清0 ? ? ? ?} ? ?} ? } /** ?* @brief ? ? ?主函數(shù). ?* @param ? ? ?None. ?* @return ? ? None. ?*/ int main(void) { ? ?System_Init(); ? ? ? ?while (1) ? ?{ ? ? ? ?TASK_Process(); ? ?} } /** ?* @brief ? ? ?定時(shí)器3中斷服務(wù)函數(shù). ?* @param ? ? ?None. ?* @return ? ? None. ?*/ void TIM3_IRQHandler(void) { ? ?if(TIM_GetITStatus(TIM3,TIM_IT_Update) == SET) //溢出中斷 ? ?{ ? ? ? ?TASK_Remarks(); ? ?} ? ? ? ?TIM_ClearITPendingBit(TIM3,TIM_IT_Update);// 清除中斷標(biāo)志位 }

三、操作系統(tǒng)

嵌入式操作系統(tǒng)EOS(Embedded OperatingSystem)是一種用途廣泛的系統(tǒng)軟件,過去它主要應(yīng)用于工業(yè)控制和國防系統(tǒng)領(lǐng)域,而對于單片機(jī)來說,比較常用的有UCOS、FreeRTOS、RT-Thread?Nano和RTX 等多種搶占式操作系統(tǒng)(其他如Linux等操作系統(tǒng)不適用于單片機(jī))

操作系統(tǒng)和“時(shí)間片論法”,在任務(wù)執(zhí)行方面來說,操作系統(tǒng)對每個(gè)任務(wù)的耗時(shí)沒有過多的要求,需要通過設(shè)置每個(gè)任務(wù)的優(yōu)先級,在高優(yōu)先級的任務(wù)就緒時(shí),會(huì)搶占低優(yōu)先級的任務(wù);操作系統(tǒng)相對復(fù)雜,因此這里沒有詳細(xì)介紹了。

關(guān)于如何選擇合適的操作系統(tǒng)(uCOSFreeRTOS、RTThreadRTX等RTOS的對比之特點(diǎn):

  • uCOS:網(wǎng)上資料豐富,非常適合學(xué)習(xí),但是在產(chǎn)品上使用則需要收費(fèi)。

  • FreeRTOS:使用免費(fèi),因此很多產(chǎn)品都在用。

  • RT-Thread:國產(chǎn)物聯(lián)網(wǎng)操作系統(tǒng),有著十分豐富的組件,也免費(fèi),資料:RT-Thread文檔中心。

  • RTX:為ARM和Cortex-M設(shè)備設(shè)計(jì)的免版稅,確定性的實(shí)時(shí)操作系統(tǒng)。

借網(wǎng)上一張對比圖:

四、總結(jié)

從上述的對比中可以看出,時(shí)間片輪詢法的優(yōu)勢還是比較大的,它既有前后臺順序執(zhí)行法的優(yōu)點(diǎn),也有操作系統(tǒng)的優(yōu)點(diǎn)。結(jié)構(gòu)清晰,簡單,非常容易理解,所以這種是比較常用的單片機(jī)設(shè)計(jì)框架。


嵌入式軟件開發(fā)常用的3種架構(gòu)的評論 (共 條)

分享到微博請遵守國家法律
东光县| 德阳市| 治县。| 凉城县| 惠安县| 自贡市| 宣武区| 义乌市| 阿鲁科尔沁旗| 威信县| 安徽省| 临海市| 金阳县| 宜城市| 许昌市| 和林格尔县| 佛学| 万安县| 汨罗市| 淄博市| 奉化市| 肥西县| 阳西县| 清河县| 乌鲁木齐市| 阿合奇县| 龙岩市| 双辽市| 天长市| 葫芦岛市| 揭东县| 当阳市| 木兰县| 沙雅县| 安平县| 繁峙县| 武定县| 吴桥县| 会东县| 如东县| 色达县|