F FisherHub Docs

嵌入式系统基础

MCU vs MPU

嵌入式系统的核心是处理器,分为两大类:

MCU (Microcontroller Unit) 将处理器、RAM、Flash、外设接口集成在单颗芯片上。适合对成本、功耗、实时性要求高的场景。典型代表:STM32F103C8T6 (Cortex-M3)、ESP32 (Xtensa LX6)。

MPU (Microprocessor Unit) 仅包含处理器核心,需要外部搭配 DDR、Flash、电源管理芯片。运行 Linux 或 Android,适合需要复杂多媒体、网络栈、UI 的应用。典型代表:Raspberry Pi 的 BCM2711、Allwinner V3s。

选择参考:纯传感器采集和简单控制用 MCU;需要摄像头、触摸屏、网络服务器用 MPU。

裸机编程

裸机编程指不依赖操作系统,在一个主循环中轮询或中断响应处理任务。

#include <stdio.h>
#include <stdint.h>

volatile uint32_t ms_counter = 0;

// 定时器中断服务函数(伪代码)
void SysTick_Handler(void) {
    ms_counter++;
}

int main(void) {
    uint32_t last_blink = 0;
    
    // 初始化GPIO
    GPIO_Init(LED_PIN, OUTPUT);
    
    while (1) {
        // 每500ms翻转LED
        if (ms_counter - last_blink >= 500) {
            GPIO_Toggle(LED_PIN);
            last_blink = ms_counter;
        }
        
        // 其他任务轮询
        uint16_t adc_val = ADC_Read(TEMP_SENSOR_CH);
        ProcessTemperature(adc_val);
    }
}

裸机编程的优点是完全可控、资源占用极少,缺点是多任务时需要手动管理状态机。

RTOS 实时操作系统

当任务数量增多时,裸机的轮询方式很快变得难以维护。RTOS 提供任务调度、信号量、消息队列等机制。

常用 RTOS:

  • FreeRTOS — 开源、轻量、生态最广,ESP-IDF 和 STM32Cube 都内置支持
  • RT-Thread — 国产,IoT 友好,支持设备框架和包管理
  • Zephyr — Linux 基金会项目,模块化设计,支持 500+ 开发板

FreeRTOS 示例:

#include <FreeRTOS.h>
#include <task.h>

void vSensorTask(void *pvParameters) {
    TickType_t xLastWakeTime = xTaskGetTickCount();
    
    for (;;) {
        // 每100ms读取传感器
        float temp = read_temperature();
        send_to_display(temp);
        
        vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(100));
    }
}

void vCommsTask(void *pvParameters) {
    for (;;) {
        // 处理网络通信
        if (mqtt_connected()) {
            mqtt_loop();
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

int main(void) {
    hardware_init();
    
    xTaskCreate(vSensorTask, "Sensor", 1024, NULL, 1, NULL);
    xTaskCreate(vCommsTask, "Comms", 2048, NULL, 2, NULL);
    
    vTaskStartScheduler();
    
    // 不会执行到这里
    return 0;
}

设计原则:中断服务函数应尽可能短,只做标志设置或数据入队,具体处理交给任务。

ESP32 入门

ESP32 是乐鑫科技推出的 WiFi + BLE 双模芯片,IoT 原型首选的利器。

# MicroPython on ESP32
from machine import Pin, ADC
import time
import network
import urequests

# 连接WiFi
def connect_wifi():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect("SSID", "PASSWORD")
    while not wlan.isconnected():
        time.sleep(1)
    print("WiFi connected:", wlan.ifconfig())

# 读取模拟传感器
adc = ADC(Pin(34))
adc.atten(ADC.ATTN_11DB)  # 0-3.3V范围

connect_wifi()

while True:
    value = adc.read()
    voltage = value * 3.3 / 4095
    print(f"Sensor: {voltage:.2f}V")
    
    try:
        urequests.get(f"http://example.com/api?val={voltage}")
    except:
        pass
    
    time.sleep(5)

STM32 入门

STM32 以丰富的产品线和成熟的生态著称。使用 STM32CubeIDE 配合 HAL 库可以快速开发。

// STM32使用HAL库读取内部温度传感器
#include "stm32f1xx_hal.h"

ADC_HandleTypeDef hadc1;

void MX_ADC1_Init(void) {
    ADC_ChannelConfTypeDef sConfig = {0};
    __HAL_RCC_ADC1_CLK_ENABLE();
    
    hadc1.Instance = ADC1;
    hadc1.Init.ScanConvMode = DISABLE;
    hadc1.Init.ContinuousConvMode = ENABLE;
    hadc1.Init.DiscontinuousConvMode = DISABLE;
    hadc1.Init.NbrOfConversion = 1;
    HAL_ADC_Init(&hadc1);
    
    sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

调试技巧

  • 串口输出 — 最简单的调试方法,printf 重定向到 UART
  • LED 指示灯 — 不同闪烁模式表示不同系统状态
  • 逻辑分析仪 — 抓取 I2C/SPI 总线波形验证时序
  • JTAG/SWD 调试 — 断点、单步执行、查看变量

小结

裸机编程适合简单任务,RTOS 适合中等复杂度的多任务系统,Linux 适合功能丰富的产品。从 Arduino 或 MicroPython 快速验证原型,再用 ESP-IDF 或 STM32Cube 做量产版本,是一条高效的路径。