可能很多工程師,工作了很多年,都不會(huì)有軟件架構(gòu)的概念。 因?yàn)槲以谧鲅邪l(fā)工程師的第6年,才開(kāi)始意識(shí)到這個(gè)東西,在此之前,都是做一些比較簡(jiǎn)單的項(xiàng)目,一個(gè)main函數(shù)干到底,架構(gòu)復(fù)雜了反而是累贅。 后面有幸,接觸了稍微復(fù)雜點(diǎn)的項(xiàng)目,感覺(jué)以前水平Hold不住,然后借著項(xiàng)目需求,學(xué)習(xí)了很多優(yōu)秀的代碼架構(gòu),比如以前同事的,一些模組廠的SDK,還有市面上成熟的系統(tǒng)。 說(shuō)出來(lái)可能有點(diǎn)夸張,一個(gè)好項(xiàng)目帶來(lái)的成長(zhǎng),頂你做幾年小項(xiàng)目。 在一個(gè)工程師從入門(mén)到成為高級(jí)工程師,都會(huì)經(jīng)歷哪些軟件架構(gòu)?
下面給大家盤(pán)點(diǎn)一下,每個(gè)都提供了簡(jiǎn)易的架構(gòu)模型代碼,難度循環(huán)漸進(jìn)。
1.線(xiàn)性架構(gòu)
這是最簡(jiǎn)單的一種程序設(shè)計(jì)方法,也就是我們?cè)谌腴T(mén)時(shí)寫(xiě)的,下面是一個(gè)使用C語(yǔ)言編寫(xiě)的線(xiàn)性架構(gòu)示例:
#include? 2.模塊化架構(gòu) 模塊化架構(gòu)是一種將程序分解為獨(dú)立模塊的設(shè)計(jì)方法,每個(gè)模塊執(zhí)行特定的任務(wù)。 這種架構(gòu)有助于代碼的重用、維護(hù)和測(cè)試。 下面是一個(gè)使用C語(yǔ)言編寫(xiě)的模塊化架構(gòu)示例,該程序模擬了一個(gè)簡(jiǎn)單的交通信號(hào)燈控制系統(tǒng)。// 包含51系列單片機(jī)的寄存器定義 // 延時(shí)函數(shù),用于產(chǎn)生一定的延遲 void delay(unsigned int count) { unsigned int i; while(count--) { for(i = 0; i < 120; i++) {} // 空循環(huán),用于產(chǎn)生延遲 } } void main() { // 初始設(shè)置P1端口為輸出模式,用于控制LED P1 = 0xFF; // 將P1端口設(shè)置為高電平,關(guān)閉所有LED while(1) { // 無(wú)限循環(huán) P1 = 0x00; // 將P1端口設(shè)置為低電平,點(diǎn)亮所有LED delay(500000); // 調(diào)用延時(shí)函數(shù),延遲一段時(shí)間 P1 = 0xFF; // 將P1端口設(shè)置為高電平,關(guān)閉所有LED delay(500000); // 再次調(diào)用延時(shí)函數(shù),延遲相同的時(shí)間 } }
#include// 包含51系列單片機(jī)的寄存器定義 // 定義信號(hào)燈的狀態(tài) typedef enum { RED_LIGHT, YELLOW_LIGHT, GREEN_LIGHT } TrafficLightState; // 函數(shù)聲明 void initializeTrafficLight(void); void setTrafficLight(TrafficLightState state); void delay(unsigned int milliseconds); // 信號(hào)燈控制主函數(shù) void main(void) { initializeTrafficLight(); // 初始化交通信號(hào)燈 while(1) { setTrafficLight(RED_LIGHT); delay(5000); // 紅燈亮5秒 setTrafficLight(YELLOW_LIGHT); delay(2000); // 黃燈亮2秒 setTrafficLight(GREEN_LIGHT); delay(5000); // 綠燈亮5秒 } } // 初始化交通信號(hào)燈的函數(shù) void initializeTrafficLight(void) { // 這里可以添加初始化代碼,比如設(shè)置端口方向、默認(rèn)狀態(tài)等 // 假設(shè)P1端口連接了信號(hào)燈,初始狀態(tài)為熄滅(高電平) P1 = 0xFF; } // 設(shè)置交通信號(hào)燈狀態(tài)的函數(shù) void setTrafficLight(TrafficLightState state) { switch(state) { case RED_LIGHT: // 設(shè)置紅燈亮,其他燈滅 P1 = 0b11100000; // 假設(shè)低電平有效,這里設(shè)置P1.0為低電平,其余為高電平 break; case YELLOW_LIGHT: // 設(shè)置黃燈亮,其他燈滅 P1 = 0b11011000; // 設(shè)置P1.1為低電平,其余為高電平 break; case GREEN_LIGHT: // 設(shè)置綠燈亮,其他燈滅 P1 = 0b11000111; // 設(shè)置P1.2為低電平,其余為高電平 break; default: // 默認(rèn)為熄滅所有燈 P1 = 0xFF; break; } } // 延時(shí)函數(shù),參數(shù)是毫秒數(shù) void delay(unsigned int milliseconds) { unsigned int delayCount = 0; while(milliseconds--) { for(delayCount = 0; delayCount < 120; delayCount++) { // 空循環(huán),用于產(chǎn)生延時(shí) } } }
3.層次化架構(gòu) 層次化架構(gòu)是一種將系統(tǒng)分解為多個(gè)層次的設(shè)計(jì)方法,每個(gè)層次負(fù)責(zé)不同的功能。
著以下是一個(gè)使用C語(yǔ)言編寫(xiě)的層次化架構(gòu)示例,模擬了一個(gè)具有不同權(quán)限級(jí)別的嵌入式系統(tǒng)。
#include4.事件驅(qū)動(dòng)架構(gòu)// 包含51系列單片機(jī)的寄存器定義 // 定義不同的操作級(jí)別 typedef enum { LEVEL_USER, LEVEL_ADMIN, LEVEL_SUPERUSER } OperationLevel; // 函數(shù)聲明 void systemInit(void); void performOperation(OperationLevel level); void displayMessage(char* message); // 系統(tǒng)初始化后的主循環(huán) void main(void) { systemInit(); // 系統(tǒng)初始化 // 模擬用戶(hù)操作 performOperation(LEVEL_USER); // 模擬管理員操作 performOperation(LEVEL_ADMIN); // 模擬超級(jí)用戶(hù)操作 performOperation(LEVEL_SUPERUSER); while(1) { // 主循環(huán)可以是空閑循環(huán)或者處理其他低優(yōu)先級(jí)任務(wù) } } // 系統(tǒng)初始化函數(shù) void systemInit(void) { // 初始化系統(tǒng)資源,如設(shè)置端口、中斷等 // 這里省略具體的初始化代碼 } // 執(zhí)行不同級(jí)別操作的函數(shù) void performOperation(OperationLevel level) { switch(level) { case LEVEL_USER: //用戶(hù)操作具體代碼 break; case LEVEL_ADMIN: //管理員操作具體代碼 break; case LEVEL_SUPERUSER: //超級(jí)用戶(hù)操作具體代碼 break; } } // 顯示消息的函數(shù) void displayMessage(char* message) { // 這里省略了實(shí)際的顯示代碼,因?yàn)閱纹瑱C(jī)通常沒(méi)有直接的屏幕輸出 // 消息可以通過(guò)LED閃爍、串口輸出或其他方式展示 // 假設(shè)通過(guò)P1端口的LED展示,每個(gè)字符對(duì)應(yīng)一個(gè)LED閃爍模式 // 實(shí)際應(yīng)用中,需要根據(jù)硬件設(shè)計(jì)來(lái)實(shí)現(xiàn)消息的顯示 }
事件驅(qū)動(dòng)架構(gòu)是一種編程范式,其中程序的執(zhí)行流程由事件(如用戶(hù)輸入、傳感器變化、定時(shí)器到期等)觸發(fā)。 在單片機(jī)開(kāi)發(fā)中,事件驅(qū)動(dòng)架構(gòu)通常用于響應(yīng)外部硬件中斷或軟件中斷。 以下是一個(gè)使用C語(yǔ)言編寫(xiě)的事件驅(qū)動(dòng)架構(gòu)示例,模擬了一個(gè)基于按鍵輸入的LED控制。
#include事實(shí)上,真正的事件型驅(qū)動(dòng)架構(gòu),是非常復(fù)雜的,我職業(yè)生涯的巔峰之作,就是用的事件型驅(qū)動(dòng)架構(gòu)。// 包含51系列單片機(jī)的寄存器定義 // 定義按鍵和LED的狀態(tài) #define KEY_PORT P3 // 假設(shè)按鍵連接在P3端口 #define LED_PORT P2 // 假設(shè)LED連接在P2端口 // 函數(shù)聲明 void delay(unsigned int milliseconds); bit checkKeyPress(void); // 返回按鍵是否被按下的狀態(tài)(1表示按下,0表示未按下) // 定時(shí)器初始化函數(shù) void timer0Init(void) { TMOD = 0x01; // 設(shè)置定時(shí)器模式寄存器,使用模式1(16位定時(shí)器) TH0 = 0xFC; // 設(shè)置定時(shí)器初值,用于產(chǎn)生定時(shí)中斷 TL0 = 0x18; ET0 = 1; // 開(kāi)啟定時(shí)器0中斷 EA = 1; // 開(kāi)啟總中斷 TR0 = 1; // 啟動(dòng)定時(shí)器 } // 定時(shí)器中斷服務(wù)程序 void timer0_ISR() interrupt 1 { // 定時(shí)器溢出后自動(dòng)重新加載初值,無(wú)需手動(dòng)重置 // 這里可以放置定時(shí)器溢出后需要執(zhí)行的代碼 } // 按鍵中斷服務(wù)程序 bit keyPress_ISR(void) interrupt 2 using 1 { if(KEY_PORT != 0xFF) // 檢測(cè)是否有按鍵按下 { LED_PORT = ~LED_PORT; // 如果有按鍵按下,切換LED狀態(tài) delay(20); // 去抖動(dòng)延時(shí) while(KEY_PORT != 0xFF); // 等待按鍵釋放 return 1; // 返回按鍵已按下 } return 0; // 如果沒(méi)有按鍵按下,返回0 } // 延時(shí)函數(shù),參數(shù)是毫秒數(shù) void delay(unsigned int milliseconds) { unsigned int i, j; for(i = 0; i < milliseconds; i++) for(j = 0; j < 1200; j++); // 空循環(huán),用于產(chǎn)生延時(shí) } // 主函數(shù) void main(void) { timer0Init(); // 初始化定時(shí)器 LED_PORT = 0xFF; // 初始LED熄滅(假設(shè)低電平點(diǎn)亮LED) while(1) { if(checkKeyPress()) { // 檢查是否有按鍵按下事件 // 如果有按鍵按下,這里可以添加額外的處理代碼 } } } // 檢查按鍵是否被按下的函數(shù) bit checkKeyPress(void) { bit keyState = 0; // 模擬按鍵中斷觸發(fā),實(shí)際應(yīng)用中需要連接硬件中斷 if(1) // 假設(shè)按鍵中斷觸發(fā) { keyState = keyPress_ISR(); // 調(diào)用按鍵中斷服務(wù)程序 } return keyState; // 返回按鍵狀態(tài) }
5.狀態(tài)機(jī)架構(gòu) 在單片機(jī)開(kāi)發(fā)中,狀態(tài)機(jī)常用于處理復(fù)雜的邏輯和事件序列,如用戶(hù)界面管理、協(xié)議解析等。 以下是一個(gè)使用C語(yǔ)言編寫(xiě)的有限狀態(tài)機(jī)(FSM)的示例,模擬了一個(gè)簡(jiǎn)單的自動(dòng)售貨機(jī)的狀態(tài)轉(zhuǎn)換。
#include// 包含51系列單片機(jī)的寄存器定義 // 定義自動(dòng)售貨機(jī)的狀態(tài) typedef enum { IDLE, COIN_INSERTED, PRODUCT_SELECTED, DISPENSE, CHANGE_RETURNED } VendingMachineState; // 定義事件 typedef enum { COIN_EVENT, PRODUCT_EVENT, DISPENSE_EVENT, REFUND_EVENT } VendingMachineEvent; // 函數(shù)聲明 void processEvent(VendingMachineEvent event); void dispenseProduct(void); void returnChange(void); // 當(dāng)前狀態(tài) VendingMachineState currentState = IDLE; // 主函數(shù) void main(void) { // 初始化代碼(如果有) // ... while(1) { // 假設(shè)事件由外部觸發(fā),這里使用一個(gè)模擬事件 VendingMachineEvent currentEvent = COIN_EVENT; // 模擬投入硬幣事件 processEvent(currentEvent); // 處理當(dāng)前事件 } } // 處理事件的函數(shù) void processEvent(VendingMachineEvent event) { switch(currentState) { case IDLE: if(event == COIN_EVENT) { // 如果在空閑狀態(tài)且檢測(cè)到硬幣投入事件,則轉(zhuǎn)換到硬幣投入狀態(tài) currentState = COIN_INSERTED; } break; case COIN_INSERTED: if(event == PRODUCT_EVENT) { // 如果在硬幣投入狀態(tài)且用戶(hù)選擇商品,則請(qǐng)求出貨 currentState = PRODUCT_SELECTED; } break; case PRODUCT_SELECTED: if(event == DISPENSE_EVENT) { dispenseProduct(); // 出貨商品 currentState = DISPENSE; } break; case DISPENSE: if(event == REFUND_EVENT) { returnChange(); // 返回找零 currentState = CHANGE_RETURNED; } break; case CHANGE_RETURNED: // 等待下一個(gè)循環(huán),返回到IDLE狀態(tài) currentState = IDLE; break; default: // 如果狀態(tài)非法,重置為IDLE狀態(tài) currentState = IDLE; break; } } // 出貨商品的函數(shù) void dispenseProduct(void) { // 這里添加出貨邏輯,例如激活電機(jī)推出商品 // 假設(shè)P1端口連接了出貨電機(jī) P1 = 0x00; // 激活電機(jī) // ... 出貨邏輯 P1 = 0xFF; // 關(guān)閉電機(jī) } // 返回找零的函數(shù) void returnChange(void) { // 這里添加找零邏輯,例如激活機(jī)械臂放置零錢(qián) // 假設(shè)P2端口連接了找零機(jī)械臂 P2 = 0x00; // 激活機(jī)械臂 // ... 找零邏輯 P2 = 0xFF; // 關(guān)閉機(jī)械臂 }
6.面向?qū)ο蠹軜?gòu) STM32的庫(kù),就是一種面向?qū)ο蟮募軜?gòu)。 不過(guò)在單片機(jī)由于資源限制,OOP并不像在高級(jí)語(yǔ)言中那樣常見(jiàn),但是一些基本概念如封裝和抽象仍然可以被應(yīng)用。
雖然C語(yǔ)言本身并不直接支持面向?qū)ο缶幊?,但可以通過(guò)結(jié)構(gòu)體和函數(shù)指針模擬一些面向?qū)ο蟮奶匦浴? 下面是一個(gè)簡(jiǎn)化的示例,展示如何在C語(yǔ)言中模擬面向?qū)ο蟮木幊田L(fēng)格,以51單片機(jī)為背景,創(chuàng)建一個(gè)簡(jiǎn)單的LED類(lèi)。
#include這段代碼定義了一個(gè)結(jié)構(gòu)體LED,模擬面向?qū)ο笾械摹邦?lèi)。 這個(gè)示例僅用于展示如何在C語(yǔ)言中模擬面向?qū)ο蟮娘L(fēng)格,并沒(méi)有使用真正的面向?qū)ο缶幊陶Z(yǔ)言的特性,如繼承和多態(tài),不過(guò)對(duì)于單片機(jī)的應(yīng)用,足以。 7.基于任務(wù)的架構(gòu) 這種我最喜歡用,結(jié)構(gòu),邏輯清晰,每個(gè)任務(wù)都能靈活調(diào)度。// 定義一個(gè)LED類(lèi) typedef struct { unsigned char state; // LED的狀態(tài) unsigned char pin; // LED連接的引腳 void (*turnOn)(struct LED*); // 點(diǎn)亮LED的方法 void (*turnOff)(struct LED*); // 熄滅LED的方法 } LED; // LED類(lèi)的構(gòu)造函數(shù) void LED_Init(LED* led, unsigned char pin) { led->state = 0; // 默認(rèn)狀態(tài)為熄滅 led->pin = pin; // 設(shè)置LED連接的引腳 } // 點(diǎn)亮LED的方法 void LED_TurnOn(LED* led) { // 根據(jù)引腳狀態(tài)點(diǎn)亮LED if(led->pin < 8) { P0 |= (1 << led->pin); // 假設(shè)P0.0到P0.7連接了8個(gè)LED } else { P1 &= ~(1 << (led->pin - 8)); // 假設(shè)P1.0到P1.7連接了另外8個(gè)LED } led->state = 1; // 更新?tīng)顟B(tài)為點(diǎn)亮 } // 熄滅LED的方法 void LED_TurnOff(LED* led) { // 根據(jù)引腳狀態(tài)熄滅LED if(led->pin < 8) { P0 &= ~(1 << led->pin); // 熄滅P0上的LED } else { P1 |= (1 << (led->pin - 8)); // 熄滅P1上的LED } led->state = 0; // 更新?tīng)顟B(tài)為熄滅 } // 主函數(shù) void main(void) { LED myLed; // 創(chuàng)建一個(gè)LED對(duì)象 LED_Init(&myLed, 3); // 初始化LED對(duì)象,連接在P0.3 // 給LED對(duì)象綁定方法 myLed.turnOn = LED_TurnOn; myLed.turnOff = LED_TurnOff; // 使用面向?qū)ο蟮娘L(fēng)格控制LED while(1) { myLed.turnOn(&myLed); // 點(diǎn)亮LED // 延時(shí) myLed.turnOff(&myLed); // 熄滅LED // 延時(shí) } }
基于任務(wù)的架構(gòu)是將程序分解為獨(dú)立的任務(wù),每個(gè)任務(wù)執(zhí)行特定的工作。
在單片機(jī)開(kāi)發(fā)中,如果沒(méi)有使用實(shí)時(shí)操作系統(tǒng),我們可以通過(guò)編寫(xiě)一個(gè)簡(jiǎn)單的輪詢(xún)調(diào)度器來(lái)模擬基于任務(wù)的架構(gòu)。
以下是一個(gè)使用C語(yǔ)言編寫(xiě)的基于任務(wù)的架構(gòu)的示例,該程序在51單片機(jī)上實(shí)現(xiàn)。
為了簡(jiǎn)化,我們將使用一個(gè)簡(jiǎn)單的輪詢(xún)調(diào)度器來(lái)在兩個(gè)任務(wù)之間切換:一個(gè)是按鍵掃描任務(wù),另一個(gè)是LED閃爍任務(wù)。
#include這里只是舉個(gè)簡(jiǎn)單的例子,這個(gè)代碼示例,比較適合51和stm8這種資源非常少的單片機(jī)。// 假設(shè)P1.0是LED輸出 sbit LED = P1^0; // 全局變量,用于記錄系統(tǒng)Tick unsigned int systemTick = 0; // 任務(wù)函數(shù)聲明 void taskLEDBlink(void); void taskKeyScan(void); // 定時(shí)器0中斷服務(wù)程序,用于產(chǎn)生Tick void timer0_ISR() interrupt 1 using 1 { // 定時(shí)器溢出后自動(dòng)重新加載初值,無(wú)需手動(dòng)重置 systemTick++; // 更新系統(tǒng)Tick計(jì)數(shù)器 } // 任務(wù)調(diào)度器,主函數(shù)中調(diào)用,負(fù)責(zé)任務(wù)輪詢(xún) void taskScheduler(void) { // 檢查系統(tǒng)Tick,決定是否執(zhí)行任務(wù) // 例如,如果我們需要每1000個(gè)Tick執(zhí)行一次LED閃爍任務(wù) if (systemTick % 1000 == 0) { taskLEDBlink(); } // 如果有按鍵任務(wù),可以類(lèi)似地檢查T(mén)ick并執(zhí)行 if (systemTick % 10 == 0) { taskKeyScan(); } } // LED閃爍任務(wù) void taskLEDBlink(void) { static bit ledState = 0; // 用于記錄LED的當(dāng)前狀態(tài) ledState = !ledState; // 切換LED狀態(tài) LED = ledState; // 更新LED硬件狀態(tài) } // 按鍵掃描任務(wù)(示例中省略具體實(shí)現(xiàn)) void taskKeyScan(void) { // 按鍵掃描邏輯 } // 主函數(shù) void main(void) { // 初始化LED狀態(tài) LED = 0; // 定時(shí)器0初始化設(shè)置 TMOD &= 0xF0; // 設(shè)置定時(shí)器模式寄存器,使用模式1(16位定時(shí)器/計(jì)數(shù)器) TH0 = 0x4C; // 設(shè)置定時(shí)器初值,產(chǎn)生定時(shí)中斷(定時(shí)周期取決于系統(tǒng)時(shí)鐘頻率) TL0 = 0x00; ET0 = 1; // 允許定時(shí)器0中斷 EA = 1; // 允許中斷 TR0 = 1; // 啟動(dòng)定時(shí)器0 while(1) { taskScheduler(); // 調(diào)用任務(wù)調(diào)度器 } }
8.代理架構(gòu) 這個(gè)大家或許比較少聽(tīng)到過(guò),但在稍微復(fù)雜的項(xiàng)目中,是非常常用的。
在代理架構(gòu)中,每個(gè)代理(Agent)都是一個(gè)獨(dú)立的實(shí)體,它封裝了特定的決策邏輯和數(shù)據(jù),并與其他代理進(jìn)行交互。
在實(shí)際項(xiàng)目中,需要?jiǎng)?chuàng)建多個(gè)獨(dú)立的任務(wù)或模塊,每個(gè)模塊負(fù)責(zé)特定的功能,并通過(guò)某種機(jī)制(如消息隊(duì)列、事件觸發(fā)等)進(jìn)行通信。
這種方式可以大大提高程序可擴(kuò)展性和可移植性。
以下是一個(gè)LED和按鍵代理的簡(jiǎn)化模型。
#include// 包含51系列單片機(jī)的寄存器定義 // 假設(shè)P3.5是按鍵輸入,P1.0是LED輸出 sbit KEY = P3^5; sbit LED = P1^0; typedef struct { unsigned char pin; // 代理關(guān)聯(lián)的引腳 void (*action)(void); // 代理的行為函數(shù) } Agent; // 按鍵代理的行為函數(shù)聲明 void keyAction(void); // LED代理的行為函數(shù)聲明 void ledAction(void); // 代理數(shù)組,存儲(chǔ)所有代理的行為和關(guān)聯(lián)的引腳 Agent agents[] = { {5, keyAction}, // 按鍵代理,關(guān)聯(lián)P3.5 {0, ledAction} // LED代理,關(guān)聯(lián)P1.0 }; // 按鍵代理的行為函數(shù) void keyAction(void) { if(KEY == 0) // 檢測(cè)按鍵是否被按下 { LED = !LED; // 如果按鍵被按下,切換LED狀態(tài) while(KEY == 0); // 等待按鍵釋放 } } // LED代理的行為函數(shù) void ledAction(void) { static unsigned int toggleCounter = 0; toggleCounter++; if(toggleCounter == 500) // 假設(shè)每500個(gè)時(shí)鐘周期切換一次LED { LED = !LED; // 切換LED狀態(tài) toggleCounter = 0; // 重置計(jì)數(shù)器 } } // 主函數(shù) void main(void) { unsigned char agentIndex; // 主循環(huán) while(1) { for(agentIndex = 0; agentIndex < sizeof(agents) / sizeof(agents[0]); agentIndex++) { // 調(diào)用每個(gè)代理的行為函數(shù) (*agents[agentIndex].action)(); // 注意函數(shù)指針的調(diào)用方式 } } }
9.組件化架構(gòu) 組件化架構(gòu)是一種將軟件系統(tǒng)分解為獨(dú)立、可重用組件的方法。
將程序分割成負(fù)責(zé)特定任務(wù)的模塊,如LED控制、按鍵處理、傳感器讀數(shù)等。
每個(gè)組件可以獨(dú)立開(kāi)發(fā)和測(cè)試,然后被組合在一起形成完整的系統(tǒng)。
以下是一個(gè)簡(jiǎn)化的組件化架構(gòu)示例,模擬了一個(gè)單片機(jī)系統(tǒng)中的LED控制和按鍵輸入處理兩個(gè)組件。
為了簡(jiǎn)化,組件間的通信將通過(guò)直接函數(shù)調(diào)用來(lái)模擬。
#include審核編輯:黃飛// 包含51系列單片機(jī)的寄存器定義 // 定義組件結(jié)構(gòu)體 typedef struct { void (*init)(void); // 組件初始化函數(shù) void (*task)(void); // 組件任務(wù)函數(shù) } Component; // 假設(shè)P3.5是按鍵輸入,P1.0是LED輸出 sbit KEY = P3^5; sbit LED = P1^0; // LED組件 void LED_Init(void) { LED = 0; // 初始化LED狀態(tài)為關(guān)閉 } void LED_Task(void) { static unsigned int toggleCounter = 0; toggleCounter++; if (toggleCounter >= 1000) // 假設(shè)每1000個(gè)時(shí)鐘周期切換一次LED { LED = !LED; // 切換LED狀態(tài) toggleCounter = 0; // 重置計(jì)數(shù)器 } } // 按鍵組件 void KEY_Init(void) { // 按鍵初始化代碼 } void KEY_Task(void) { if (KEY == 0) // 檢測(cè)按鍵是否被按下 { LED = !LED; // 如果按鍵被按下,切換LED狀態(tài) while(KEY == 0); // 等待按鍵釋放 } } // 組件數(shù)組,存儲(chǔ)系統(tǒng)中所有組件的初始化和任務(wù)函數(shù) Component components[] = { {LED_Init, LED_Task}, {KEY_Init, KEY_Task} }; // 系統(tǒng)初始化函數(shù),調(diào)用所有組件的初始化函數(shù) void System_Init(void) { unsigned char componentIndex; for (componentIndex = 0; componentIndex < sizeof(components) / sizeof(components[0]); componentIndex++) { components[componentIndex].init(); } } // 主循環(huán),調(diào)用所有組件的任務(wù)函數(shù) void main(void) { System_Init(); // 系統(tǒng)初始化 while(1) { unsigned char componentIndex; for (componentIndex = 0; componentIndex < sizeof(components) / sizeof(components[0]); componentIndex++) { components[componentIndex].task(); // 調(diào)用組件任務(wù) } } }
-
單片機(jī)
+關(guān)注
關(guān)注
6067文章
44992瀏覽量
650597 -
寄存器
+關(guān)注
關(guān)注
31文章
5434瀏覽量
124545 -
嵌入式系統(tǒng)
+關(guān)注
關(guān)注
41文章
3683瀏覽量
131408 -
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7632瀏覽量
141800
原文標(biāo)題:長(zhǎng)文干貨預(yù)警 | 單片機(jī)常用的9種軟件架構(gòu)!
文章出處:【微信號(hào):nanshuqg,微信公眾號(hào):無(wú)際單片機(jī)編程】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
單片機(jī)開(kāi)發(fā)中常用的三種軟件架構(gòu)
單片機(jī)常用輔助軟件自?。?/a>
概述常用單片機(jī)軟件架構(gòu)
單片機(jī)系統(tǒng)常用軟件抗干擾措施
常用單片機(jī)介紹
單片機(jī)教程九:單片機(jī)數(shù)據(jù)傳遞類(lèi)指令

單片機(jī)學(xué)習(xí)和開(kāi)發(fā)常用的軟件合集免費(fèi)下載

單片機(jī)開(kāi)發(fā)會(huì)用到的常用軟件合集

評(píng)論