嵌入式系統開發可以分為?裸機(Bare Metal)?和?RTOS(實時操作系統)?兩種方式。
裸機開發意味著?沒有 RTOS,程序直接運行在 MCU 上,所有任務調度?完全由開發者手動管理。裸機開發適用于?簡單任務,低功耗系統,小型嵌入式設備,但當任務復雜到一定程度,就需要 RTOS 來管理。

裸機編程是?不依賴 RTOS,直接操作 MCU 硬件?的開發方式,通常采用:??主循環(Super Loop)
??中斷驅動(Interrupt Driven)
??狀態機(State Machine)
int?main() {? ? hardware_init(); ?//?硬件初始化(GPIO、UART、I2C、SPI)? ??while?(1) { ?//?主循環? ? ? ? task1(); ?//?處理傳感器數據? ? ? ? task2(); ?//?處理按鍵輸入? ? ? ? task3(); ?//?處理顯示屏刷新? ? }}
這個編程起來就非常的簡單,如程序所示。
說說裸機的問題->
任務管理困難:多個任務需要手動安排執行順序 .因為是從頭運行到尾部,一些子任務復雜,就要占用大量的CPU時間,下面的任務就執行不了。
實時性差:任務執行時間不可預測,容易卡死。這條就是1的后半段,后面的一些任務就餓死了。
同步與通信難:多個任務共享資源時,容易發生數據競爭。裸機之間的信息傳輸是需要global變量,這就有很多意想不到的問題,比如數據競爭什么的。
代碼難以維護:任務邏輯復雜后,裸機程序難以維護。這個我覺得不是裸機的問題,純粹就是寫多了,都復雜。

這里總結了一些場景和用途
??簡單的單任務/少任務嵌入式系統 → 適合裸機
??復雜的多任務、實時性要求高的系統 → 需要 RTOS
void?main() {? ??hardware_init(); ?// 硬件初始化? ? while (1) {? ? ? ? led_task();? ? ? ? button_task();? ? ? ? uart_task();? ? }}
這種代碼最喜歡??
void?USART_IRQHandler()?{ ?? ??char?data = USART_ReceiveData(); ?? ? process_data(data); ?}
??減少 CPU 負擔,數據來了才處理
??任務間通信難,如果多個中斷搶占,容易丟失數據,因為中斷來的 時候,當前的數據是放在棧里面。
void?TIM2_IRQHandler()?{? ??if?(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {? ? ? ? sensor_read_task();? ? ? ? display_update_task();? ? ? ? TIM_ClearITPendingBit(TIM2, TIM_IT_Update);? ? }}
??定期任務調度,提高實時性
??任務增多時,定時器調度難以管理。也就是說定時器的時間戳給每個子任務使用。
typedef?enum?{ IDLE, PROCESSING, ERROR } SystemState;SystemState current_state = IDLE;void?main()?{? ??while?(1) {? ? ? ??switch?(current_state) {? ? ? ? ? ??case?IDLE: ?? ? ? ? ? ? ? ??if?(button_pressed()) current_state = PROCESSING;? ? ? ? ? ? ? ??break;? ? ? ? ? ??case?PROCESSING: ?? ? ? ? ? ? ? ? process_task();? ? ? ? ? ? ? ? current_state = IDLE;? ? ? ? ? ? ? ??break;? ? ? ? ? ??case?ERROR:? ? ? ? ? ? ? ? error_handle();? ? ? ? ? ? ? ??break;? ? ? ? }? ? }}
??適用于復雜邏輯(如工控、狀態機管理)
??狀態增多時,代碼可讀性下降
void?Task1(void?*argument)?{? ??while?(1) {? ? ? ??printf("任務 1 運行\n");? ? ? ??vTaskDelay(1000);? ? }}void?Task2(void?*argument)?{? ??while?(1) {? ? ? ??printf("任務 2 運行\n");? ? ? ??vTaskDelay(2000);? ? }}void?main()?{? ??xTaskCreate(Task1,?"Task1",?512,?NULL,?1,?NULL);? ??xTaskCreate(Task2,?"Task2",?512,?NULL,?2,?NULL);? ??vTaskStartScheduler();}
然后我們就可以寫這種任務
RTC外設有什么用??昨天不是寫了一個RTC嗎?我一直對定時器情有獨鐘,那我們就分析一下設計一個時鐘怎么做?
鬧鐘應用通常需要 精準的時間管理、低功耗運行、定時喚醒,最佳選擇是 MCU 內部的 RTC(Real-Time Clock)外設。

如果是設計一個引爆器,就是裸機了,感覺港劇里面的起爆器太low了,剪線?笑死,我把所有的傳感器都加上,復雜的判斷條件,精通的定時,誰都別想活。
初始化 RTC
設置 RTC 鬧鐘
進入低功耗模式
RTC 到時間觸發中斷,喚醒 MCU
播放蜂鳴器 / LED 提示
等待用戶停止鬧鐘
流程大概就是這樣吧?
#include?"stm32f4xx.h"void?RTC_Alarm_IRQHandler(void) {? ??if?(RTC->ISR?&?RTC_ISR_ALRAF) {? ? ? ??RTC->ISR?&= ~RTC_ISR_ALRAF;?// 清除鬧鐘標志位? ? ? ? printf("鬧鐘響了!\n");? ? ? ? buzzer_on(); ?// 打開蜂鳴器? ? }}void RTC_SetAlarm(uint8_t hour, uint8_t min, uint8_t sec) {? ? RTC->ALRMAR = (hour << 16) | (min << 8) | sec; ?// 設置鬧鐘時間? ? RTC->CR |= RTC_CR_ALRAIE; ?// 使能鬧鐘中斷}void main() {? ? RTC_Init(); ?// 初始化 RTC? ? RTC_SetAlarm(7, 30, 0); ?// 設置鬧鐘 7:30:00? ? enter_low_power_mode(); ?// 進入低功耗模式}
??鬧鐘觸發后 MCU 喚醒,執行?buzzer_on()?響鈴
??只能管理一個鬧鐘,多個鬧鐘需要手動寫代碼管理
我們來看看RTOS,
創建 RTC 任務
任務循環監聽 RTC 時間
管理多個鬧鐘列表
RTC 觸發鬧鐘,發送任務通知
任務處理響鈴邏輯
支持低功耗模式
#include?"task.h"#include?"queue.h"TaskHandle_t AlarmTaskHandle;typedef struct {? ? uint8_t hour;? ? uint8_t min;? ? uint8_t sec;} AlarmTime_t;QueueHandle_t xAlarmQueue; ?// 鬧鐘隊列void RTC_Alarm_IRQHandler(void) {? ? BaseType_t xHigherPriorityTaskWoken = pdFALSE;? ? xTaskNotifyFromISR(AlarmTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken);? ? portYIELD_FROM_ISR(xHigherPriorityTaskWoken);}void AlarmTask(void *pvParameters) {? ? AlarmTime_t alarm;? ? while (1) {? ? ? ? if (xQueueReceive(xAlarmQueue, &alarm, portMAX_DELAY)) {? ? ? ? ? ? printf("鬧鐘響了!時間:%02d:%02d:%02d\n", alarm.hour, alarm.min, alarm.sec);? ? ? ? ? ? buzzer_on();? ? ? ? }? ? }}void main() {? ? xAlarmQueue = xQueueCreate(5, sizeof(AlarmTime_t)); ?// 創建鬧鐘隊列? ? xTaskCreate(AlarmTask, "AlarmTask", 512, NULL, 1, &AlarmTaskHandle);? ? vTaskStartScheduler();}
??支持多個鬧鐘,鬧鐘時間可以存入隊列
??任務管理,優先級可控,實時性高
??可以在?buzzer_on()?之后,延遲一定時間自動關閉蜂鳴器

總結一下