第2章:嵌入式基础:STM32微控制器简介、GPIO、定时器、中断、PWM输出原理
各位同学,欢迎来到第二章。说实话,很多初学者一上来就盯着寄存器手册看,结果三天就放弃了。我当年也是这样,差点把书扔出窗外。后来我悟出一个道理:学嵌入式,先别管那些复杂的底层细节,先把几个核心外设玩明白,后面自然就通了。
这一章,我们就来啃下STM32的四大金刚:GPIO、定时器、中断、PWM。你想想看,电机控制里90%的场景,其实就是在跟这四个家伙打交道。
2.1 STM32微控制器简介
STM32是意法半导体推出的32位ARM Cortex-M系列微控制器。为什么电机控制领域它这么火?说白了,就是性价比高、外设丰富、生态成熟。
我个人习惯把STM32分成三个梯队:
- 入门级(F0/F1系列):Cortex-M0/M3内核,主频48-72MHz,适合简单电机控制、传感器采集。我最早做直流有刷电机项目用的就是STM32F103,皮实耐用。
- 主流级(F4系列):Cortex-M4内核,带FPU(浮点运算单元),主频168MHz。做FOC(磁场定向控制)的标配,我现在的项目80%都在用F405。
- 高性能(H7系列):Cortex-M7内核,主频400MHz+,双核架构。伺服驱动器、多轴机器人控制才会用到,一般初学者暂时不用碰。
核心要点:对于电机控制入门,STM32F103或F405是最佳选择。别一上来就追H7,容易把自己劝退。
2.2 GPIO:最基础的数字接口
GPIO(General Purpose Input/Output),通用输入输出口。说白了,就是芯片的「手脚」——可以输出高低电平去控制外部设备,也可以读取外部信号的高低电平。
STM32的GPIO有8种工作模式,但做电机控制你只需要记住这几种:
| 模式 | 用途 | 我的经验 |
|---|---|---|
| 推挽输出 | 驱动LED、继电器、使能信号 | 最常用,输出0或3.3V |
| 开漏输出 | I2C总线、电平转换 | 需要外接上拉电阻 |
| 浮空输入 | 读取按键、霍尔传感器 | 默认电平不确定,建议用上拉/下拉 |
| 复用功能 | PWM输出、串口通信 | 让定时器接管引脚控制 |
嗯,这里要注意:GPIO的驱动能力有限,一般最大20mA。我曾经有个同事直接拿GPIO去驱动一个电磁铁,结果芯片烧了。驱动大负载,必须加三极管或MOS管。
小技巧:初始化GPIO时,养成先使能时钟、再配置模式、最后设置电平的习惯。顺序错了,有时候会莫名其妙出问题。
2.3 定时器:电机的「心跳」
定时器是电机控制的核心。为什么?因为PWM、编码器测速、周期中断,全都依赖它。
STM32的定时器分三类:
- 基本定时器(TIM6/TIM7):只能计时,产生中断。我一般用它做系统心跳,比如每1ms执行一次状态机。
- 通用定时器(TIM2-TIM5):有输入捕获、输出比较、PWM功能。做电机控制的主力,一个定时器可以同时输出多路PWM。
- 高级定时器(TIM1/TIM8):带死区插入、刹车功能。专门为电机驱动设计的,做三相逆变器必备。
定时器的核心原理其实很简单:一个计数器从0开始往上数,数到预设值就归零,同时触发一个事件。这个「数数」的速度由时钟频率决定。
// 定时器配置示例(TIM2,1ms中断)
void TIM2_Init(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // 使能时钟
TIM2->PSC = 72 - 1; // 预分频:72MHz/72 = 1MHz
TIM2->ARR = 1000 - 1; // 自动重装:1MHz/1000 = 1kHz
TIM2->DIER |= TIM_DIER_UIE; // 使能更新中断
TIM2->CR1 |= TIM_CR1_CEN; // 启动定时器
NVIC_EnableIRQ(TIM2_IRQn); // 使能中断
}
你看,就这么几行代码,一个1ms的定时器就搞定了。PSC和ARR这两个寄存器,你记住一个公式就行:输出频率 = 时钟频率 / (PSC+1) / (ARR+1)。
避坑指南:我曾经在调试一个BLDC电机时,发现PWM频率怎么调都不对。查了半天,原来是定时器的时钟源没选对——APB1和APB2的时钟频率不一样!TIM2挂在APB1上,默认是36MHz,而我按72MHz算的。所以,配置前一定先确认定时器挂在哪个总线上。
2.4 中断:让CPU「该干嘛干嘛」
中断,是嵌入式系统的灵魂。没有中断,CPU就得一直轮询,啥事也干不了。
中断的工作流程,我打个比方:你正在看书(主程序),突然手机响了(中断请求),你记下看到哪一页(保存现场),接电话(中断服务函数),挂电话后继续看书(恢复现场)。
STM32的中断系统有几个关键概念:
- 中断优先级:STM32支持抢占优先级和子优先级。高优先级可以打断低优先级的中断。电机控制中,电流环中断优先级最高,速度环次之,通信中断最低。
- 中断向量表:存放所有中断服务函数入口地址的表。复位后CPU会从这里找到第一条指令。
- NVIC(嵌套向量中断控制器):管理所有中断的使能、挂起、优先级。
// 定时器中断服务函数
void TIM2_IRQHandler(void) {
if (TIM2->SR & TIM_SR_UIF) { // 检查更新中断标志
TIM2->SR = ~TIM_SR_UIF; // 清除标志位
// 在这里放你的代码,比如电机状态机更新
Motor_StateMachine();
}
}
你想想看,如果没有中断,CPU就得不停地问:「定时器到时间了吗?到了吗?到了吗?」——这叫轮询,效率极低。有了中断,CPU可以安心做其他事,定时器到了它会主动通知CPU。
核心原则:中断服务函数要短小精悍,不要在里面做延时、打印等耗时操作。我一般只在中断里设置标志位,真正的处理放在主循环里。否则,中断嵌套一多,系统就崩了。
2.5 PWM输出原理:电机调速的核心
PWM(Pulse Width Modulation),脉冲宽度调制。说白了,就是通过调节方波的占空比来控制平均电压。
为什么电机控制要用PWM?因为直接调电压效率低、发热大。而PWM配合MOS管,开关损耗小,效率能做到90%以上。
PWM的三个关键参数:
- 频率:PWM波每秒的周期数。电机控制一般用10kHz-20kHz,低于人耳听觉范围(20kHz)会有啸叫声。我一般用16kHz,安静又高效。
- 占空比:高电平时间占整个周期的比例。0%就是全关,100%就是全开,50%就是一半电压。
- 分辨率:占空比可调节的精细程度。比如ARR=999,分辨率就是0.1%。
用定时器输出PWM,其实就是利用「输出比较」功能:计数器值小于比较值时,输出高电平;大于比较值时,输出低电平。
// PWM输出配置(TIM2,通道1,PA0)
void PWM_Init(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
// 配置PA0为复用功能
GPIOA->MODER |= GPIO_MODER_MODE0_1; // 复用模式
GPIOA->AFR[0] |= 1 << 0; // AF1:TIM2_CH1
// 定时器配置
TIM2->PSC = 72 - 1; // 72MHz/72 = 1MHz
TIM2->ARR = 1000 - 1; // PWM频率 = 1MHz/1000 = 1kHz
TIM2->CCR1 = 500; // 占空比 = 500/1000 = 50%
TIM2->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // PWM模式1
TIM2->CCER |= TIM_CCER_CC1E; // 使能输出
TIM2->CR1 |= TIM_CR1_CEN; // 启动定时器
}
改变占空比很简单,直接修改CCR1的值就行。比如想让电机转快点,就把CCR1设大一点。
我的习惯:做电机控制时,我会把PWM频率固定,只调节占空比。频率一变,电机的电感特性就变了,控制参数也得跟着调,太麻烦。另外,高级定时器的死区时间一定要配好,否则上下桥臂直通,MOS管瞬间冒烟——我亲眼见过,那味道真不好闻。
2.6 本章小结
这一章我们聊了STM32的四大核心外设。GPIO是手脚,定时器是心跳,中断是神经系统,PWM是力量输出。这四个东西组合起来,就能搭建一个最基本的电机控制系统。
下一章,我们会把这些知识串起来,做一个真正的电机转动实验。到时候你会发现,原来让电机转起来,就这么简单。
记住:理论是死的,板子是活的。看完这一章,赶紧去你的开发板上试试。只有亲手配置过寄存器,踩过几个坑,这些东西才能真正变成你的。
课后作业:用STM32输出一个10kHz、占空比30%的PWM波,用示波器或逻辑分析仪验证。试试改变占空比,观察电机转速变化(如果有电机的话)。
公众号:蓝海资料掘金营,微信deep3321