在《直流有刷电机及机械特性》我们对直流有刷电机的工作原理、机械特性以及电动机的启动、制动、调速进行了详细的介绍。本节主要介绍电机的驱动器以及调速控制方案的实现。
一、电机介绍
由于我们需要学习直流有刷电机的控制,所以我们手里必须要有一款直流有刷电机。
这里我在淘宝购买的电机为:常规775
高速电机吹风机马达电动机双滚珠轴承高转速调速 12V~24V
。
具体型号信息:电压为24V
,转速一分钟20000
转,双出轴。
1.1 产品参数
直流有刷电机电机参数如下:
品牌 | Vantel | 型号 | VT-775 |
---|---|---|---|
品名 | 直流高速电机 | 工作电压 | 12/24V |
转速 | 6000 ~ 20000转 | 功率 | 30W |
电流 | 0.5A | 连续旋转寿命 | 1000小时 |
电机尺寸 | 44*66mm | 出轴尺寸 | \(\phi\) 5*17.5mm |
调速方式 | PWM/无极调速 | 最大转矩 | 0.6kgf.cm |
1.1.1 图纸

1.1.2 实物尺寸图

1.1.3 3D
建模图

1.2 性能参数
转速 | 工作电压 | 功率 | 转矩 | 空载电流 |
---|---|---|---|---|
6000R | 12V | 30W | 0.6kfg.cm | 0.4A |
10000R | 12V | 30W | 0.6kfg.cm | 0.4A |
12000R | 24V | 30W | 0.6kfg.cm | 0.5A |
20000R | 24V | 30W | 0.6kfg.cm | 0.5A |
由于我们选择的具体型号为电压为24V
,转速一分钟20000
转,双出轴。所以我们参考最后一行性能数据。
1.2.1 常规单位换算
这里我们看到的转矩单位为0.6kfg.cm
,这个和我们经常见到的N.m
如何进行换算呢?
gf.cm | kgf.cm | N.m | mN.m | N.cm |
---|---|---|---|---|
1.0 | 0.001 | 0.000098 | 0.098 | 0.0098 |
1000 | 1.0 | 0.098 | 98 | 9.8 |
10,204.08 | 10.204 | 1.0 | 1000 | 100 |
10.20 | 0.010 | 0.001 | 1.0 | 0.1 |
102.04 | 0.102 | 0.01 | 10 | 1.0 |
1.2.2 选型标准
通常点击参数表扭矩代表的是什么意思?
电机标准转矩为\(10kg.cm\),假设使用皮带轮传动,皮带轮的半径为\(1cm\)。皮带输出的拉力就是\(10kg\)。
如果皮带轮的半径为\(2cm\)。皮带输出的拉力就是\(5kg\)。
1.2.3 扭矩概念
扭矩 = 垂直于力臂的拉力 x 力劈。
例如:滚筒起吊,左图滚筒半径 = 力臂 = \(10cm\),起重量 = \(5kg\),需要扭矩 = \(5kg \times 10cm = 50 kg.cm\)。
右图滚筒半径 = 力臂 = \(5cm\),起重量 = \(5kg\),需要扭矩 = \(5kg \times 5cm = 25 kg.cm\)。
从该例子看出力臂很重要,同样重量起吊扭矩完全不一样,不同用法要看实际计算。

1.2.4 调速范围
正常且合理的调速范围应为\(50\% \sim 100\%\)。调速器越往下调速,速度就越慢,力道就越大。
二、驱动器设计
2.1 为什么要用驱动
MCU
的IO
口的电流输出能力一般在20mA
左右,那么输出功率\(P=UI=3.3V*20mA=66mW\)。
而我们所使用的VT-775
直流电机的额定功率为\(20W\),很显然,\(66mW\)的驱动能力驱动能力是无法推动\(30W\)的负载的。
所以MCU
的IO
口输出的PWM
信号,必须经过功率放大才能驱动电机,直流电机通常采用H
桥进行驱动。
2.2 H
桥工作原理
下面以MOS
管搭建的H
桥电路解释电机正反转控制。要使电机运转,必须使对角线上的一对MOS
管导通。如下图;

