5. 直流有刷电机¶
直流有刷电机(Brushed DC motor)具有结构简单、易于控制、成本低等特点, 在一些功能简单的应用场合,或者说在能够满足必要的性能、低成本和足够的可靠性的前提下, 直流有刷电机往往是一个很好的选择。例如便宜的电子玩具、各种风扇和汽车的电动座椅等。 基本的直流有刷电机在电源和电机之间只需要两根电缆,这样就可以节省配线和连接器所需的空间, 并降低电缆和连接器的成本。此外,还可以使用MOSFET/IGBT开关对直流有刷电机进行控制, 给电机提供足够好的性能的同时,整个电机控制系统也会比较便宜。
直流有刷电机转速快、扭矩小,在某些应用中可能无法满足要求。这种情况就需要做一些改进来降低转速,并提高力矩。 直流减速电机就是这样一种电机,实物图如下图所示。
这种电机通常也叫齿轮减速电机,它是在普通直流有刷电机的基础上增加了一套齿轮减速箱, 用来提供更大的力矩和更低的转速。齿轮减速箱可以通过配置不同的减速比,提供各种不同的转速和力矩。 在实际使用中减速电机使用的最为广泛,所以本章节将主要介绍直流有刷减速电机。
本章节将介绍直流有刷电机的工作原理、电机参数和驱动电路,最后通过实验来实现电机运动的简单控制。
5.1. 直流有刷电机工作原理¶
在分析原理前我们先复习一下左手定则。
左手定则是判断通电导体处于磁场中时,所受安培力 F (或运动)的方向、 磁感应强度B的方向以及通电导体棒的电流 I 三者方向之间的关系的定律。 通过左手定则可以知道通电导体在磁场中的受力方向,如下图所示。
判断方法是:伸开左手,使拇指与其他四指垂直且在一个平面内,让磁感线从手心流入, 四指指向电流方向,大拇指指向的就是安培力方向(即导体受力方向)。
有刷直流电机在其电枢上绕有大量的线圈,所产生强大的磁场与外部磁场相互作用产生旋转运动。 磁极方向的跳转是通过移动固定位置的接触点来完成的,该接触点在电机转子上与电触点相对连接。 这种固定触点通常由石墨制成,与铜或其他金属相比,在大电流短路或断路/起动过程中石墨不会熔断或者与旋转触点焊接到一起, 并且这个触点通常是弹簧承载的,所以能够获得持续的接触压力,保证向线圈供应电力。 在这里我们将通过其中一组线圈和一对磁极来分析其工作原理,如下图所示。
图中C和D两片半圆周的铜片构成换向器,两个弹性铜片靠在换向器两侧的A和B是电刷,电源通过电刷向导线框供电, 线框中就有电流通过,在线框两侧放一对磁极N和S,形成磁场,磁力线由N到S。线框通有电流时, 两侧导线就会受到磁场的作用力,方向依左手定则判断,红色和蓝色线框部分分别会受到力F1和F2, 这两个力的方向相反,这使得线框会转动,当线框转过90°时,换向器改变了线框电流的方向,产生的安培力方向不变, 于是导线框会连续旋转下去,这就是直流电动机的工作原理。
5.2. 直流有刷减速电机几个重要参数¶
空载转速:正常工作电压下电机不带任何负载的转速(单位为r/min(转/分))。 空载转速由于没有反向力矩,所以输出功率和堵转情况不一样,该参数只是提供一个电机在规定电压下最大转速的参考。
空载电流:正常工作电压下电机不带任何负载的工作电流(单位mA(毫安))。越好的电机,在空载时,该值越小。
负载转速:正常工作电压下电机带负载的转速。
负载力矩:正常工作电压下电机带负载的力矩 (N·m(牛米))。
负载电流:负载电流是指电机拖动负载时实际检测到的定子电流数值。
堵转力矩:在电机受反向外力使其停止转动时的力矩。如果电机堵转现象经常出现, 则会损坏电机,或烧坏驱动芯片。所以大家选电机时,这是除转速外要考虑的参数。 堵转时间一长,电机温度上升的很快,这个值也会下降的很厉害。
堵转电流:在电机受反向外力使其停止转动时的电流,此时电流非常大,时间稍微就可能会烧毁电机, 在实际使用时应尽量避免。
减速比:是指没有减速齿轮时转速与有减速齿轮时转速之比。
功率:般指的是它的额定功率(单位W(瓦)),即在额定电压下能够长期正常运转的最大功率, 也是指电动机在制造厂所规定的额定情况下运行时, 其输出端的机械功率。
5.3. 直流有刷电机驱动设计与分析¶
我们先来想一个问题,假设你手里现在有一个直流电机和一节电池, 当你把电机的两根电源线和电池的电源连接在一起时,这时电机可以正常旋转, 当想要电机反向旋转时,只需要把两根电源线交换一下就可以了。 但是当在实际应用中要实现正转和反转的控制也通过交换电源线实现吗? 显然这样的方法是不可行的。这时候我们可以用一个叫做“H桥电路”来驱动电机。
5.3.1. 控制电路原理设计与分析¶
如下图所示,是使用4个三极管搭建的H桥电路。
上图中,H桥式电机驱动电路包括4个三极管和一个电机。要使电机运转,必须导通对角线上的一对三极管。 根据不同三极管对的导通情况,电流可能会从左至右或从右至左流过电机,从而控制电机的转向。
上图中,当Q1和Q4导通时,电流将经过Q1从左往右流过电机, 在经过Q4流到电源负极,这时图中电机可以顺时针转动。
上图中,当Q3和Q2导通时,电流将经过Q3从右往左流过电机, 在经过Q2流到电源负极,这时图中电机可以逆时针转动。
特别地,当同一侧的Q1和Q2同时导通时,电流将从电源先后经过Q1和Q2,然后直接流到电源负极, 在这个回路中除了三极管以外就没有其他负载(没有经过电机),这时电流可能会达到最大值,此时可能会烧毁三极管, 同理,当Q3和Q4同时导通时,也会出现相同的状况。这样的情况肯定是不能发生的, 但是我们写程序又是三分写代码七分在调试,这就难免会有写错代码将同一测得三极管导通的情况, 为此我们就需要从硬件上来避免这个问题。下面电路图是改进后的驱动电路图。
与改进前的电路相比,在上面的改进电路中新增加了两个非门和4个与门,经过这样的组合就可以实现一个信号控制两个同一侧的三极管, 并且可以保证在同一侧中两个三级管不会同时导通,在同一时刻只会有一个三极管是导通的。
我们来分析一下电信号的变化:在ENABLE脚接入高电平,在IN1脚接入高电平,在经过第一个非门后,AND1的2脚就是低电平, 此时与门AND1的输出(3脚)就是低电平,所以Q1截止。而AND2的1脚和2脚都是高电平,所以AND2的3脚也是高电平, 这样Q2就导通了。在IN2接入低电平,同理分析可得,Q3导通Q4截止。在IN1和IN2处分别接入低电平和高电平, 则Q1和Q4导通,Q3和Q2截止。当IN1和IN2都接入高电平或者高电平时都只会同时导通上面或者下面的两个三极管, 不会出现同一侧的三极管同时导通的情况。
5.3.2. 驱动芯片分析¶
通常在驱动电机的时候我们会选择集成H桥的IC,因为H桥使用分立元件搭建比较麻烦,增加了硬件设计难度, 当然如果集成IC无法满足我们的功率要求时,还是需要我们自己使用MOS管、三极管等元件来搭建H桥电路, 这样的分立元件搭建的H桥一般驱动能力都会比集成IC要高。当我们在选择集成IC时, 我们需要考虑集成IC是否能满足电机的驱动电压要求,是否能承受电机工作时的电流等情况。
5.3.2.1. L298N驱动芯片¶
L298N是ST公司的产品,内部包含4通道逻辑驱动电路,是一种二相和四相电机的专门驱动芯片, 即内含两个H桥的高电压大电流双桥式驱动器,接收标准的TTL逻辑电平信号,可驱动4.5V~46V、 2A以下的电机,电流峰值输出可达3A,其内部结构如下图所示。
其工作原理与上面的讲解的H桥原理一样,这里不再赘述。L298N引脚图如下图所示。
L298N逻辑功能表。
IN1 |
IN2 |
ENA |
电机状态 |
---|---|---|---|
× |
× |
0 |
电机停止 |
1 |
0 |
1 |
电机正转 |
0 |
1 |
1 |
电机反转 |
0 |
0 |
1 |
电机停止 |
1 |
1 |
1 |
电机停止 |
IN3,IN4的逻辑图与上表相同。由上表可知ENA为低电平时,INx输入电平对电机控制不起作用, 当ENA为高电平,输入电平为一高一低,电机正或反转。同为低电平电机停止,同为高电平电机停止。 L298N的应用电路图将在后面硬件设计小节讲解。
5.4. 直流有刷减速电机控制实现¶
5.4.1. 速度控制原理¶
脉冲宽度调制(Pulse width modulation,PWM)信号,即PWM是一种按一定的规则对各脉冲的宽度进行调制, 既可改变电路输出电压的大小,也可改变输出频率。PWM通过一定的频率来改变通电和断电的时间, 从而控制电路输出功率,在电机的控制周期中,通电时间决定了它的转速。其中, 通电时间/(通断时间+断电时间)=占空比,即,高电平占整个周期的百分比,如下图所示:
上图中:T1为高电平时间,T2为低电平时间,T是周期。
D(占空比) = T1/T*100%
设电机的速度为V,最大速度为Vmax。
则:V=Vmax*D
当占空比D(0≤D≤1)的大小改变时,速度V也会改变,所以只要改变占空比就能达到控制的目的。
5.4.2. 硬件设计¶
主控有刷电机接口原理图如下图所示,有刷电机接口与无刷接口使用的是同一个接口,舍去了其中一些多余的接口, 用到了两个定时器通道,编码器、两路ADC采集通道(后续章节讲解)。本节实验用到了 GTIOC4A 和 GTIOC5A , 即 PE10 和 PE11 来输出PWM信号来控制电机,注意主控板需要和电机驱动板供地。
5.4.2.1. L298N¶
驱动板可以支持12-42V的宽电压供电,并且带输入电压转5V的电压芯片,所以驱动板只需要一个电源输入。 具体需要多大电压需要根据电机来选择。电路图见下图所示。
在下图电机控制接口中,ENABLEA和ENABLEB是使能输入脚,ENABLEA用于控制A桥,可以接到单片机的引脚控制, 也是直接使用跳冒连接到5V,ENABLEB用于控制B桥,控制方式与ENABLE一样。 INPUT1和INPUT2是A桥的控制信号,INPUT1和INPUT2是B桥的控制信号,可以接PWM控制电机。 OUTPUT1和OUTPUT2是A桥的输出接口,OUTPUT3和OUTPUT4是B桥的输出接口。
上图中8个二极管用于防止电机的反电动势损坏L298N,当E点反电势为正,超过电源+0.7V时, 上端二极管导通,这样输出线就被限位在电源电压+0.7V上,不会超过这个数值; 当E点反电势为负,低于-0.7V时,下端二极管导通,这样输出线就被限位在-0.7V上, 不会低于-0.7V了。这两个二极管是作为钳位使用,使得输出线上电压(或叫电位) 被箝位在-0.7V~+Vcc+0.7V之间。其他二极管作用于E点这两个一样。
电机与L298N驱动板连接见下表所示。
电机 |
L298N驱动板 |
---|---|
M+ |
电机输出:1 |
M- |
电机输出:2 |
L298N驱动板与主控板连接见下表所示。
L298N驱动板 |
主控板 |
---|---|
PWM1 |
PE10 |
PWM2 |
PE11 |
GND |
GND |
ENA |
PB15 |
在L298N驱动板与主控板连接中,ENA可以不接PB15,使用跳冒连接到5V。
5.4.2.2. 野火直流有刷电机驱动板-MOS管搭建板¶
野火有刷电机驱动板是使用MOS管搭建的大功率H桥电机驱动板,实物图如下图所示。
驱动板可支持12V~70V的宽电压输入,10A过电流保护电路,超过10A可自动禁用电机控制信号,最高功率支持700W。 实际使用输入电压需要根据电机进行选择,同时还具有电流采样电路、编码器接口和电源电压检测电路等等, 本小节主要讲解电机驱动部分电路,其他功能将在后续章节中讲解。
野火使用MOS管搭建的直流有刷驱动板做到了信号完全隔离,其他驱动板基本都只是使用光耦隔离了控制信号, 并没有对ADC采样电路进行隔离,野火不仅使用光耦对控制信号进行了隔离, 还使用AMC1200SDUBR隔离运放对ADC采样电路进行了隔离。
PWM控制信号使用了TLP2362高速光耦进行了隔离,SD控制信号使用了EL357N光耦进行了隔离,如下图所示。
与门的作用是可以使单片机和过流保护电路共同控制SD脚,过流保护电路将在电流电压采集章节讲解, 与门输入输出与MOS管状态真值表如下表所示。
A |
B |
Y |
MOS |
---|---|---|---|
H |
H |
H |
可导通 |
H |
L |
L |
关断(过流保护) |
L |
H |
L |
关断(单片机控制关断) |
L |
L |
L |
关断(单片机控制关断,过流保护) |
下图是使用MOS管搭建的H桥电路,使用两个EG2104驱动四个MOS管。
EG2104S主要功能有逻辑信号输入处理、死区时间控制、电平转换功能、悬浮自举电源结构和上下桥图腾柱式输出。 逻辑信号输入端高电平阀值为 2.5V 以上,低电平阀值为 1.0V 以下,要求逻辑信号的输出电流小, 可以使MCU输出逻辑信号直接连接到EG2104S的输入通道上。EG2104S芯片有一个shutdown引脚, 逻辑输入控制信号低电平有效,控制强行使LO、HO输出低电平。这样可以直接使用这个引脚做软件控制电机的旋转与停止, 还可以实现硬件的限流保护(后续章节分析保护电路),输入信号和输出信号逻辑真值表如下表所示。
IN(引脚2) |
SD(引脚3) |
HO(引脚7) |
LO(引脚5) |
---|---|---|---|
L |
L |
L |
L |
H |
L |
L |
L |
L |
H |
L |
H |
H |
H |
H |
L |
从真值表可知,在输入逻辑信号SD为“L”时,不管IN为“H”或者“L”情况下,驱动器控制输出HO、LO同时为“L”, 上、下功率管同时关断;当输入逻辑信号SD为“H”、IN为“L”时,HO输出为“L”,LO输出为“H”; 当输入逻辑信号SD为“H”、IN 为“H”时,HO输出为“H”,LO输出为“L”。
EG2104S内部集成了死区时控制电路,死区时间波形图如下图所示,其中死区时间DT的典型值为640ns。
EG2104S采用自举悬浮驱动电源结构大大简化了驱动电源设计, 只用一路电源电压VCC即可完成高端N沟道MOS管和低端N沟道MOS管两个功率开关器件的驱动,给实际应用带来极大的方便。 EG2104S自举电路结构如下图所示,EG2104S可以使用外接一个自举二极管和一个自举电容自动完成自举升压功能, 假定在下管开通、上管关断期间VC自举电容已充到足够的电压(Vc=VCC),当HO输出高电平时上管开通、下管关断时, VC自举电容上的电压将等效一个电压源作为内部驱动器VB和VS的电源,完成高端N沟道MOS管的驱动。
电机与MOS管搭建驱动板连接见下表所示。
电机 |
MOS管搭建驱动板 |
---|---|
M+ |
M+ |
M- |
M- |
MOS管搭建驱动板与主控板连接见下表所示。
MOS管搭建驱动板 |
主控板 |
---|---|
PWM1 |
PE10 |
PWM2 |
PE11 |
SD |
PB15 |
电源输入:5V |
5V |
电源输入:GND |
GND |
推荐使用配套的牛角排线直接连接驱动板和主控板。
5.4.3. 软件设计¶
5.4.3.1. 新建工程¶
我们直接在定时器章节的的 “006_GPT_PWM_Output” 例程的基础上修改程序。
- 对于 e2 studio 开发环境:
拷贝一份我们之前的 e2s 工程 “006_GPT_PWM_Output”, 然后将工程文件夹重命名为 “200_Motor_BDC_PWM_Control”,最后再将它导入到我们的 e2 studio 工作空间中。
- 对于 Keil 开发环境:
拷贝一份我们之前的 Keil 工程 “006_GPT_PWM_Output”, 然后将工程文件夹重命名为 “200_Motor_BDC_PWM_Control”,并进入该文件夹里面双击 Keil 工程文件,打开该工程。
工程新建好之后,在工程根目录的 “src” 文件夹下面新建 “motor_controls” 文件夹, 再进入 “motor_controls” 文件夹里面新建源文件和头文件:“bsp_motor_control.c” 和 “bsp_motor_control.h”。 工程文件结构如下。
200_Motor_BDC_PWM_Control
├─ ......
└─ src
├─ beep
│ ├─ bsp_beep.c
│ └─ bsp_beep.h
├─ debug_uart
│ ├─ bsp_debug_uart.c
│ └─ bsp_debug_uart.h
├─ gpt
│ ├─ bsp_gpt_pwm_output.c
│ └─ bsp_gpt_pwm_output.h
├─ key
│ ├─ bsp_key_irq.c
│ └─ bsp_key_irq.h
├─ led
│ ├─ bsp_led.c
│ └─ bsp_led.h
├─ motor_controls
│ ├─ bsp_motor_control.c //新建文件
│ └─ bsp_motor_control.h //新建文件
└─ hal_entry.c
5.4.3.2. FSP配置¶
下面以野火启明6T2开发板为例来讲解相关的 FSP 配置。
本节实验用到了 GTIOC4A 和 GTIOC5A , 即 PE10 和 PE11 来输出PWM信号来控制电机, 因此需要先在“Pins”配置页中为 GPT 配置引脚, 我们将 GPT4 和 GPT5 的 GTIOC4A 和 GTIOC5A 信号输出分别连接到 PE10 和 PE11 引脚,如下图所示。
然后在“Stacks”配置页中更改 GPT 模块,并对其作如下图所示的配置。
再次添加一个 GPT 模块,并对其作如下图所示的配置。
上图中框起来的部分是需要我们去修改的区域,其他的配置属性按照默认即可。 图中需要更改的一部分配置如下:
Pin Output Support:这一项配置允许输出 PWM 信号到引脚,我们改为使能引脚输出。
Name 和 Channel:这两项分别设置 GPT 模块名字为 “g_timer4_pwm” / “g_timer5_pwm” 和选择第 4/5 个 GPT 定时器(第4/5个通道)。
Mode:配置 GPT 的工作模式为 PWM 输出模式。
Period 和 Period Unit:我们将PWM频率设为 20 KHz, 因此“Period”设置为 20,单位“Period Unit”设置为 Kilohertz,即千赫兹(KHz)。
GTIOCA Output Enabled:使能 GTIOCA 输出。
GTIOCA Stop Level:设置定时器停止时 GTIOCA 输出的电平为低电平。
GTIOC4A:选择连接到 PE10 引脚,这个软件会自动设置的,我们只要确认了就好。
GTIOC5A:选择连接到 PE11 引脚,这个软件会自动设置的,我们只要确认了就好。
GPT的“Output”部分的属性描述如下表所示。
属性 |
描述 |
---|---|
Custom Waveform > GTIOA/GTIOB > Initial Output Level |
设置GPT初始化时 GTIOCxA/GTIOCxB 的电平(低电平或高电平)。 |
Custom Waveform > GTIOA/GTIOB > Cycle End Output Level |
完成一个计数周期时 GTIOCxA/GTIOCxB 的输出电平(保持不变、输出高、输出低或反转电平)。 |
Custom Waveform > GTIOA/GTIOB > Compare Match Output Level |
发生比较匹配时 GTIOCxA/GTIOCxB 的输出电平(保持不变、输出高、输出低或反转电平)。 |
Custom Waveform > GTIOA/GTIOB > Retain Output Level at Count Stop |
在计数停止时保持 GTIOCxA/GTIOCxB 电平。 |
Custom Waveform > Custom Waveform Enable |
使能自定义波形的配置。 |
Duty Cycle Percent (only applicable in PWM mode) |
设定 PWM 占空比(仅用于 PWM 模式) |
GTIOCA Output Enabled |
使能 GTIOCA 输出到相应引脚 |
GTIOCA Stop Level |
当 GPT 定时器停止时 GTIOCA 的输出电平 |
GTIOCB Output Enabled |
使能 GTIOCB 输出到相应引脚 |
GTIOCB Stop Level |
当 GPT 定时器停止时 GTIOCB 的输出电平 |
5.4.3.3. 定时器初始化函数¶
/** GPT初始化函数
*/
void Motor_GPT_PWM_Init(void)
{
timer_info_t info;
/* 初始化 GPT 模块 */
R_GPT_Open(&g_timer4_pwm_ctrl, &g_timer4_pwm_cfg);
R_GPT_Open(&g_timer5_pwm_ctrl, &g_timer5_pwm_cfg);
/* 获得计时器一个周期需要的计数次数 */
R_GPT_InfoGet(&g_timer4_pwm_ctrl, &info);
current_period_counts1 = info.period_counts;
R_GPT_InfoGet(&g_timer5_pwm_ctrl, &info);
current_period_counts2 = info.period_counts;
R_GPT_Enable(&g_timer4_pwm_ctrl);
R_GPT_Enable(&g_timer4_pwm_ctrl);
/* 启动 GPT 定时器 */
R_GPT_Start(&g_timer4_pwm_ctrl);
R_GPT_Start(&g_timer5_pwm_ctrl);
/* 初始化占空比为 0 */
Motor_GPT_PWM_SetDuty(0, 0);
}
5.4.3.4. 设置占空比函数¶
/** 设置PWM占空比函数
@param duty_pwm1: 占空比范围:0~100 %
@param duty_pwm2: 占空比范围:0~100 %
*/
void Motor_GPT_PWM_SetDuty(uint8_t duty_pwm1, uint8_t duty_pwm2)
{
uint32_t duty_cycle_counts1;
uint32_t duty_cycle_counts2;
if (duty_pwm1 > 100)
duty_pwm1 = 100; //限制占空比范围:0~100
if (duty_pwm2 > 100)
duty_pwm2 = 100; //限制占空比范围:0~100
/* 根据占空比和一个周期的计数次数计算GTCCR寄存器的值 */
/*执行 (current_period_counts1 - 100) 是为了防止H桥电路中的自举电容无法充电
*从而导致高端MOSFET无法维持导通、电机缓慢停转的现象出现*/
duty_cycle_counts1 = (uint32_t)(((uint64_t) (current_period_counts1 - 100) * duty_pwm1) / 100);
duty_cycle_counts2 = (uint32_t)(((uint64_t) (current_period_counts2 - 100) * duty_pwm2) / 100);
/* 最后调用FSP库函数设置占空比 */
R_GPT_DutyCycleSet(&g_timer4_pwm_ctrl, duty_cycle_counts1, GPT_IO_PIN_GTIOCA);
R_GPT_DutyCycleSet(&g_timer5_pwm_ctrl, duty_cycle_counts2, GPT_IO_PIN_GTIOCA);
}
5.4.3.5. 电机初始化函数¶
/*电机初始化*/
void Motor_Control_Init(void)
{
/* 设置电机方向 */
motor_dir = true; //正转
/*设置电机方向和占空比*/
Motor_Control_SetDirAndDuty(motor_dir, (uint8_t)motor_pwm_duty);
}
5.4.3.6. 电机控制函数¶
/**
* @brief 启动电机
*/
void Motor_Control_Start(void)
{
SD_HIGH_MOTOR_ENABLE; // 使能电机
R_GPT_OutputEnable(&g_timer4_pwm_ctrl, GPT_IO_PIN_GTIOCA); // 使能定时器4的PWM输出
R_GPT_OutputEnable(&g_timer5_pwm_ctrl, GPT_IO_PIN_GTIOCA); // 使能定时器5的PWM输出
}
/**
* @brief 停止电机
*/
void Motor_Control_Stop(void)
{
SD_LOW_MOTOR_DISABLE; // 禁用电机
R_GPT_OutputDisable(&g_timer4_pwm_ctrl, GPT_IO_PIN_GTIOCA); // 禁用定时器4的PWM输出
R_GPT_OutputDisable(&g_timer5_pwm_ctrl, GPT_IO_PIN_GTIOCA); // 禁用定时器5的PWM输出
}
/**
* @brief 反转电机方向
*/
void Motor_Control_Reverse(void)
{
// 反转电机方向
motor_dir = !motor_dir;
// 根据新的电机方向设置 PWM 占空比
if (motor_dir == false)
{
Motor_GPT_PWM_SetDuty((uint8_t)motor_pwm_duty, 0); // 设置正向占空比
}
else
{
Motor_GPT_PWM_SetDuty(0, (uint8_t)motor_pwm_duty); // 设置反向占空比
}
}
/**
* @brief 设置电机方向和占空比
* @param dir 方向 (0: 正向, 1: 反向)
* @param pwm_duty 占空比 (0-100)
*/
void Motor_Control_SetDirAndDuty(uint8_t dir, uint8_t pwm_duty)
{
if (false == dir) // 如果方向为0
Motor_GPT_PWM_SetDuty(pwm_duty, 0); // 设置正向占空比
else
Motor_GPT_PWM_SetDuty(0, pwm_duty); // 设置反向占空比
}
5.4.3.7. 串口接收控制函数¶
本届实验中,使用了串口来调试电机,所以还要在 bsp_debug_uart.c 文件中进行修改。
// 电机功能操作允许标志位
volatile bool motor_start_flag = false;
volatile bool motor_stop_flag = false;
volatile bool motor_speedup_flag = false;
volatile bool motor_slowdown_flag = false;
volatile bool motor_reverse_flag = false;
/* 发送完成标志 */
volatile bool uart_send_complete_flag = false;
volatile bool uart_receive_complete_flag = false;
/* 串口中断回调 */
void debug_uart9_callback (uart_callback_args_t * p_args)
{
switch (p_args->event)
{
case UART_EVENT_RX_CHAR:
{
/* 根据字符指令进行操作 */
switch (p_args->data)
{
case 's': //start
motor_start_flag = true;
break;
case 'p': //pause
motor_stop_flag = true;
break;
case 'u': //up
motor_speedup_flag = true;
break;
case 'd': //down
motor_slowdown_flag = true;
break;
case 'r': //reverse
motor_reverse_flag = true;
break;
default:
// input error
break;
}
break;
break;
}
case UART_EVENT_TX_COMPLETE:
{
uart_send_complete_flag = true;
break;
}
default:
break;
}
}
5.4.3.8. hal_entry入口函数¶
/* 用户头文件包含 */
#include "hal_data.h"
#include "led/bsp_led.h"
#include "beep/bsp_beep.h"
#include "key/bsp_key_irq.h"
#include "debug_uart/bsp_debug_uart.h"
#include "gpt/bsp_gpt_pwm_output.h"
#include "motor_control/bsp_motor_control.h"
void hal_entry(void)
{
/* TODO: add your own code here */
LED_Init(); // LED 初始化
Debug_UART9_Init(); // SCI4 UART 调试串口初始化
printf("这是一个有刷电机基础控制示例\r\n");
printf("打开串口助手发送以下指令,可控制电机运行状态:\r\n");
printf("s----------------电机开始旋转\r\n");
printf("p----------------电机停止旋转\r\n");
printf("u----------------电机加速旋转[PWM+10%%]\r\n");
printf("d----------------电机减速旋转[PWM-10%%]\r\n");
printf("r----------------电机反向旋转\r\n");
/* 电机PWM和编码器初始化 */
Motor_GPT_PWM_Init();
Motor_Control_Init();
LED1_ON;
LED4_ON;
while(1)
{
if(motor_start_flag == true) // 如果电机启动标志为真
{
motor_start_flag = false; // 将电机启动标志设为假
Motor_Control_Start(); // 启动电机
printf("电机启动,当前PWM占空比 = %d%%\r\n", motor_pwm_duty);
}
if(motor_stop_flag == true) // 如果电机停止标志为真
{
motor_stop_flag = false; // 将电机停止标志设为假
Motor_Control_Stop(); // 停止电机
printf("************电机关闭************\r\n");
}
if(motor_speedup_flag == true) // 如果电机加速标志为真
{
motor_speedup_flag = false; // 将电机加速标志设为假
motor_pwm_duty += 10; // 增加电机的PWM占空比
if (motor_pwm_duty > 100) {// 如果PWM占空比超过100
motor_pwm_duty = 100; // 将PWM占空比限制为100
printf("已到达最大占空比,当前电机PWM占空比 = %d%%\r\n", motor_pwm_duty);
}else{
Motor_Control_SetDirAndDuty(motor_dir, (uint8_t)motor_pwm_duty); // 设置电机方向和占空比
printf("电机加速,新的电机PWM占空比 = %d%%\r\n", motor_pwm_duty); // 打印当前的PWM占空比
}
}
if(motor_slowdown_flag == true) // 如果电机减速标志为真
{
motor_slowdown_flag = false; // 将电机减速标志设为假
motor_pwm_duty -= 10; // 减少电机的PWM占空比
if (motor_pwm_duty < 0){// 如果PWM占空比小于0
motor_pwm_duty = 0; // 将PWM占空比限制为0
printf("已到达最小占空比,当前电机PWM占空比 = %d%%\r\n", motor_pwm_duty);
}else{
Motor_Control_SetDirAndDuty(motor_dir, (uint8_t)motor_pwm_duty); // 设置电机方向和占空比
printf("电机减速,新的电机PWM占空比 = %d%%\r\n", motor_pwm_duty); // 打印当前的PWM占空比
}
}
if(motor_reverse_flag == true) // 如果电机反转标志为真
{
motor_reverse_flag = false; // 将电机反转标志设为假
Motor_Control_Reverse(); // 反转电机
if (motor_dir == 0) {
printf("电机方向翻转,当前旋转方向:正向\n");
}
else {
printf("电机方向翻转,当前旋转方向:反向\n");
}
}
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
5.4.4. 下载验证¶
编译并下载程序后,复位开发板使程序重新运行,如果有条件的话,这里我们先不连接电机,先通过示波器连接到开发板的PWM输出引脚上,通过示波器来观察PWM 的变化情况,使用示波器的CH1连接到 PE10 ,使用示波器的CH2连接到 PE11 ,注意示波器要与开发板共地。
程序运行后我们打开串口调试助手,连接开发板,可以看到对电机的控制方法,我们可以通过野火多功能调试助手中的多项发送来控制电机,如下图所示:
上电后我们通过示波器可以观察到两个通道都是低电平,当启动电机后,如下图所示。
在上图中黄色波形为CH1通道,蓝色波形为CH2通道,。此时可以通过示波器上显示的波形的占空比和频率, 通过波形计算也与理论相符,这说明我们的PWM的配置是正确的,其中CH1通道的波形 一直为低电平。当发送反转信号后,输出口更换,电机反向旋转,我们也可以通过示波器观察到,如下图所示:
在确定PWM输出正确后就可以接上电机验证程序了。