电控组学习路线
这份学习路线面向暑假想学习嵌入式相关知识的同学。
嵌入式学习并不是把几个视频看完、把例程复制到开发板上就算完成。真正需要逐步建立的是一套完整的工程能力:
- 会写基础代码
- 会阅读和修改工程
- 会配置单片机外设
- 会看基础原理图
- 会连接和调试硬件
- 会使用仪器定位问题
- 会查阅芯片手册和模块资料
- 会记录、分析和复盘问题
- 会使用 AI 辅助学习和开发
- 会与结构组成员协同完成整车联调
整体学习顺序建议为:
前置工具与环境 → C 语言基础 → 单片机基础 → 常见模块与电机控制 → 工程化开发 → FreeRTOS → 综合项目
本文档与进阶训练的关系
这份文档定位为电控组基础学习路线,目标是让新成员建立完整的嵌入式基础能力,并能够独立完成常见外设、传感器、电机和简单闭环控制。
完成基础训练后,再进入专项进阶训练:
基础学习路线 → 状态机与 PID 进阶训练 → 综合机器人控制项目
其中,《电控组进阶训练:状态机与 PID》不会重复讲 GPIO、PWM、编码器、串口等基础内容,而是默认学习者已经能够独立完成这些模块,并进一步训练:
- 非阻塞程序设计
- 状态机流程组织
- PID 闭环控制
- VOFA+ 波形分析
- 异常检测和保护
- 状态机与 PID 的组合使用
- 工程化代码组织
因此,不建议刚点亮 LED、刚学会 PWM 就直接进入进阶训练。先把本路线中的基础实验真正做完,再学习控制算法会更有效。
这条路线不要求大家一开始就把所有内容全部学会,而是希望大家按照阶段逐步推进。每完成一个阶段,都应该留下能够实际运行的程序、接线和实验结果,而不是只留下看过的视频和收藏的资料。
一、学习前的准备
1. 学习以实践为主
嵌入式是一门实践性很强的方向。很多知识只看视频时感觉已经听懂,但真正接线、编译和烧录时,仍然会遇到各种问题。
建议保持以下学习节奏:
- 先了解知识点的作用。
- 跟着教程完成一次实验。
- 不看教程,自己重新完成一次。
- 修改参数或功能,观察结果变化。
- 将代码整理成自己的模块。
- 记录遇到的问题和解决方法。
例如学习 PWM 时,不要只满足于让 LED 呼吸或舵机转动,还可以继续尝试:
- 修改 PWM 频率
- 修改占空比
- 通过按键调节占空比
- 通过串口发送指令调节占空比
- 使用 VOFA+ 观察数据变化
- 将 PWM 控制代码拆分成独立文件
只有能够自己修改和扩展,才说明真正掌握了这个知识点。
2. 不要一开始就追求复杂项目
刚开始学习时,不建议直接上手平衡车、四轮底盘、机械臂、FOC 或大型机器人项目。
这些项目通常同时涉及:
- 单片机外设
- 电机驱动
- 编码器
- PID
- 通信协议
- 供电
- 机械结构
- 多模块联调
如果基础不扎实,遇到问题时很难判断到底是代码、接线、参数、供电还是机械结构的问题。
更合理的方法是先完成一系列小实验,再逐步组合成完整项目。
3. 建立自己的学习记录
建议每个人建立一个学习仓库或学习文档,记录:
- 学习日期
- 学习内容
- 使用的芯片和模块
- 接线方式
- 实验现象
- 遇到的问题
- 排查过程
- 最终解决方法
- 对应代码版本
代码建议使用 Git 管理。即使暂时不上传 GitHub 或 Gitee,也应该养成提交版本的习惯。
二、前置工具与开发环境
很多初学者最早遇到的问题并不是代码错误,而是驱动、下载器、串口、路径、芯片包和软件配置问题。因此,在正式学习前需要先把基本开发环境搭建好。
1. 开发软件
建议准备:
- Keil MDK
- STM32CubeMX
- STM32CubeIDE
- VSCode
- Git
Keil MDK
Keil 是常见的单片机开发环境,适合刚开始接触 STM32 的同学。
需要学会:
- 新建和打开工程
- 添加源文件和头文件
- 选择芯片型号
- 配置编译选项
- 编译工程
- 查看警告和错误
- 下载程序
- 进入 Debug
- 添加断点
- 单步运行
- 查看变量和寄存器
前期可以先使用 Keil 跟着教程学习,不需要一开始就折腾复杂工具链。
STM32CubeMX
CubeMX 主要用于:
- 选择芯片
- 配置引脚
- 配置系统时钟
- 配置 GPIO
- 配置串口、定时器、ADC、I2C、SPI、CAN 等外设
- 生成初始化代码
需要注意:CubeMX 只是帮助生成初始化代码,不能代替理解外设原理。使用 CubeMX 时,至少要知道自己配置了什么、为什么这样配置。
STM32CubeIDE
CubeIDE 集成了 CubeMX、代码编辑、编译、烧录和调试功能。
可以在熟悉基本开发流程后尝试使用,重点掌握:
- 创建工程
- 图形化配置外设
- 编译和烧录
- 断点调试
- 查看变量
- 查看外设寄存器
VSCode
VSCode 适合后期进行更舒适的代码编辑和工程管理。
前期只需要掌握:
- 安装 C/C++ 插件
- 打开工程文件夹
- 搜索函数和变量
- 全局跳转
- 使用终端
- 使用 Git
- 使用 AI 或 Agent 阅读工程
不建议刚开始就花大量时间配置复杂的 CMake、OpenOCD 和交叉编译环境。先把基础开发流程跑通,再逐步优化工具。
Git
Git 是代码版本管理工具,需要尽早接触。
前期至少掌握:
git initgit addgit commitgit statusgit log- 创建分支
- 切换分支
- 回退到旧版本
建议每完成一个可运行功能就提交一次,例如:
- 完成 LED 闪烁
- 完成串口发送
- 完成按键中断
- 完成电机 PWM 控制
- 完成编码器读取
不要等工程全部写完才保存版本。
2. 驱动和调试软件
需要准备:
- ST-Link / J-Link / DAPLink 驱动
- CH340 / CH341 / CP2102 串口驱动
- VOFA+
- 逻辑分析仪软件
需要能区分以下设备的作用:
- 下载器:用于烧录和调试单片机程序
- USB 转 TTL:用于串口通信
- 逻辑分析仪:用于观察数字通信波形
- 示波器:用于观察模拟信号、PWM 和电源纹波
- 万用表:用于测量电压、电阻、通断和电流
3. VOFA+
VOFA+ 是后续调试中非常实用的工具,需要重点掌握。
建议学会:
- 选择正确串口
- 设置波特率
- 查看串口文本
- 使用曲线显示数据
- 同时显示多组数据
- 观察传感器变化
- 观察 PID 目标值和实际值
- 保存调试数据
- 根据波形判断振荡、超调和响应速度
例如调电机速度环时,可以同时发送:
- 目标速度
- 实际速度
- PID 输出
只看电机转动现象很难准确判断控制效果,结合曲线会更加直观。
4. 常用硬件工具
建议准备:
- 单片机开发板
- 下载器
- USB 转 TTL
- 杜邦线
- 面包板
- 万用表
- 可调电源
- 逻辑分析仪
- 示波器
- LED、电阻、按键
- OLED
- 舵机
- 直流电机
- 编码器电机
- 电机驱动模块
- 常见传感器模块
刚入门不需要一次性买齐全部设备,但开发板、下载器、USB 转 TTL、万用表和基础接线工具最好尽早准备。
三、AI 与 Agent 辅助学习
AI 和 Agent 可以用于辅助学习和排查问题,但不能代替实际调试。
使用时尽量提供:
- 芯片和开发板型号
- 使用的软件和库
- 接线方式
- 关键代码
- 完整报错
- 期望现象
- 实际现象
- 已经尝试的方法
AI 可以帮助:
- 解释代码和报错
- 阅读芯片手册
- 分析工程结构
- 搜索函数调用关系
- 对比两个工程
- 整理排查步骤
- 生成代码框架和注释
Agent 更适合阅读整个工程和处理多文件任务,例如分析某个功能涉及哪些文件。
所有生成内容都必须经过验证:
- 能否正常编译
- 接口和引脚是否正确
- 参数是否符合芯片手册
- 代码逻辑是否能够解释
- 实际上板现象是否正确
不要把未经验证的 AI 代码直接用于比赛或正式项目。
四、C 语言基础
C 语言是嵌入式开发的基础。后面学习 STM32、驱动模块、PID、通信协议和 FreeRTOS,都离不开 C 语言。
1. 推荐资源
推荐:
- 翁恺 C 语言课程
- 菜鸟教程
- C 语言相关教材或课堂资料
翁恺适合系统入门,菜鸟教程适合快速查询语法。
2. 基础语法
需要学习:
- 变量
- 常量
- 数据类型
- 类型转换
- 运算符
- 位运算
ifswitchforwhiledo whilebreakcontinue
嵌入式中尤其要注意:
- 整数位数
- 有符号数和无符号数
- 数据溢出
- 浮点数开销
- 位运算
- 不同类型之间的转换
常见数据类型包括:
uint8_tint8_tuint16_tint16_tuint32_tint32_tfloatdouble
要知道它们能够表示的大致范围,以及为什么嵌入式工程中经常使用固定宽度整数类型。
3. 函数
需要掌握:
- 函数声明
- 函数定义
- 函数参数
- 返回值
- 局部变量
- 全局变量
- 静态变量
- 参数传值
- 参数传地址
- 回调函数基础
需要理解:
- 为什么函数要在头文件中声明
- 为什么有些参数使用指针
- 为什么某些变量需要加
static - 为什么中断回调函数不能随意修改名称
4. 数组和字符串
需要掌握:
- 一维数组
- 二维数组
- 字符数组
- 字符串结束符
- 数组遍历
- 数组作为函数参数
- 常用字符串函数
- 格式化输出
嵌入式中经常需要使用数组保存:
- 串口接收数据
- ADC 采样数据
- 传感器数据
- 滤波窗口
- 电机历史速度
- 通信数据帧
5. 指针
指针是 C 语言和嵌入式中的重点,需要反复练习。
需要掌握:
- 地址
- 指针变量
- 解引用
- 空指针
- 指针和数组
- 指针作为函数参数
- 结构体指针
- 二级指针基础
- 函数指针基础
const与指针- 指针越界
- 野指针
阶段目标不是背概念,而是能看懂类似代码:
void Motor_SetSpeed(Motor_t *motor, int16_t speed);
并能够解释:
motor为什么是指针- 函数为什么可以修改结构体中的数据
int16_t为什么适合表示速度- 调用时应该传入什么
6. 结构体和枚举
需要掌握:
- 结构体定义
- 结构体变量
- 结构体数组
- 结构体指针
- 嵌套结构体
typedef- 枚举
- 联合体基础
结构体非常适合整理模块数据,例如:
typedef struct
{
int16_t target_speed;
int16_t actual_speed;
float kp;
float ki;
float kd;
} Motor_t;
后续可以把一个电机的目标值、实际值和控制参数统一管理,而不是使用大量零散的全局变量。
7. 宏定义和预处理
需要学习:
#define- 条件编译
- 头文件保护
#include- 宏函数
- 编译开关
- 调试宏
需要能够看懂:
#ifndef __MOTOR_H
#define __MOTOR_H
#endif
以及:
#define MOTOR_MAX_OUTPUT 1000
8. .c 和 .h 文件拆分
这是从写小程序走向写工程的重要一步。
需要理解:
.h文件放声明和类型定义.c文件放函数实现- 哪些变量应该设为
static - 哪些函数应该对外公开
- 如何降低模块之间的耦合
- 如何避免重复定义
- 如何避免头文件互相包含
建议练习将以下功能分别拆成模块:
- LED
- 按键
- 蜂鸣器
- 串口
- 舵机
- 电机
- 编码器
- PID
9. C 语言练习任务
建议完成:
- 数组求最大值和平均值
- 字符串命令解析
- 使用结构体保存传感器数据
- 使用指针修改变量
- 编写简单环形缓冲区
- 编写按键状态机
- 编写 PID 数据结构
- 将一个完整程序拆分成多个
.c和.h文件
10. 阶段目标
完成这一阶段后,至少应该做到:
- 能独立编写简单 C 程序
- 能看懂基础单片机代码
- 能使用函数封装功能
- 能使用结构体整理数据
- 能理解常见指针写法
- 能完成
.c和.h文件拆分 - 能根据编译错误定位基本语法问题
五、单片机基础
单片机是电控学习的核心。建议使用 STM32 作为主要学习平台,也可以根据比赛或项目需要接触 MSPM0、ESP32 等其他芯片。
不同芯片的寄存器和库函数可能不同,但 GPIO、串口、定时器、ADC、I2C、SPI、CAN 等基本概念是相通的。
1. 推荐教程
优先推荐:
- KeysKing
- 铁头山羊
如果时间充裕、有耐心,可以继续看:
- 正点原子
- 野火
不同教程的代码风格和开发板可能不同,不建议在刚入门时同时跟多个教程。先选一套教程完成基础内容,再用其他资料补充。
2. 建立第一个工程
需要掌握:
- 选择正确芯片型号
- 新建工程
- 配置调试接口
- 配置系统时钟
- 配置 GPIO
- 生成代码
- 编译工程
- 连接下载器
- 烧录程序
- 进入调试模式
- 查看程序运行状态
第一个阶段应该完成:
- LED 点亮
- LED 闪烁
- 修改闪烁频率
- 使用按键控制 LED
- 使用断点观察变量
3. GPIO
需要学习:
- 输入模式
- 输出模式
- 推挽输出
- 开漏输出
- 上拉输入
- 下拉输入
- 浮空输入
- 引脚速度
- 读取输入电平
- 设置输出电平
- 引脚复用
实践任务:
- LED 点亮和闪烁
- 流水灯
- 按键控制 LED
- 蜂鸣器控制
- 使用宏或函数封装 GPIO 操作
4. 外部中断和 NVIC
需要学习:
- 中断的基本概念
- 轮询与中断的区别
- 上升沿触发
- 下降沿触发
- 双边沿触发
- 中断优先级
- 中断回调函数
- 中断服务函数
- 中断中不能执行过多耗时操作
实践任务:
- 按键外部中断
- 统计按键触发次数
- 使用中断改变 LED 状态
- 使用标志位将中断事件交给主循环处理
5. 系统时钟和时钟树
需要了解:
- 内部时钟
- 外部晶振
- PLL
- 系统时钟
- AHB
- APB
- 外设时钟
- 定时器时钟
- 分频和倍频
不要求一开始就手算所有时钟,但要能够判断:
- 当前系统主频是多少
- 串口时钟来自哪里
- 定时器实际时钟是多少
- 为什么时钟配置错误会导致串口乱码或定时不准
6. USART 串口
需要学习:
- TX 和 RX
- 波特率
- 数据位
- 停止位
- 校验位
- 轮询发送
- 中断接收
- DMA 接收
- 不定长数据接收
- 数据帧
- 环形缓冲区
- 串口重定向
实践任务:
- 单片机向电脑发送字符串
- 发送变量值
- 接收电脑指令控制 LED
- 接收指令控制舵机
- 使用串口发送传感器数据
- 使用 VOFA+ 显示波形
- 编写简单命令解析器
7. 定时器
需要学习:
- 基本定时
- 计数器
- 预分频
- 自动重装值
- 定时器中断
- 输入捕获
- 输出比较
- 编码器模式
- PWM 输出
实践任务:
- 定时器控制 LED 闪烁
- 1 ms 周期任务
- 非阻塞按键扫描
- 测量脉冲宽度
- 读取编码器
- 输出 PWM
8. PWM
需要学习:
- PWM 频率
- 周期
- 占空比
- 定时器通道
- PWM 输出比较
- 频率和分辨率之间的关系
实践任务:
- LED 呼吸灯
- 蜂鸣器发声
- 舵机角度控制
- 直流电机调速
- 通过串口修改占空比
- 使用 VOFA+ 观察目标值和实际值
9. ADC
需要学习:
- ADC 分辨率
- 参考电压
- 采样时间
- 单通道采样
- 多通道扫描
- 连续转换
- DMA 采样
- 电压换算
- 数据滤波
实践任务:
- 读取电位器
- 读取光敏电阻
- 读取电池电压
- 多通道传感器采集
- 使用 DMA 连续采样
- 使用滑动平均滤波
10. DMA
需要理解 DMA 的作用:
- 减少 CPU 搬运数据的工作
- 提高连续采样和通信效率
- 配合 ADC、串口、SPI 等外设使用
需要学习:
- 内存到外设
- 外设到内存
- 普通模式
- 循环模式
- DMA 完成回调
- 缓冲区管理
实践任务:
- ADC + DMA 多通道采样
- 串口 DMA 发送
- 串口 DMA 接收
- 环形缓冲区基础
11. I2C
需要学习:
- SDA
- SCL
- 主机和从机
- 设备地址
- 起始信号
- 停止信号
- 应答
- 寄存器地址
- 上拉电阻
- 软件 I2C 和硬件 I2C
实践任务:
- 驱动 OLED
- 读取 IMU
- 读取温度或气压传感器
- 使用逻辑分析仪查看 I2C 波形
12. SPI
需要学习:
- SCK
- MOSI
- MISO
- CS
- 主机和从机
- 全双工
- 时钟极性
- 时钟相位
- SPI 模式
- 片选控制
实践任务:
- 驱动屏幕
- 读取 SPI 传感器
- 使用逻辑分析仪分析通信数据
- 对比 SPI 和 I2C 的特点
13. CAN
CAN 在机器人和电机控制中非常常见。
需要学习:
- CAN_H 和 CAN_L
- 差分通信
- 终端电阻
- 波特率
- 标准帧
- 扩展帧
- 数据帧
- 过滤器
- 发送邮箱
- 接收 FIFO
- 总线仲裁
- 错误状态
实践任务:
- 两块开发板 CAN 通信
- 发送自定义数据帧
- 接收并解析数据
- 控制 CAN 电机
- 读取电机反馈数据
六、常见模块与执行器
学习外设的目的不是记住 API,而是能够驱动真实模块并完成控制任务。
1. 基础模块
建议接触:
- LED
- 按键
- 蜂鸣器
- OLED / LCD
- 灰度传感器
- 光电开关
- 超声波模块
- 激光测距模块
- 编码器
- IMU
- 温度传感器
- 电流和电压检测模块
学习每个模块时,需要弄清:
- 工作电压
- 接口类型
- 引脚定义
- 输出信号
- 更新频率
- 测量范围
- 精度
- 是否需要电平转换
- 是否需要上拉电阻
- 是否存在供电或电流限制
2. 舵机
需要学习:
- 舵机供电
- PWM 控制方式
- 控制周期
- 脉宽和角度关系
- 角度限位
- 堵转电流
- 单片机地与舵机电源地共地
- 多舵机供电问题
实践任务:
- 控制单个舵机
- 串口设置舵机角度
- 按键控制角度
- 舵机平滑运动
- 多舵机动作序列
3. 直流电机
需要学习:
- 电机驱动模块
- H 桥
- 正反转控制
- PWM 调速
- 电机额定电压
- 启动电流
- 堵转电流
- 反电动势
- 续流保护
- 电源隔离和共地
实践任务:
- 电机正反转
- PWM 调速
- 缓启动
- 急停
- 电机速度闭环
4. 编码器电机
需要学习:
- A 相和 B 相
- 正交编码器
- 方向判断
- 脉冲计数
- 线数
- 倍频
- 减速比
- 速度计算
- 位置计算
- 编码器溢出处理
实践任务:
- 读取编码器计数
- 判断电机方向
- 计算转速
- 使用 VOFA+ 显示速度
- 完成速度 PID
- 完成位置 PID
5. CAN 电机
需要学习:
- 电机通信协议
- CAN ID
- 控制报文
- 反馈报文
- 电流控制
- 速度反馈
- 位置反馈
- 温度和故障信息
- 多电机 ID 管理
使用前必须阅读对应电机的协议手册,不要凭经验猜测报文格式。
七、硬件电路基础
电控成员不能只会写代码,也应该能够看懂基础原理图并排查常见硬件问题。
1. 基础元器件
需要了解:
- 电阻
- 电容
- 电感
- 二极管
- 发光二极管
- 三极管
- MOS 管
- 运算放大器
- 比较器
- 稳压管
- 保险丝
- 接插件
不要求一开始就进行复杂电路计算,但要知道常见器件的基本作用。
2. 常见电路概念
需要学习:
- 欧姆定律
- 串联和并联
- 限流
- 分压
- 上拉
- 下拉
- 滤波
- 去耦
- 旁路
- 共地
- 电平匹配
- 输入保护
- 反接保护
- 过流保护
- 续流二极管
- MOS 管开关
- 电机驱动
- 信号隔离
3. 电源基础
需要了解:
- LDO
- Buck
- Boost
- Buck-Boost
- 输入电压范围
- 输出电压
- 最大电流
- 效率
- 发热
- 纹波
- 压降
- 负载能力
很多系统运行不稳定并不是程序问题,而是供电不足或电源设计不合理。
常见现象包括:
- 电机启动时单片机复位
- 舵机动作时串口断开
- 传感器数据突然异常
- CAN 通信偶发丢包
- 屏幕闪烁
- 系统运行一段时间后重启
遇到这些问题时,需要优先检查电源。
4. 原理图阅读
需要能够识别:
- 单片机最小系统
- 晶振电路
- 复位电路
- 下载接口
- 串口接口
- CAN 收发器
- 电源输入
- 稳压模块
- 电机驱动
- 传感器接口
- 上拉和下拉电阻
- 去耦电容
- 接口保护电路
5. PCB 基础
建议了解:
- 原理图绘制
- 元件封装
- PCB 布局
- PCB 布线
- 电源线宽
- 地线和地平面
- 去耦电容摆放
- 接口位置
- 丝印
- 设计规则检查
- 打样和焊接
可以使用:
- 嘉立创 EDA
- KiCad
- Altium Designer
入门阶段建议先使用嘉立创 EDA,完成一块简单的转接板或最小系统板。
八、调试与仪器使用
会调试比会复制代码更重要。
遇到问题时,不要立刻怀疑所有代码,也不要反复无目的地改参数。应该按照一定顺序排查。
1. 基本排查顺序
推荐顺序:
- 检查供电是否正常。
- 检查模块工作电压。
- 检查是否共地。
- 检查接线和引脚定义。
- 检查下载器是否连接。
- 检查程序是否成功烧录。
- 检查时钟配置。
- 检查外设参数。
- 检查是否进入中断或回调。
- 检查数据格式和通信协议。
- 最后再检查复杂算法。
2. 万用表
需要学会:
- 测量电压
- 测量电阻
- 测量通断
- 测量电流
- 判断短路
- 检查供电
- 检查接口连接
3. 逻辑分析仪
需要学会观察:
- UART
- I2C
- SPI
- PWM
- GPIO
- 编码器脉冲
逻辑分析仪适合判断:
- 单片机是否真的发送了数据
- 波特率是否正确
- I2C 地址是否正确
- SPI 模式是否正确
- PWM 频率和占空比是否正确
4. 示波器
需要学会基本操作:
- 电压档位
- 时间档位
- 触发
- 探头倍率
- 测量频率
- 测量周期
- 测量峰峰值
- 观察 PWM
- 观察电源纹波
- 观察模拟传感器信号
5. 软件调试
需要掌握:
- 串口打印
- 断点
- 单步运行
- 查看变量
- 查看调用栈
- 查看内存
- 查看寄存器
- 使用断言
- 添加错误码
- 使用状态变量
- 使用 LED 指示程序阶段
调试时尽量一次只改变一个变量,这样才能判断问题是如何被解决的。
九、控制算法基础
电机、底盘、舵机和云台都离不开控制算法。
这一章只负责建立控制算法入门概念。在这里不要求一开始就推导复杂公式,也不要求直接写完整的机器人控制系统。首先要把“反馈、误差、周期控制、闭环”这些基本概念真正理解,并完成一个最简单的电机闭环实验。
学习 PID 前,至少应该已经能够:
- 使用 PWM 控制电机正反转和速度
- 正确读取编码器计数
- 根据编码器计算速度
- 使用固定周期定时器或任务运行控制代码
- 使用串口输出目标值和实际值
- 使用 VOFA+ 查看曲线
- 确认电机方向和编码器方向一致
如果上述内容还不能独立完成,应先返回前面的 PWM、编码器、定时器和串口章节继续练习。
1. PID 基础
需要学习:
- 目标值
- 实际值
- 误差
- 比例项 P
- 积分项 I
- 微分项 D
- 控制输出
- 采样周期
- 输出限幅
需要理解:
- P 过小响应慢
- P 过大容易振荡
- I 用于消除静差
- I 过大容易积分饱和
- D 可以抑制快速变化
- D 对噪声比较敏感
2. PID 类型
需要学习:
- 位置式 PID
- 增量式 PID
- 单环 PID
- 串级 PID
- 速度环
- 位置环
- 角度环
3. PID 工程处理
需要掌握:
- 输出限幅
- 积分限幅
- 积分分离
- 死区
- 误差滤波
- 输出斜坡
- 防止电机突然启动
- 堵转检测
- 超时保护
4. 滤波基础
需要学习:
- 限幅滤波
- 中值滤波
- 滑动平均滤波
- 一阶低通滤波
- 互补滤波
- 卡尔曼滤波基本概念
不需要刚开始就深入推导复杂公式,先理解不同滤波方法适合解决什么问题。
5. 实践任务
建议依次完成:
- 电机开环 PWM 控制
- 编码器速度读取
- 电机速度闭环
- 电机位置闭环
- 速度和位置串级控制
- 使用 VOFA+ 观察目标和实际曲线
- 添加输出限幅和堵转保护
6. 基础 PID 阶段验收
进入进阶 PID 训练前,至少应完成以下验收:
- 电机可以稳定开环运行
- 编码器速度方向正确
- 控制周期固定且可以说明周期是多少
- 能够独立写出
target - actual的误差计算 - 能够实现最基础的位置式 PID
- 能够解释 P、I、D 各自的大致作用
- 能够通过 VOFA+ 同时观察目标值、实际值和控制输出
- 能够通过调整 Kp 观察响应速度和振荡变化
- 知道为什么输出需要限幅
- 知道积分过大可能导致什么现象
完成这些内容后,再进入《电控组进阶训练:状态机与 PID》,继续学习积分分离、微分滤波、增量式 PID、串级 PID、系统保护和在线调参。
十、工程化与代码规范
当代码逐渐增多时,工程结构会直接影响开发效率。
1. 模块化
建议按功能拆分文件,例如:
motor.c
motor.h
encoder.c
encoder.h
pid.c
pid.h
imu.c
imu.h
can_motor.c
can_motor.h
chassis.c
chassis.h
每个模块应该尽量做到:
- 对外接口明确
- 内部变量尽量隐藏
- 命名统一
- 参数集中管理
- 减少跨文件全局变量
2. 命名规范
建议统一:
- 函数命名
- 变量命名
- 宏命名
- 结构体命名
- 文件命名
- 枚举命名
例如:
Motor_Init();
Motor_SetSpeed();
Motor_Stop();
Encoder_GetSpeed();
PID_Calculate();
命名应该让别人快速判断函数用途。
3. 注释
注释应该说明:
- 代码为什么这样写
- 参数单位是什么
- 输入和输出是什么
- 是否存在范围限制
- 是否存在硬件依赖
- 是否存在特殊时序
不需要给每一行简单语句写注释,也不要只写“电机函数”“串口函数”这种没有信息量的注释。
4. 参数管理
建议统一管理:
- 引脚
- 定时器
- 串口
- CAN ID
- 电机方向
- PID 参数
- 限幅值
- 机械尺寸
- 编码器分辨率
- 超时阈值
不要把大量数字直接散落在代码中。
5. 状态机
状态机是从“会写功能”走向“会组织完整机器人流程”的重要工具。
刚开始写程序时,很多功能可以直接放在 while(1) 中:
if (key_pressed)
{
Motor_Run();
}
if (sensor_triggered)
{
Motor_Stop();
}
当任务变成“启动 → 前进 → 找到目标 → 停车 → 执行动作 → 返回 → 故障处理”以后,如果继续堆叠大量 if,程序很快就会出现:
- 条件互相影响
- 同一个动作被重复执行
- 不知道当前程序运行到哪一步
- 修改一个流程影响另外一个流程
- 出现故障后难以恢复
- 大量
delay导致其他功能不能及时响应
这时应该开始使用状态机。
例如定义:
typedef enum
{
STATE_IDLE = 0,
STATE_INIT,
STATE_RUN,
STATE_STOP,
STATE_ERROR
} SystemState_t;
主循环只根据当前状态执行对应逻辑:
switch (system_state)
{
case STATE_IDLE:
break;
case STATE_INIT:
break;
case STATE_RUN:
break;
case STATE_STOP:
break;
case STATE_ERROR:
break;
}
基础阶段需要先理解三个核心问题:
- 当前处于什么状态?
- 当前状态应该执行什么?
- 满足什么条件后切换到下一个状态?
建议先完成两个小练习:
练习一:LED 状态机
LED_OFF:LED 熄灭LED_SLOW_BLINK:500 ms 闪烁LED_FAST_BLINK:100 ms 闪烁- 按键切换状态
- 禁止使用长时间阻塞
delay
练习二:电机流程状态机
MOTOR_IDLE:等待启动MOTOR_ACCEL:逐渐提高目标速度MOTOR_RUN:稳定运行MOTOR_STOP:停车MOTOR_ERROR:故障停机
完成基础练习后,需要能够解释:
- 为什么状态应该使用枚举
- 为什么不要在工程各处直接修改状态变量
- 为什么状态切换最好集中管理
- 为什么状态内部应尽量使用非阻塞逻辑
- 状态与“普通 if 判断”有什么区别
基础路线只要求理解并写出简单状态机。更完整的 Enter / Update / Exit、统一状态切换、状态超时、子状态机、故障恢复以及“状态机 + PID”组合设计,放在《电控组进阶训练:状态机与 PID》中继续训练。
6. 错误处理
需要逐步加入:
- 参数检查
- 通信超时
- 传感器离线
- 电机堵转
- 电压异常
- 温度异常
- 紧急停止
- 看门狗
- 错误码
- 故障日志
7. 进入专项进阶训练前的检查
在继续学习 FreeRTOS 或进入状态机/PID专项训练前,建议先完成一次基础能力检查。
应能够独立完成:
- 从零创建并烧录一个单片机工程
- GPIO、外部中断、定时器、PWM、串口基本使用
- 至少一种 I2C 或 SPI 传感器驱动
- 编码器读取和速度计算
- 电机开环控制
- 最基础的速度 PID
- 一个简单非阻塞状态机
.c/.h模块拆分- 使用 Git 保存可运行版本
- 使用 VOFA+ 分析至少三路数据
- 根据现象区分代码、供电、接线和参数问题
如果其中有多项仍然需要完全依赖例程或 AI 才能完成,建议暂时不要急着进入更复杂的控制和 RTOS 内容。
完成后可以进入两条并行路线:
- 控制方向:学习《电控组进阶训练:状态机与 PID》
- 系统方向:继续学习 FreeRTOS,并在后续综合项目中把两者结合起来
十一、FreeRTOS 实时操作系统
当工程功能越来越多时,如果所有代码都堆在 while(1) 中,程序会越来越难维护。
FreeRTOS 可以把不同功能拆分成独立任务,并通过队列、信号量等机制完成任务之间的协作。
1. 学习前提
学习 FreeRTOS 前,建议先掌握:
- C 语言指针
- 结构体
- 函数指针基础
- GPIO
- 中断
- 定时器
- 串口
- CubeMX
- 模块化代码
- 基本调试方法
基础外设还没有掌握时,不建议过早进入 FreeRTOS。
2. 推荐资源
推荐:
- 韦东山 FreeRTOS 教程
- 正点原子 FreeRTOS 教程
- FreeRTOS 官方文档
韦东山适合理解原理,正点原子适合结合 STM32 实践。
3. 任务
需要学习:
- 创建任务
- 删除任务
- 任务优先级
- 任务状态
- 任务切换
- 任务阻塞
- 任务挂起
- 任务恢复
- 相对延时
- 绝对延时
- 调度器
需要理解为什么不能在任务中长期占用 CPU,以及为什么需要使用阻塞和延时。
4. 队列
队列适合在任务之间传递数据。
需要学习:
- 创建队列
- 发送数据
- 接收数据
- 阻塞等待
- 从中断发送数据
- 队列长度
- 数据类型
实践任务:
- 传感器任务采集数据
- 控制任务从队列读取数据
- 显示任务显示最新数据
5. 信号量
需要学习:
- 二值信号量
- 计数信号量
- 中断与任务同步
- 资源数量管理
实践任务:
- 串口接收完成后通知解析任务
- 外部中断触发后通知处理任务
- DMA 完成后通知数据处理任务
6. 互斥量
互斥量用于保护共享资源。
需要学习:
- 共享资源
- 临界区
- 互斥访问
- 优先级继承
- 死锁基本概念
实践任务:
- 多个任务共用串口
- 多个任务访问屏幕
- 多个任务访问同一总线
7. 事件组
事件组适合表示多个状态或条件,例如:
- 传感器初始化完成
- CAN 通信正常
- 电机已使能
- 系统允许启动
- 急停已解除
8. 软件定时器和任务通知
需要学习:
- 软件定时器
- 周期回调
- 单次定时
- 任务通知
- 任务通知值
- 使用任务通知替代简单信号量
9. 内存和栈
需要了解:
- 动态内存
- 静态内存
- Heap
- 任务栈
- 栈溢出
- 剩余栈空间
- 内存碎片
- 内存分配失败
不要盲目给每个任务分配很大的栈,也不要完全忽略栈空间。
10. FreeRTOS 实践项目
建议完成一个包含以下任务的小工程:
- 按键任务
- LED 状态任务
- 传感器采集任务
- 电机控制任务
- 串口通信任务
- 显示任务
- 故障监测任务
任务之间通过队列、信号量或任务通知进行通信。
11. 阶段目标
完成 FreeRTOS 学习后,应该能够:
- 合理划分任务
- 设置任务优先级
- 使用队列传递数据
- 使用信号量处理中断事件
- 使用互斥量保护共享资源
- 排查任务阻塞和栈溢出
- 设计结构清楚的多任务工程
十二、综合实践项目
完成基础学习后,建议通过综合项目把知识串联起来。
项目一:串口控制小系统
功能建议:
- 串口接收命令
- 控制 LED
- 控制蜂鸣器
- 控制舵机
- 返回系统状态
- 使用模块化代码
- 使用 Git 管理版本
项目二:传感器数据采集系统
功能建议:
- 读取多个传感器
- ADC + DMA 采集
- 数据滤波
- OLED 显示
- 串口发送
- VOFA+ 曲线显示
- 异常值检测
项目三:编码器电机闭环控制
功能建议:
- PWM 控制电机
- 编码器读取速度
- 速度 PID
- 位置 PID
- 串口设置目标值
- VOFA+ 显示曲线
- 添加限幅和堵转保护
项目四:简易移动底盘
功能建议:
- 两轮或四轮电机控制
- 编码器反馈
- 速度闭环
- 转向控制
- IMU 读取
- 串口或遥控控制
- 急停
- 电压检测
- 通信超时保护
项目五:FreeRTOS 多任务控制系统
功能建议:
- 电机任务
- 传感器任务
- 通信任务
- 显示任务
- 故障任务
- 队列传递数据
- 信号量同步
- 互斥量保护资源
综合项目不要求功能越多越好,重点是稳定、清晰、可调试。
十三、暑假学习安排建议
可以根据个人进度调整,不要求所有人完全一致。
第一阶段:环境和 C 语言
建议内容:
- 安装开发软件和驱动
- 跑通第一个工程
- 学习 C 语言基础
- 重点练习函数、指针、结构体
- 学习
.c和.h文件拆分 - 学习 Git 基础
阶段成果:
- 一个可以编译运行的 C 语言练习仓库
- 一个可以烧录运行的单片机工程
- 一份学习记录
第二阶段:单片机基础外设
建议内容:
- GPIO
- 外部中断
- 串口
- 定时器
- PWM
- ADC
- DMA
阶段成果:
- 按键控制 LED
- 串口命令控制
- PWM 控制舵机或电机
- ADC 数据通过 VOFA+ 显示
第三阶段:通信和模块
建议内容:
- I2C
- SPI
- CAN
- OLED
- IMU
- 编码器
- 电机驱动
阶段成果:
- 读取一个 I2C 传感器
- 使用 SPI 驱动一个模块
- 两块板进行 CAN 通信
- 完成编码器速度读取
第四阶段:控制和工程化
建议内容:
- PID
- 滤波
- 电机闭环
- 状态机
- 模块化
- 错误处理
- Git 分支和版本管理
阶段成果:
- 一个稳定的电机闭环控制工程
- 一个不依赖阻塞延时的简单状态机
- 使用 VOFA+ 完成参数调试
- 能解释目标值、实际值、误差和控制输出之间的关系
- 完整记录调参过程
完成这一阶段后,即可开始《电控组进阶训练:状态机与 PID》。
第五阶段:FreeRTOS 和综合项目
建议内容:
- 任务
- 队列
- 信号量
- 互斥量
- 任务通知
- 多任务设计
- 综合项目联调
阶段成果:
- 一个多任务控制工程
- 一份项目说明文档
- 一次完整演示
十四、学习过程中常见误区
1. 只看视频,不动手
看懂不等于会做。每学一个外设,都要完成实际实验。
2. 只会复制例程
例程能够运行只是第一步,还要理解引脚、参数、调用关系和数据流。
3. 所有代码都写在 main.c
工程功能增加后必须逐步模块化,否则后续联调会非常困难。
4. 一出问题就怀疑代码
嵌入式问题可能来自:
- 供电
- 接线
- 驱动
- 下载器
- 时钟
- 外设配置
- 通信协议
- 机械结构
- 控制参数
要按照顺序排查,不要只盯着程序。
5. 过早学习复杂内容
基础外设还不熟时,不建议直接学习 FreeRTOS、FOC 或复杂机器人算法。
6. 只追求“能跑”
代码能运行不代表工程质量合格,还需要考虑:
- 稳定性
- 可读性
- 可维护性
- 异常处理
- 安全保护
- 模块化
- 调试接口
7. 不记录问题
同一个问题反复出现,往往是因为没有记录。建议将每次故障的现象、原因和解决方法整理下来。
十五、进阶方向
基础打牢之后,可以根据兴趣选择方向:
1. 电机与控制
- 编码器电机控制
- 串级 PID
- 云台控制
- 平衡车
- FOC 无刷电机控制
- 电机驱动器设计
2. 机器人控制
- 差速底盘
- 麦克纳姆轮底盘
- 全向轮底盘
- 机械臂控制
- 运动学
- 里程计
- 多传感器融合
3. 嵌入式 Linux
- Linux 基础命令
- Shell
- CMake
- GCC
- 串口和网络通信
- 驱动基础
- 多线程
- 进程通信
- 上位机与下位机协同
4. ROS / ROS2
- 节点
- Topic
- Service
- Action
- TF
- 传感器数据
- 底盘控制
- 导航
- SLAM
5. 视觉与边缘计算
- OpenCV
- 摄像头采集
- 颜色和形状识别
- YOLO
- 目标坐标解算
- 单片机与视觉主控通信
- RDK、树莓派或其他 Linux 板卡
6. 硬件设计
- 原理图
- PCB
- 电源设计
- 接口保护
- 电机驱动
- 信号完整性基础
- EMC 基础
7. 上位机开发
- Python
- C#
- Qt
- 串口工具
- 参数调试界面
- 数据绘图
- 日志管理
- 固件升级工具
十六、最终目标
完成这条路线后,希望大家不只是“看过教程”,而是能够真正参与嵌入式相关项目:
- 能看懂工程
- 能修改代码
- 能配置常用外设
- 能调试通信
- 能读取传感器
- 能控制舵机和电机
- 能完成基础闭环控制
- 能看懂基础原理图
- 能使用万用表、逻辑分析仪和示波器
- 能使用 VOFA+ 分析数据
- 能使用 Git 管理代码
- 能使用 AI 和 Agent 辅助开发
- 能记录问题并复盘
- 能参与底层驱动、运动控制、通信,并与结构组协同完成整车联调
嵌入式学习前期会比较杂,代码、硬件、电路、工具和算法都要接触。但只要坚持动手,很多看起来零散的内容会逐渐串联起来。
遇到问题不要怕。能够把问题描述清楚、根据现象提出假设、使用工具逐步排查,并最终记录解决过程,本身就是电控成员非常重要的能力。
十七、团队交流
我们团队目前分为:
- 电控组(覆盖嵌入式软件、主控、PCB、电源、驱动、接口、焊接与调试)
- 结构组
学习过程中遇到问题,可以在群内交流讨论,也可以分享学习记录、工程代码和调试经验。
团队 QQ 群号:1081176436