当Q1
管和Q4
管导通时(此时必须保证Q2
和Q3
关断),电流就从电源正极经Q1
从左至右流过电机,然后再经Q4
回到电源负极。按图中电流箭头所示,该流向的电流将驱动电机顺时针转动。
另一对MOS
管Q2
和Q3
导通的时候(此时必须保证Q1
和Q4
关断),电流从右至左流过电机,从而驱动电机沿逆时针方向转动。
驱动电机时,保证H
桥两个同侧的MOS
管不会同时导通非常重要,如果MOS
管Q1
和Q2
同时导通,那么电流就会从电源正极穿过两个MOS
管直接回到负极,此时电路中除了MOS
管外没有其它任何负载,因此电路上的电流就达到最大值,烧坏MOS
管和电源。Q3
和Q4
同时导通是同样的道理。
简单的开关只能控制电机正反转,引入PWM
控制可以实现方向和速度调节。调节占空比实现控速,占空比越大平均电压(电流)越大,速度越快PWM
频率一般在10KHz~20KHz
之间。频率太低会导致电机转速过低,噪声较大。频率太高,会因为MOS
管的开关损耗而降低系统的效率。
根据不同桥臂的PWM
控制方式不同,大致上可以分为三种控制模式:受限单极模式、单极模式、双极模式。
2.2.1 受限单极模式
1)工作原理
控制方式:在一个PWM
周期内,只有一个桥臂进行PWM
调制,另一个桥臂保持固定状态(常开或常闭)。
电流路径:电流在电机中单向流动,通过PWM
调制控制电机的平均电压。
2)优点
效率高:由于只有一个桥臂进行PWM
调制,开关损耗较小。
控制简单:实现相对简单,适用于单向控制。
3)缺点
无法反转:只能实现单向控制,无法实现电机的正反转。
应用受限:适用于不需要反转的应用场景。
2.2.2 单级模式

1)工作原理
控制方式:在一个PWM周
期内,两个桥臂中的一个进行PWM
调制,另一个桥臂保持固定状态(常开或常闭)。
电流路径:电流在电机中双向流动,通过PWM
调制控制电机的平均电压和方向。
2)优点
可反转:可以实现电机的正反转。
效率较高:开关损耗相对较小。
3)缺点
控制复杂:相比受限单极模式,控制逻辑稍复杂。
应用场景:适用于需要正反转但不需要频繁切换的应用。
2.2.3 双级模式

1)工作原理
控制方式:在一个PWM
周期内,两个桥臂都进行PWM
调制,且调制信号互补。
电流路径:电流在电机中双向流动,通过PWM
调制控制电机的平均电压和方向。
2)优点
快速响应:可以实现快速的电机正反转和速度调节。
精确控制:适用于需要高精度控制的应用场景。
3)缺点
效率较低:由于两个桥臂都进行PWM
调制,开关损耗较大。
控制复杂:控制逻辑复杂,需要精确的PWM
信号生成。
2.3 L298N
芯片
通常在驱动电机的时候我们会选择集成H
桥的IC
,因为H
桥使用分立元件搭建比较麻烦,增加了硬件设计难度。
当然如果集成IC
无法满足我们的功率要求时,还是需要我们自己使用MOS
管、三极管等元件来搭建H
桥电路, 这样的分立元件搭建的H
桥一般驱动能力都会比集成IC
要高。
当我们在选择集成IC
时, 我们需要考虑集成IC
是否能满足电机的驱动电压要求,是否能承受电机工作时的电流等情况。
市面上已经有很多比较常用的IC
方案,比如常用的L293D
、L298N
、TA7257P
、SN754410
等。接上电源、电机,通过输入控制信号就可以驱动电机了。
L298N
驱动板使用了优质的L298N
作为驱动芯片。具有驱动能力强发热量低,抗干扰能力强的特点。
2.3.1 基本介绍
L298N
芯片是ST
公司的一款电机驱动芯片,可以驱动一台两相步进电机或四相步进电机,也可以驱动两台直流电机。L298N
芯片主要特点是:
- 工作电压高,工作电压最高可达\(46V\);
- 输出电流大,瞬间峰值电流可达\(3A\),持续工作电流为\(2A\);
- 额定功率\(25W\);
- 内含两个
H
桥的高电压大电流全桥式驱动器,可以用来驱动直流电动机和步进电动机,继电器线圈等感性负载; - 采用标准逻辑电平信号控制具有两个使能控制端,在不受输入信号影响的情况下允许或禁止器件;
- 接收标准的
TTL
逻辑电平信号; - 可以外接检测电阻,将变化量反馈给控制电路。
2.3.2 功能框图
L298N
芯片内部结构如下图所示:

