学习目标
- 了解电机驱动原理
- 熟悉原理图
- 了解电机驱动芯片的驱动原理
- 掌握PWM控制电机转动
- 熟悉驱动封装
- 掌握逻辑分析仪使用方法
学习内容
电机
采用N20电机,电机上有两个触点,通电就可以转动。我们采用的N20电机的额定电压为6V,最大转速是300RPM(300圈/分钟)


通电的时候,无论正接还是反接,电机都可以转动,只是转动的方向不同。 :::warning 注意:
- 减速电机请尽量避免堵转或者超负载,否则会出现崩齿轮损耗。
- 正反转控制时,不要让齿轮在传动中立刻切换转向,建议在完全停止后切换转向
:::
原理图

每个电机分别对应一个电机驱动芯片,通过电机驱动芯片进行驱动电机转动。
电机驱动芯片又是通过两路pwm来控制的。
以下是电机驱动芯片的真值表:
两个引脚分别对应了采用互补的方式,可以驱动电机,达到电机可以正转反转的效果。
电机驱动帮助我们解决了正反转动态切换的问题驱动编写
```cifndef MOTORS_H
define MOTORS_H
include “Config.h”
void Motors_init();
// 0 -> 100 void Motors_forward(int speed);
// 0 -> 100 void Motors_backward(int speed);
// 0左转 void Motors_left(int speed);
// 0右转 void Motors_right(int speed);
// 原地转 void Motors_around(int speed);
// stop void Motors_stop();
endif
```c#include "Motors.h"#include "STC8H_PWM.h"#include "GPIO.h"#define RQ_B P15#define RQ_F P14#define PERIOD (MAIN_Fosc / 1000)typedef struct {int LQ_speed;int LH_speed;int RQ_speed;int RH_speed;} MotorCfg;PWMx_Duty dutyA;// -100 ------------------ 0 --------------------- 100 Speed//B_Max 0 F_Max 速度// 0 -------------------- 50 -------------------- 100 dutyint speed2duty(int speed) {// speed > 0 前进// speed < 0 后退// [-100, 100]// speed / 2 => [-50, 50]// speed / 2 + 50 => [ 0, 100]return speed / 2 + 50;}void Motors_config(MotorCfg cfg){PWMx_InitDefine pwmInit;int LQ_duty = speed2duty(cfg.LQ_speed);int LH_duty = speed2duty(cfg.LH_speed);int RQ_duty = speed2duty(cfg.RQ_speed);int RH_duty = speed2duty(cfg.RH_speed);// 配置PWM1 - LH 左后pwmInit.PWM_Mode = CCMRn_PWM_MODE1; //模式, CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2pwmInit.PWM_Duty = PERIOD * LH_duty / 100; //PWM占空比时间, 0~PeriodpwmInit.PWM_EnoSelect = (cfg.LH_speed == 0 ? 0 : (ENO1P | ENO1N)); //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWM_Configuration(PWM1, &pwmInit); //初始化PWM// 配置PWM2 - RH 右后pwmInit.PWM_Mode = CCMRn_PWM_MODE2; //模式, CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2pwmInit.PWM_Duty = PERIOD * RH_duty / 100; //PWM占空比时间, 0~PeriodpwmInit.PWM_EnoSelect = (cfg.RH_speed == 0 ? 0 : (ENO2P | ENO2N)); //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWM_Configuration(PWM2, &pwmInit); //初始化PWM// 配置PWM3 - RQ 右前pwmInit.PWM_Mode = CCMRn_PWM_MODE1; //模式, CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2pwmInit.PWM_Duty = PERIOD * RQ_duty / 100; //PWM占空比时间, 0~PeriodpwmInit.PWM_EnoSelect = (cfg.RQ_speed == 0 ? 0 : (ENO3P | ENO3N)); //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWM_Configuration(PWM3, &pwmInit);// 配置PWM4 - LQ 左前pwmInit.PWM_Mode = CCMRn_PWM_MODE2; //模式, CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2pwmInit.PWM_Duty = PERIOD * LQ_duty / 100; //PWM占空比时间, 0~PeriodpwmInit.PWM_EnoSelect = (cfg.LQ_speed == 0 ? 0 : (ENO4P | ENO4N)); //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWM_Configuration(PWM4, &pwmInit);// 配置PWMApwmInit.PWM_Period = PERIOD - 1; //周期时间, 0~65535pwmInit.PWM_DeadTime = 0; //死区发生器设置, 0~255pwmInit.PWM_MainOutEnable= ENABLE; //主输出使能, ENABLE,DISABLEpwmInit.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLEPWM_Configuration(PWMA, &pwmInit); //初始化PWM通用寄存器, PWMA,PWMB// 切换PWM通道// LH 左后PWM1_SW(PWM1_SW_P20_P21); //PWM1_SW_P10_P11,PWM1_SW_P20_P21,PWM1_SW_P60_P61// RH 右后PWM2_SW(PWM2_SW_P22_P23); //PWM2_SW_P12_P13,PWM2_SW_P22_P23,PWM2_SW_P62_P63// RQ 右前PWM3_SW(PWM3_SW_P14_P15); //PWM3_SW_P14_P15,PWM3_SW_P24_P25,PWM3_SW_P64_P65// LQ 左前PWM4_SW(PWM4_SW_P16_P17); //PWM4_SW_P16_P17,PWM4_SW_P26_P27,PWM4_SW_P66_P67,PWM4_SW_P34_P33// 初始化PWMA的中断NVIC_PWM_Init(PWMA,DISABLE,Priority_0);}void Motors_init() {// 电机IO口P1_MODE_IO_PU(GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7);P2_MODE_IO_PU(GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3);}// 0 -> 100void Motors_forward(int speed) {MotorCfg cfg;cfg.LQ_speed = speed;cfg.LH_speed = speed;cfg.RQ_speed = speed;cfg.RH_speed = speed;Motors_config(cfg);}// 0 -> 100void Motors_backward(int speed) {MotorCfg cfg;cfg.LQ_speed = -speed;cfg.LH_speed = -speed;cfg.RQ_speed = -speed;cfg.RH_speed = -speed;Motors_config(cfg);}// 0左转void Motors_left(int speed) {MotorCfg cfg;cfg.LQ_speed = 0;cfg.LH_speed = 0;cfg.RQ_speed = speed;cfg.RH_speed = speed;Motors_config(cfg);}// 0右转void Motors_right(int speed) {MotorCfg cfg;cfg.LQ_speed = speed;cfg.LH_speed = speed;cfg.RQ_speed = 0;cfg.RH_speed = 0;Motors_config(cfg);}// 原地转void Motors_around(int speed){MotorCfg cfg;cfg.LQ_speed = speed;cfg.LH_speed = speed;cfg.RQ_speed = -speed;cfg.RH_speed = -speed;Motors_config(cfg);}// stopvoid Motors_stop() {MotorCfg cfg;cfg.LQ_speed = 0;cfg.LH_speed = 0;cfg.RQ_speed = 0;cfg.RH_speed = 0;Motors_config(cfg);}
控制逻辑

- 前进:4个轮子同时转动即可
- 左转:右侧轮子的转速大于左侧即可
- 右转:左侧轮子的转速大于右侧即可
N20电机参数

参数表如下图:
额定电压与真实电压输入的范围要求:
- 3V电机电压输入范围:1.5V-5V
- 6V电机电压输入范围:3V-9V
- 12V电机电压输入范围:6V-12V


练习题
- pwm驱动单个电机的启停
- pwm驱动多路电机的启停
- 实现小车的前进后退转弯等功能
