嵌入式系统基础:定义、RTOS与常用MCU平台

各位同学,咱们今天聊聊嵌入式系统的基础。说实话,这个领域我摸爬滚打了十几年,踩过的坑比走过的路还多。但正是这些基础概念,决定了你设计的系统能不能稳定跑上十年八年。

嵌入式系统到底是什么?

嵌入式系统,说白了就是「专门干一件事的计算机」。它不像你桌上的PC,能打游戏、写文档、刷网页。嵌入式系统从出生那天起,任务就定死了——比如分拣机里的控制板,一辈子就负责读传感器、算位置、发脉冲。

我个人习惯把嵌入式系统拆成三块看:

  • 硬件层:MCU、传感器、执行器、通信接口。这是骨架。
  • 软件层:裸机程序或RTOS、驱动、应用逻辑。这是血肉。
  • 中间层:协议栈、算法库、硬件抽象层。这是筋腱。

我在项目中遇到过最典型的误解——有人觉得嵌入式就是「单片机编程」。其实不对。嵌入式系统强调的是「资源受限下的可靠运行」。你想想看,分拣机一天要处理几万个包裹,MCU的RAM可能只有几百KB,Flash也就几MB。在这种条件下,还要保证99.99%的可靠性,这才是真功夫。

核心特征:

  • 专用性:软硬件针对特定任务定制
  • 实时性:必须在规定时间内响应外部事件
  • 可靠性:常年7×24小时运行,不能死机
  • 资源受限:CPU主频低、内存小、存储有限

实时操作系统(RTOS)概念

为什么要用RTOS?嗯,这个问题我当年也纠结过。裸机也能跑分拣机啊,一个超级循环搞定一切。但后来我发现,当系统复杂度上去以后,裸机就是给自己挖坑。

RTOS的核心价值在于——任务调度。它让你把复杂的控制逻辑拆成多个独立任务,每个任务有自己的优先级和周期。RTOS负责决定「现在该跑哪个任务」。

我建议你记住这几个关键概念:

概念 说明 分拣机中的例子
任务(Task) 独立的执行线程,有自己的栈空间 读编码器任务、控制电机任务
信号量(Semaphore) 用于任务间同步或资源互斥 包裹到位信号量,通知电机启动
消息队列(Queue) 任务间传递数据 扫码结果传给分拣决策任务
中断(ISR) 硬件事件触发,优先级最高 编码器脉冲中断,记录位置

我曾经在一个项目中,因为信号量使用不当,导致两个任务互相等待——死锁了。分拣机直接卡住,包裹堆了一地。那次教训让我明白:RTOS不是万能药,用不好反而添乱。

我的经验:新手用RTOS,最容易犯的错误是「任务切得太碎」。比如把读一个传感器就搞成一个任务,结果上下文切换开销比实际干活还多。我建议:任务粒度以「功能模块」为单位,一个模块一个任务就够了。

分拣机常用MCU平台

分拣机控制器的MCU选型,说白了就是平衡「性能」和「成本」。我这些年用过不少平台,但最常用的就两个系列。

STM32系列

STM32,尤其是F4和H7系列,在分拣机领域用得特别多。为什么?

  • 生态成熟:HAL库、CubeMX、各种例程,上手快
  • 外设丰富:多路定时器、PWM、ADC、CAN、以太网
  • 性价比高:几十块钱的芯片,能搞定大部分分拣控制

我记得有个项目,用STM32F407控制一条小型分拣线。主频168MHz,驱动4个步进电机、读取8个光电传感器、还要跑Modbus TCP和上位机通信。嗯,跑得稳稳的。

代码示例——用STM32的定时器产生PWM控制步进电机:

// 初始化定时器TIM2,输出PWM控制步进电机
void Stepper_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    TIM_OC_InitTypeDef sConfigOC = {0};
    
    // 使能时钟
    __HAL_RCC_TIM2_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    // 配置PA0为TIM2_CH1
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // 配置PWM参数
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 84 - 1;      // 84MHz / 84 = 1MHz
    htim2.Init.Period = 1000 - 1;       // 1MHz / 1000 = 1kHz PWM
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    HAL_TIM_PWM_Init(&htim2);
    
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 500;              // 50%占空比
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
    
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
}

NXP i.MX RT系列

当分拣机需要更高性能时——比如要跑视觉算法、要处理高速编码器信号、要支持EtherCAT——i.MX RT就派上用场了。

这个系列的特点:

  • 主频高:最高可达1GHz,Cortex-M7内核
  • 大内存:内部SRAM可达2MB,还支持SDRAM扩展
  • 高速外设:千兆以太网、USB HS、FlexCAN、ENET

我有个朋友做高速交叉带分拣机,用的就是i.MX RT1064。主频600MHz,同时控制32个交叉带小车,每个小车独立控制转向和卸货。这要是用STM32,光中断处理就够呛。

注意:i.MX RT虽然性能强,但功耗和散热也要考虑。我见过有人把i.MX RT当普通单片机用,不加散热片,结果跑着跑着就过热降频了。分拣机是工业环境,夏天车间温度可能到40°C以上,散热设计不能省。

选型建议

说了这么多,到底怎么选?我个人的经验是:

  • 小型分拣线(10个以下分拣口):STM32F4系列,够用,成本低
  • 中型分拣线(10-50个分拣口):STM32H7或i.MX RT1020,性能有富余
  • 大型高速分拣线(50个以上,带视觉):i.MX RT1060以上,必要时上FPGA配合

记住一句话:选MCU不是选最强的,而是选最合适的。我见过有人用i.MX RT只干了一个定时器中断的活,纯属浪费。也见过有人用STM32F1硬扛高速分拣,结果CPU占用率99%,稍微有点干扰就丢脉冲。

好了,这一章的内容就这些。嵌入式系统的基础,说白了就是理解「资源受限」和「实时可靠」这两个核心。下一章咱们聊聊分拣机的软件架构分层设计,那才是真正考验架构能力的地方。