L298N
驱动芯片,它内部用两个H
桥电路。我们分别称之为A
和B
;
A
电路分别有3
个控制端口:分别是ENA
、IN1
、IN2
;B
电路分别有3
个控制端口:分别是ENA
,IN3
,IN4
。
15
脚封装;
脚名称 | 引脚标号 | I/O | 功能 | 引脚名称 | 引脚标号 | I/O | 功能 |
---|---|---|---|---|---|---|---|
Sense A | 1 | O | H桥A的电流控制,可通过一个电阻接地限制电流(不限电流时直接接地) | Vss | 9 | – | 给内部逻辑电路供电,一般接5V |
OUT 1 | 2 | O | H桥A的输出1脚 | IN 3 | 10 | I | H桥B的逻辑输入1 |
OUT 2 | 3 | O | H桥A的输出2脚 | EN B | 11 | I | H桥B的使能控制端,高电平打开,低电平关闭 |
Vs | 4 | – | 电机驱动电压3~48V,需要一个100nF的滤波电容接地 | IN 4 | 12 | I | H桥B的逻辑输入2 |
IN 1 | 5 | I | H桥A的逻辑输入1 | OUT 3 | 13 | O | H桥B的输出1脚 |
EN A | 6 | I | H桥A的使能控制端,高电平打开,低电平关闭 | OUT 4 | 14 | O | H桥B的输出2脚 |
IN 2 | 7 | I | H桥A的逻辑输入2 | Sense B | 15 | O | H桥B的电流控制,可通过一个电阻接地限制电流(不限电流时直接接地) |
GND | 8 | – | 接地 |
2.3.3 逻辑控制
以H
桥A
为例,L298N
逻辑功能表;
IN1 | IN2 | ENA | 电机状态 |
---|---|---|---|
× | × | 0 | 电机停止 |
1 | 0 | 1 | 电机正转 |
0 | 1 | 1 | 电机反转 |
0 | 0 | 1 | 电机停止 |
1 | 1 | 1 | 电机停止 |
当IN1
和IN2
全0
时,Q1
和Q3
截止,电流关断,电路停止工作。
当IN1
和IN2
全1
时,Q2
和Q4
截止,电流关断,电路也停止工作。
当IN1=0
,IN2=1
时,Q2
和Q3
导通,Q1
和Q4
截止,电流从OUT2
端流入电机,从OUT1
端流出电机。
当IN1=1
,IN2=0
时,Q2
和Q3
截止,Q1
和Q4
导通,电流从OUT1
端流入电机,从OUT2
端流出电机。
2.4 L298N
驱动板
驱动板如下:

