我們學習MCU開發,大部分都是面向過程的開發,但實際項目一般要求我們有面向對象(模塊化)的方式來開發。
剛學習C語言開發的朋友,應該常常聽說面向對象,但實際對于面向對象開發可能還是不太了解。
為了初學者進一步理解,本文結合實際項目(LEDs狀態燈)給大家帶來比較基礎的模塊化設計。
Ⅰ關于C語言的模塊化
對于MCU的開發,大部分人都還是習慣性用的C語言,原因之一在于C語言具有高效的特點。
可以了解一下,許多操作系統的內核使用的編程語言,其實都用到了C語言,這就是C語言的優點,也是C語言這么多年不衰敗的原因。
說回來,對于MCU的開發,除了C語言,當然還可以其它語言,像C++有許多人就用上了。
C++語言本身就是面向對象的開發語言,定義一個類,可以包含許多成員。站在C語言的角度,可以理解成定義一個結構體,里面包含許多數據類型。如下面要說的LEDs數據結構體:
typedef struct { uint8_t Mode; //模式(常滅 常亮 閃爍) uint8_t Status; //當前狀態(滅 亮) uint16_t OffTimes; //滅時間(xLED_COUNT_PERIOD毫秒) uint16_t OnTimes; //亮時間 uint16_t Counter; //計數(計時) void (*OffFun)(void); //滅函數接口 void (*OnFun)(void); //亮函數接口 }LED_TypeDef;
可以看到,結構體里面包含整型變量,函數指針。
補充,指針函數與函數指針的區別:
1、指針函數:本質是一個函數,函數返回類型是某一類型的指針。
格式: 類型標識符 *函數名(參數表)
如:int *f(x,y);
2、函數指針:本質是一個指針,指向函數的指針變量。
格式:類型說明符 (*函數名)(參數)
如:int (*f) (int x);
Ⅱ為什么要模塊化設計
假如一個系統中做的事情非常多,比如:采集兩個增量式編碼器、兩個絕對值編碼器、控制4個電機、控制多個LED狀態燈、通信收發數據,采集溫度、濕度、超聲波雷達等···許多模塊,那么問題來了,這么多模塊,你的軟件該如何設計?
答案就是需要模塊化設計。
模塊化設計,包含底層驅動,中間接口函數,應用程序等。對于MCU級別的開發,為了規范,建議大家從底層設計到應用層設計都按照模塊化的方式來設計。
簡單的來說,模塊化就是源文件、數據結構、變量、函數命名等需要按照模塊的方式來設計。比如LEDs狀態燈:IO口的定義用LED(模塊),文件名用led,變量、函數名抬頭用LED,定義一個LED數據結構(模塊的數據結構)等。
模塊化的設計優點在于:便于源代碼管理、移植、理解等等。(相信有許多自己寫的代碼,放一段時間之后,重新再次閱讀,可能看了半天都不明白源代碼的意思。)
ⅢLEDs實例講述
為方便大家理解,拿一個簡單的LEDs狀態燈的實例來分析。里面使用到了RTOS簡單系統延時(本文不講述關于RTOS的知識)。文末提供例程下載地址。
1.描述
綠、黃、紅三個(可以自己添加許多個)LED狀態燈,可獨自實現常滅、常亮、閃爍三個模式。
閃爍:滅、亮時間可設置(提供函數接口修改)。
在一個線程(任務)里面執行。
3個LED不同亮滅時間效果:
2.數據結構
typedef struct { uint8_t Mode; //模式(常滅 常亮 閃爍) uint8_t Status; //當前狀態(滅 亮) uint16_t OffTimes; //滅時間(xLED_COUNT_PERIOD毫秒) uint16_t OnTimes; //亮時間 uint16_t Counter; //計數(計時) void (*OffFun)(void); //滅函數接口 void (*OnFun)(void); //亮函數接口 }LED_TypeDef;
為了方便理解,只使用一個數據結構(實際大的項目可能有多個包含,類似C++繼承關系)。
3.底層LED函數接口
void LEDGreen_Off(void);
void LEDGreen_On(void);
void LEDYellow_Off(void);
void LEDYellow_On(void);
void LEDRed_Off(void);
void LEDRed_On(void);
主要就是亮滅函數接口,這里提供三組LED(根據需求可添加)。
4.定義局部變量
static LED_TypeDef sLEDG_Structure; //綠燈 static LED_TypeDef sLEDY_Structure; //黃燈 static LED_TypeDef sLEDR_Structure; //紅燈
5.初始化變量
/************************************************函數名稱 : LED_Data_Init功 能 : 數據初始化參 數 : 無返 回 值 : 無作 者 : strongerHuang*************************************************/ static void LED_Data_Init(void){ /* 綠燈 */ sLEDG_Structure.Mode = LED_MODE_FLICKER; //初始化為閃爍 sLEDG_Structure.OffTimes = 50; //滅亮時間 sLEDG_Structure.OnTimes = 50; sLEDG_Structure.Counter = 0; //計數歸零 sLEDG_Structure.OffFun = LEDGreen_Off; //滅函數接口 sLEDG_Structure.OnFun = LEDGreen_On; //亮函數接口 /* 黃燈 */ sLEDY_Structure.Mode = LED_MODE_ON; //初始化為常亮 sLEDY_Structure.OffTimes = 0; //滅亮時間 sLEDY_Structure.OnTimes = 0; sLEDY_Structure.Counter = 0; //計數歸零 sLEDY_Structure.OffFun = LEDYellow_Off; //滅函數接口 sLEDY_Structure.OnFun = LEDYellow_On; //亮函數接口 /* 紅燈 */ sLEDR_Structure.Mode = LED_MODE_ON; //初始化為常亮 sLEDR_Structure.OffTimes = 0; //滅亮時間 sLEDR_Structure.OnTimes = 0; sLEDR_Structure.Counter = 0; //計數歸零 sLEDR_Structure.OffFun = LEDRed_Off; //滅函數接口 sLEDR_Structure.OnFun = LEDRed_On; //亮函數接口 /* 對外調用接口(例子) */ LEDG_Set(LED_MODE_FLICKER, 50, 50); LEDY_Set(LED_MODE_FLICKER, 50, 10); LEDR_Set(LED_MODE_FLICKER, 20, 30);}
這里重要的就是要初始化滅亮函數接口。
6.LEDs任務(線程)
/************************************************函數名稱 : LED_Task_Proc功 能 : 狀態燈任務程序參 數 : pvParameters --- 可選參數返 回 值 : 無作 者 : strongerHuang*************************************************/ static void LED_Task_Proc(void *pvParameters){ static TickType_t xLastWakeTime; xLastWakeTime = xTaskGetTickCount(); for(;;) { //間隔固定計數周期(采樣時間) vTaskDelayUntil(&xLastWakeTime, LED_COUNT_PERIOD); /* 瀏覽LEDs */ LED_Scan(&sLEDG_Structure); LED_Scan(&sLEDY_Structure); LED_Scan(&sLEDR_Structure); }}
流程圖:
7.LED瀏覽(或者說處理)
/************************************************函數名稱 : LED_Scan功 能 : 狀態燈掃描(修改狀態)參 數 : LED_Struct --- 狀態燈數據結構返 回 值 : 無作 者 : strongerHuang*************************************************/ static void LED_Scan(LED_TypeDef *LED_Struct){ /* 1.常滅模式 */ if(LED_MODE_OFF == LED_Struct->Mode) { LED_Struct->Status = LED_STATUS_OFF; //狀態置為"滅" LED_Struct->OffFun(); //滅燈 } /* 2.常亮模式 */ else if(LED_MODE_ON == LED_Struct->Mode) { LED_Struct->Status = LED_STATUS_ON; //狀態置為"亮" LED_Struct->OnFun(); //亮燈 } /* 3.閃爍模式 */ else if(LED_MODE_FLICKER == LED_Struct->Mode) { /* 在滅的狀態 */ if(LED_STATUS_OFF == LED_Struct->Status) { LED_Struct->Counter++; if(LED_Struct->Counter >= LED_Struct->OffTimes) { LED_Struct->Counter = 0; LED_Struct->OnFun(); //亮燈 LED_Struct->Status = LED_STATUS_ON; //狀態置為"亮" } } /* 在亮的狀態 */ else if(LED_STATUS_ON == LED_Struct->Status) { LED_Struct->Counter++; if(LED_Struct->Counter >= LED_Struct->OnTimes) { LED_Struct->Counter = 0; LED_Struct->OffFun(); //滅燈 LED_Struct->Status = LED_STATUS_OFF; //狀態置為"滅" } } else { LED_Struct->Status = LED_STATUS_OFF; //狀態置為"滅" } } /* 4.未知模式 */ else { LED_Struct->Status = LED_STATUS_OFF; //狀態置為"滅" LED_Struct->OffFun(); //滅燈 }}
源代碼工程下載地址:
鏈接:https://pan.baidu.com/s/1cNtwJDdCOfyYwsvKCclFyw
密碼:kk74
-
mcu
+關注
關注
146文章
17162瀏覽量
351313 -
LEDs
+關注
關注
1文章
39瀏覽量
25537 -
RTOS
+關注
關注
22文章
814瀏覽量
119668 -
線程
+關注
關注
0文章
505瀏覽量
19693
發布評論請先 登錄
相關推薦
評論