2.4.1 产品参数
产品参数:
- 驱动芯片:
L298N
双H
桥直流电机驱动芯片; - 驱动电压
Vs
:+5V~+35V
; 如需要板内取电,则供电范围Vs
:+5V~+12V
; - 驱动电流
Io
:2A
(MAX
单桥); - 逻辑电压Vss
:
+5V~+7V`; - 逻辑电流:
0~36mA
; - 控制信号输入电压范围:
- 低电平:
-0.3V ≤ Vin ≤ 1.5V
; - 高电平:
2.3V ≤ Vin ≤ Vss
;
- 低电平:
- 使能信号输入电压范围:
- 低电平:
-0.3V ≤ Vin ≤ 1.5V
(控制信号无效); - 高电平:
2.3V ≤ Vin ≤ Vss
(控制信号有效);
- 低电平:
- 最大功耗:
25W
; - 存储温度:
-20℃ ~ +135℃
。
在实际测试的时候发现,H
桥输出如果是空载时,输出电压等于\(Vs\);但是如果H
桥连接了直流电机,输出电压会有2V
的压降。
2.4.2 电路原理图

这个模块还有一个板载\(5V\)稳压器78M05
(图中并没有画出,主要是我们找到驱动板的原理与图),该稳压器可使用跳线帽的方式进行使能。
在L298N
芯片电路中,外接多个二极管(通常是续流二极管或飞轮二极管)的主要目的是为了保护电路和芯片,防止电机在开关过程中产生的反向电动势)对电路造成损坏。以下是详细原因和作用:
1)电枢电动势的产生
- 在《直流有刷电机及机械特性》我们介绍了直流电动机电枢电动势\(E_a = C_e\phi n\)(描述的是电机在稳态运行时的电枢电动势);
- 当电机突然停止或状态突变时,电机的动态特性(如电感)会起主导作用,电枢电动势公式不再完全适用;
- 电机的电枢绕组具有电感 \(L\),电感会存储能量,其大小为 \(\frac{1}{2}LI^2\);
- 电机的机械能会转化为电能,电枢绕组中的电流会迅速减小;
- 根据楞次定律,电感会试图维持电流不变,从而产生一个反向电动势;
- 这个反向电动势(\(U_L=-L\frac{dI}{dt}\))的大小取决于电流变化率\(\frac{dI}{dt}\),可能会远高于电源电压。
2)续流二极管的主要作用是提供一个低阻抗路径,让电枢电动势产生的电流能够安全释放,从而保护电路和芯片;
- 当反向电动势产生时,续流二极管导通,将电流引导回电源,避免高压作用于电路元件。
3)如果没有续流二极管或其他保护电路,反向电动势会通过电路中的其他元件释放,可能导致击穿L298N
芯片内部的晶体管或MOSFET
。
2.4.3 驱动电压\(7V \sim 12V\)
当驱动电压为\(7V \sim 12V\)时,我们可以启用板载的78M05
供给L298N
芯片的逻辑电源,指示灯亮,可以不用再外接逻辑电源。

当使用板载\(5V\)供电后,接口中的\(+5V\)供电端子不要输入电压,但是可以引出\(5V\)电压供外部使用。
2.4.4 驱动电压\(12V \sim 24V\)
如果驱动电压大于\(12V\),小于等于\(24V\)(芯片手册中提出可以支持到\(35V\),但是按照经验一般L298N
保守应用最大电压支持到\(24V\)已经很了不起),则必须断开跳线,因为该电压会损坏板载稳压器78M05
。
断开跳线后,指示灯熄灭,不使用板载的78M05
供给L298N
芯片的逻辑电源,然后再\(5V\)输出端口外接输入\(5V\)电压对L298N
芯片内部逻辑电路供电。

2.4.5 补充
LN298N
使能端,高电平有效,常态下用跳线帽连接到\(5V\)电平。
注意事项:L298N
逻辑供电电压\(Vss\)如果是用另外电源供电的话(即不是和MCU
的电源共用),那么需要将MCU
的GND
和模块上的GND
连接在一起,只有这样MCU
上过来的逻辑信号才有个参考0
点。
三、电机调速控制
在《直流有刷电机及机械特性》我们介绍了直流电机的调速方式主要包括:
- 电枢串电阻调速:属于有级调速,效率低,用于各种对调速性能要求不高的设备上;
- 降压调速:可达到无级调速、低速时电损耗小,效率高;是一种性能优越的调速方法,广泛应用于对调速性能要求较高的设备上;
- 弱磁调速:可达到无级调速、功率损耗小,调速范围较小。
在实际生产中,通常把降压调速和弱磁调速配合起来使用,以电动机的额定转速作为基准,在基速以下调压,在基速以上调磁,以实现双向调速,扩大调节范围。
由于这里我是用的电机定子励磁采用永磁体,因此无法进行弱磁调速,因此本节主要介绍降压调速方式。
只要MCU
输出占空比可调的方波,即PWM
信号即可控制电机两端的电压发生变化,从而实现电机转速的控制。
3.1 PWM
信号调速的原理
脉冲宽度调制(Pulse width modulation
,PWM
):这种控制方式是指开关管调制信号的周期固定不变,而开关管导通信号的宽度可调。
其具有两个很重要的参数:频率和占空比;
- 频率,就是周期的倒数;
- 占空比,就是高电平在一个周期内所占的比例。
PWM
方波的示意图如下图所示:

在上图中,频率\(f\)的值为\(\frac{1}{T_1 + T_2}\),占空比\(D\)的值为\(\frac{T_1}{T_1+T_2}\)。
通过改变单位时间内脉冲的个数可以实现调频。
通过改变占空比可以实现调压,平均电压\(U=U_N \cdot D\);
- 占空比越大,所得到的平均电压也就越大,幅值也就越大;
- 占空比越小,所得到的平均电压也就越小,幅值也就越小。
通过以上原理就可以知道,只要改变PWM
信号的占空比,就可以改变直流电机两端的平均电压,从而实现直流电机的调速。
3.1.1 直流电机机械特性
我们知道直流电机的机械特性方程式:
式中:
- \(U\)是电枢回路的直流电源电压;
- \(R_a\)为电枢电阻;
- \(R_C\)为电枢回路外串电阻;
- \(C_e\)为电动势常数,\(C_e=\frac{pz}{60a}\);
- \(z\)为电枢绕组的导体中枢;
- \(a\)为并联支路对数;
- \(C_T\)为转矩常数,\(C_T=\frac{pz}{2 \pi a}\);
- \(\phi\)为每极主磁通,\(\phi=B_{av} \tau_p l_e\);
- \(B_{av}\)为每极平均气隙磁通密度,
- \(\tau_p\)值的是两个相邻主极之间的长度,
- \(l_e\)为电枢铁芯的有效长度。
3.1.2 降压调速原理
当电压下降时,则可得到与固有机械特性相互平行的人为机械特性。

从上图可以看到,相同负载转矩\(T_L\)下,转速随着电压的下降而下降。
因此当占空比\(D(0≤D≤1)\)的大小改变时,电压\(U\)下降,速度\(n\)也会随着下降,所以只要改变占空比就能达到控制速度的目的。
3.2 硬件设计
3.2.2 STM32F103RTC6
开发板
我们在《STM32
》系列相关博文中介绍了PWM
的配置,当时使用的是型号为STM32F103RTC6
的开发板。
本节实验只用到了TIM1
的CH1
和CH2
, 即PA8
和PA9
来输出PWM
信号来控制电机,注意主控板需要和电机驱动板供地。
3.2.1 L298N
驱动板
这里我们使用到 L298N
驱动板H
桥A
,引脚接线如下:
L298N驱动板 | STM32 开发板 | 其它 |
---|---|---|
IN1 | PA8 | |
IN2 | PA9 | |
ENA | 使用跳线帽连接到5V | |
5V供电 | VT-775电机额定电压为24V,需要拔掉L298N驱动板的跳线帽 外接输入5V电压对L298N芯片内部逻辑电路供电 | |
供电GND | 和STM32开发板供地 | |
驱动电压 | 24V | |
OUT1 | 直流电机VT-775的M+端子 | |
OUT2 | 直流电机VT-775的M-端子 |
3.3 软件设计
接下来我们实现一个功能:
- 按下
KEY0
加速电机; - 按下
KEY1
减速电机。
既然我们需要实现该功能,就需要实现如下代码:
(1)定时器2
通道 CH1
以及通用CH2 PWM
初始化,设置频率为10kHz
,占空比均设置为0;
- 定时器
2
通道CH1
使用的引脚是PA0
; - 定时器
2
通道CH2
使用的引脚是PA1
; - 这里并没有使用定时器
1
的通道CH1
和CH2
,主要是因为串口1
的TX
引脚和定时器1
的CH2
引脚冲突了(PA9
引脚)。
(2)编写外部中断处理程序:
KEY0
连接STM32
的PC5
,按下时输出低电平;- 配置
GPIOC
对应的EXTI
线[9:5]
外部中断,下降沿触发; - 中断处理函数检测
KEY0
按键按下,增加通道CH1
的占空比,最大为100
;
- 配置
KEY1
连接STM32
的PA15
,按下时输出低电平;- 配置
PA15
对应的EXTI
线[15:10]
外部中断,下降沿触发; - 中断处理函数检测
KEY1
按键按下,减小通道CH1
的占空比,最小为0
。
- 配置
3.3.1 main
函数实现
#include "common.h"
#include "stdio.h"
#include "motor.h"
int main()
{
int duty;
STM32_Clock_Init(9); //系统时钟初始化
// 串口初始化
STM32_NVIC_Init(2,USART1_IRQn,0,1); //串口中断优先级初始化,其中包括中断使能
usart_init(USART_1,115200); //串口1初始化,波特率115200 映射到PA9 PA10
// 按键KEY初始化
gpio_init(PC5,GPI_UP,HIGH); //PC5接按键KEY0
gpio_init(PA15,GPI_UP,HIGH); //PC5接按键KEY0
Ex_NVIC_Congig(PC5,FALLING); //按键KEY0按下触发 高电平->低电平
Ex_NVIC_Congig(PA15,FALLING); //按键KEY1按下触发 高电平->低电平
STM32_NVIC_Init(2,EXTI9_5_IRQn,2,2); //EXTI线[9:5]中断优先级初始化,其中包括中断使能
STM32_NVIC_Init(2,EXTI15_10_IRQn,2,2); //EXTI线[15:10]中断优先级初始化,其中包括中断使能
motor_init(); // 电机初始化
while(1)
{
duty = get_motor_duty();
printf("duty: %d\n",duty);
delay_ms(1000);
}
}
3.3.2 motor.h
motor.h
为直流电机驱动头文件:
/******************************************************************************************************
*
* Function : 直流有刷电机控制,L298N驱动板
使用定时器TIME2 CH1生成PWM1,使用PA0引脚
使用定时器TIME2 CH2生成PWM2,使用PA1引脚
*
*
*********************************************************************************************************/
#ifndef _STM32f10x__MOTOR_H
#define _STM32f10x__MOTOR_H
#include "pwm.h"
/*******************************************************************************************/
extern void motor_init(void); //电机初始化
extern void motor_speed_up(void); //电机加速
extern void motor_slow_down(void); //电机减速
extern int get_motor_duty(void); //获取电机PWM占空比
#endif
3.3.3 motor.c
motor.c
为直流电机驱动源文件:
/*********************************************************************************************/
#include "motor.h"
/* 电机占空比 */
volatile int g_motor_pwm = 0;
/* 电机正转/反转 */
volatile bool g_motor_fwd = TRUE;
/**************************************************************************************************
*
* Function : 电机初始化
*
**************************************************************************************************/
void motor_init(void)
{
//电机初始化********************************************************
TIM_PWM_Init(TIMER2, 10, PWM_CH1); // PWM初始化,频率为10kHz PA0
TIM_PWM_Init(TIMER2, 10, PWM_CH2); // PWM初始化,频率为10kHz PA1
TIM_PWM_Duty(TIMER2, 0, PWM_CH1);
TIM_PWM_Duty(TIMER2, 0, PWM_CH2);
}
/**************************************************************************************************
*
* Function : 刷新电机速度
*
**************************************************************************************************/
void motor_update_speed(void)
{
// 电机正转
if(g_motor_fwd)
{
TIM_PWM_Duty(TIMER2, g_motor_pwm, PWM_CH1);
TIM_PWM_Duty(TIMER2, 0, PWM_CH2);
}
else
{
TIM_PWM_Duty(TIMER2, 0, PWM_CH1);
TIM_PWM_Duty(TIMER2, g_motor_pwm, PWM_CH2);
}
}
/**************************************************************************************************
*
* Function : 电机加速
*
**************************************************************************************************/
void motor_speed_up(void)
{
g_motor_pwm++;
if(g_motor_pwm >100)
{
g_motor_pwm = 100;
}
motor_update_speed();
}
/**************************************************************************************************
*
* Function : 电机减速
*
**************************************************************************************************/
void motor_slow_down(void)
{
g_motor_pwm--;
if(g_motor_pwm < 0)
{
g_motor_pwm = 0;
}
motor_update_speed();
}
/**************************************************************************************************
*
* Function : 获取电机PWM占空比
*
**************************************************************************************************/
int get_motor_duty(void)
{
return g_motor_pwm;
}
3.3.4 EXTI9_5_IRQHandler
中断处理函数
在EXTI9_5_IRQHandler
中断处理函数中实现了KEY0
按键按下电机加速的功能;
/*********************************************************************************************************************
* Function Name : EXTI9_5_IRQHandler
* Description : This function handles External lines 9 to 5 interrupt request.
* Input : None
* Output : None
* Return : None
*************************************************************************************************************************/
void EXTI9_5_IRQHandler(void)
{
if( EXTI->PR & 1<<5 ) //来自中断线5上的中断
{
//**********************自定义用户任务****************************//
motor_speed_up();
//*****************************************************************//
EXTI->PR = 1<<5; //清中断线5上的中断标志
}
if( EXTI->PR & 1<<6 ) //来自中断线6上的中断
{
//**********************自定义用户任务****************************//
//*****************************************************************//
EXTI->PR = 1<<6; //清中断线6上的中断标志
}
if( EXTI->PR & 1<<7 ) //来自中断线7上的中断
{
//**********************自定义用户任务****************************//
//*****************************************************************//
EXTI->PR = 1<<7; //清中断线7上的中断标志
}
if( EXTI->PR & 1<<8 ) //来自中断线8上的中断
{
//**********************自定义用户任务****************************//
//*****************************************************************//
EXTI->PR = 1<<8; //清中断线8上的中断标志
}
if( EXTI->PR & 1<<9 ) //来自中断线9上的中断
{
//**********************自定义用户任务****************************//
//*****************************************************************//
EXTI->PR = 1<<9; //清中断线9上的中断标志
}
}
3.3.5 EXTI15_10_IRQHandler
中断处理函数
在EXTI15_10_IRQHandler
中断处理函数中实现了KEY1
按键按下电机减速的功能;
/***********************************************************************************************************************
* Function Name : EXTI15_10_IRQHandler
* Description : This function handles External lines 15 to 10 interrupt request.
* Input : None
* Output : None
* Return : None
*************************************************************************************************************************/
void EXTI15_10_IRQHandler(void)
{
if( EXTI->PR & 1<<10 ) //来自中断线10上的中断
{
//**********************自定义用户任务****************************//
//*****************************************************************//
EXTI->PR = 1<<10; //清中断线10上的中断标志
}
if( EXTI->PR & 1<<11 ) //来自中断线11上的中断
{
//**********************自定义用户任务****************************//
//*****************************************************************//
EXTI->PR = 1<<11; //清中断线11上的中断标志
}
if( EXTI->PR & 1<<12 ) //来自中断线12上的中断
{
//**********************自定义用户任务****************************//
//*****************************************************************//
EXTI->PR = 1<<12; //清中断线12上的中断标志
}
if( EXTI->PR & 1<<13 ) //来自中断线13上的中断
{
//**********************自定义用户任务****************************//
//*****************************************************************//
EXTI->PR = 1<<13; //清中断线13上的中断标志
}
if( EXTI->PR & 1<<14 ) //来自中断线14上的中断
{
//**********************自定义用户任务****************************//
//*****************************************************************//
EXTI->PR = 1<<14; //清中断线14上的中断标志
}
if( EXTI->PR & 1<<15 ) //来自中断线15上的中断
{
//**********************自定义用户任务****************************//
motor_slow_down();
//*****************************************************************//
EXTI->PR = 1<<15; //清中断线15上的中断标志
}
}
3.3.6 测试
编译程序并下载测试,我们通过按下KEY0
/KEY1
调节占空比,可以通过串口查看当前输出的占空比;

如果有条件的话,这里我们先不连接电机,先通过示波器连接到STM32
开发板的PWM
输出引脚上,通过示波器来观察PWM
的变化情况,这里我们将PA0
引脚连接到逻辑分析仪的通道0
,PA1
引脚连接到逻辑分析仪的通道1
;

上图中:
- 红色波形为
CH1
通道,时钟周期为100us
,换算成频率就是10kHz
,此时的占空比为87
,与我们设置的一致; - 蓝色波形为
CH2
通道,始终为低电平。
当CH1
和CH2
都为低电平时,电机停止转动。当CH1
上的平均电压大于电机的启动电压后电机就可以转动了,电源电压为\(24V\),占空比为\(D\),则平均电压为:\(24V \times D\)。
在确定PWM
输出正确后我们就可以接上电机进行验证我们的程序了。
四、源码下载
源码下载路径:stm32f103
。
参考文章
[1] 直流有刷电机的驱动电路设计
[2] 4. 直流有刷电机