4.7 L298N 电机驱动模块
L298N 是 ST 公司生产的一种高电压、大电流电机驱动芯片。该芯片采用 15 脚封装。主要特点是:工作电压高,最高工作电压可达 46V;输出电流大,瞬间峰值电流可达 3A,持续工作电流为 2A;额定功率 25W。内含两个 H 桥的高电压大电流全桥式驱动器,可以用来驱动直流电动机和步进电动机、继电器线圈等感性负载;采用标准逻辑电平信号控制;具有两个使能控制端,在不受输入信号影响的情况下允许或禁止器件工作有一个逻辑电源输入端,使内部逻辑电路部分在低电压下工作;可以外接检测电阻,将变化量反馈给控制电路。使用 L298N 芯片驱动电机,该芯片可以驱动一台两相步进电机或四相步进电机,也可以驱动两台直流电机。
4.7.1 模块来源
采购链接: L298N 双路电机驱动板 L298 两路 2 步进马达模块 智能小车机器人配件
资料下载:
4.7.2 规格参数
驱动电压:5V~24V
驱动电流:2A
逻辑电压:5V
逻辑电流:36mA
控制方式:PWM
4.7.3 移植过程
我们的目标是在梁山派 GD32F470 上能够控制电机旋转速度的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
4.7.3.1 查看资料
当驱动电压为 7V~12V 的时候,即 VCC 电机驱动端子接通驱动电源时,板载的 78M05 供给芯片的逻辑电源,指示灯亮,可以不用再外接逻辑电源;如果使用电机驱动的板载 5V 供电,接口中的 +5V 供电端子不要输入电压,但是可以引出 5V 电压供外部使用(这种即为常规应用!)。
当驱动电压高于 12V,小于等于 24V(芯片手册中提出可以支持到 35V,但是按照经验一般 L298 保守应用最大电压支持到 24V 已经很了不起!)时,比如要驱动额定电压为 18V 的电机。首先必须断开板载 5V 使能,指示灯熄灭,不使用板载的 78M05 供给芯片的逻辑电源,然后在 5V 输出端口外部接入 5V 电压对 L298N 内部逻辑电路供电。(这种是高压驱动的非常规应用!)
5V 使能即一个电平为 5V 的控制信号,当此信号输入有效时且电机驱动模块中电源供电正常时,电机驱动模块输出电流。否则即使电源供电正常,电机上也无电流。
L298N 使能端(高电平有效,常态下用跳线帽接于 VCC)可通过这两个端口 1 实现 PWM 调速(使用 PWM 调速时取下跳线帽)ENA 和 ENB 接 EPWM 信号,1N1,1N2,1N3,1N4 正常接上高低电平使电机正转,反转或停转。
注意:L298N 供电的 5V 如果是用另外电源供电的话,(即不是和单片机的电源共用),那么需要将单片机的 GND 和模块上的 GND 连接在一起,只有这样单片机上过来的逻辑信号才有个参考 0 点。板载 5V 稳压芯片的输入引脚和电机供电驱动接线端子导通的。
4.7.3.2 引脚选择
L298N 控制电机速度的方式,是通过将 IN1 与 IN2 接入 PWM,直接通过调整 PWM 的占空比进行速度控制。因此要求 IN1/IN2/IN3/IN4 都要使用 PWM 功能。
| L298N | 立创·梁山派 |
|---|---|
| GND | GND |
| +12V | 接外部电源(6-24V) |
| IN1 | PB14 |
| IN2 | PB15 |
| IN3 | PB1 |
| IN4 | PB0 |
4.7.3.3 移植至工程
移植步骤中的导入.c 和.h 文件与之前相同,只是将.c 和.h 文件更改为 bsp_L298N.c 与 bsp_L298N.h。见 2.2.3.3 移植至工程。这里不再过多讲述。移植完成后面修改相关代码。
在文件 bsp_L298N.c 中,编写如下代码。
/********************************************************************************
* 文 件 名: bsp_L298N.c
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2022年04月27日
* 功能介绍:
******************************************************************************
* 开发板官网:www.lckfb.com
*********************************************************************************/
#include "bsp_L298N.h"
#include "systick.h"
/******************************************************************
* 函 数 名 称:L298N_Init
* 函 数 说 明:PWM配置
* 函 数 形 参: pre定时器时钟预分频值 per周期
* 函 数 返 回:无
* 作 者:LC
* 备 注:PWM频率=200 000 000 /( (pre+1) * (per+1) )
******************************************************************/
void L298N_Init(uint16_t pre,uint16_t per)
{
timer_parameter_struct timere_initpara={0}; // 定义定时器结构体
timer_oc_parameter_struct timer_ocintpara={0}; //定时器比较输出结构体
//定时器时钟
rcu_periph_clock_enable(RCU_IN1_TIMER); // 开启定时器时钟
rcu_periph_clock_enable(RCU_IN2_TIMER);
rcu_periph_clock_enable(RCU_IN3_TIMER);
rcu_periph_clock_enable(RCU_IN4_TIMER);
//引脚时钟
rcu_periph_clock_enable(RCU_IN1);
rcu_periph_clock_enable(RCU_IN2);
rcu_periph_clock_enable(RCU_IN3);
rcu_periph_clock_enable(RCU_IN4);
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4); // 配置定时器时钟
/* 配置AIN1*/
gpio_mode_set(PORT_IN1,GPIO_MODE_AF,GPIO_PUPD_NONE,GPIO_IN1);
gpio_output_options_set(PORT_IN1,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,GPIO_IN1);
gpio_af_set(PORT_IN1,AF_IN1,GPIO_IN1);
/* 配置AIN2*/
gpio_mode_set(PORT_IN2,GPIO_MODE_AF,GPIO_PUPD_NONE,GPIO_IN2);
gpio_output_options_set(PORT_IN2,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,GPIO_IN2);
gpio_af_set(PORT_IN2,AF_IN2,GPIO_IN2);
/* 配置BIN1*/
gpio_mode_set(PORT_IN3,GPIO_MODE_AF,GPIO_PUPD_NONE,GPIO_IN3);
gpio_output_options_set(PORT_IN3,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,GPIO_IN3);
gpio_af_set(PORT_IN3,AF_IN3,GPIO_IN3);
/* 配置BIN2*/
gpio_mode_set(PORT_IN4,GPIO_MODE_AF,GPIO_PUPD_NONE,GPIO_IN4);
gpio_output_options_set(PORT_IN4,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,GPIO_IN4);
gpio_af_set(PORT_IN4,AF_IN4,GPIO_IN4);
/* 配置定时器参数 */
timer_deinit(BSP_IN1_TIMER);
timer_deinit(BSP_IN2_TIMER);
timer_deinit(BSP_IN3_TIMER);
timer_deinit(BSP_IN4_TIMER);
// 复位定时器
timere_initpara.prescaler = pre-1; // 时钟预分频值
timere_initpara.alignedmode = TIMER_COUNTER_EDGE; // 边缘对齐
timere_initpara.counterdirection = TIMER_COUNTER_UP; // 向上计数
timere_initpara.period = per-1; // 周期
timere_initpara.clockdivision = TIMER_CKDIV_DIV1; // 分频因子
timere_initpara.repetitioncounter = 0; // 重复计数器 0-255
timer_init(BSP_IN1_TIMER,&timere_initpara); // 初始化定时器
timer_init(BSP_IN2_TIMER,&timere_initpara); // 初始化定时器
timer_init(BSP_IN3_TIMER,&timere_initpara); // 初始化定时器
timer_init(BSP_IN4_TIMER,&timere_initpara); // 初始化定时器
/* 配置输出结构体 */
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH; // 有效电平的极性
timer_ocintpara.outputstate = TIMER_CCX_ENABLE; // 配置比较输出模式状态 也就是使能PWM输出到端口
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH; // 通道互补输出极性为高电平
timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE; // 通道互补输出状态失能
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW; // 信道输出的空闲状态为低
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;// 信道互补输出的空闲状态为低
/* 配置定时器输出功能 */
timer_channel_output_config(BSP_IN1_TIMER,BSP_IN1_CHANNEL,&timer_ocintpara);
timer_channel_output_config(BSP_IN2_TIMER,BSP_IN2_CHANNEL,&timer_ocintpara);
timer_channel_output_config(BSP_IN3_TIMER,BSP_IN3_CHANNEL,&timer_ocintpara);
timer_channel_output_config(BSP_IN4_TIMER,BSP_IN4_CHANNEL,&timer_ocintpara);
/* 配置占空比 范围 0 ~ (per-1) */
timer_channel_output_pulse_value_config(BSP_IN1_TIMER,BSP_IN1_CHANNEL,0);
timer_channel_output_pulse_value_config(BSP_IN2_TIMER,BSP_IN2_CHANNEL,0);
timer_channel_output_pulse_value_config(BSP_IN3_TIMER,BSP_IN3_CHANNEL,0);
timer_channel_output_pulse_value_config(BSP_IN4_TIMER,BSP_IN4_CHANNEL,0);
timer_channel_output_mode_config(BSP_IN1_TIMER,BSP_IN1_CHANNEL,TIMER_OC_MODE_PWM0); // 配置定时器通道输出比较模式
timer_channel_output_mode_config(BSP_IN2_TIMER,BSP_IN2_CHANNEL,TIMER_OC_MODE_PWM0); // 配置定时器通道输出比较模式
timer_channel_output_mode_config(BSP_IN3_TIMER,BSP_IN3_CHANNEL,TIMER_OC_MODE_PWM0); // 配置定时器通道输出比较模式
timer_channel_output_mode_config(BSP_IN4_TIMER,BSP_IN4_CHANNEL,TIMER_OC_MODE_PWM0); // 配置定时器通道输出比较模式
timer_channel_output_shadow_config(BSP_IN1_TIMER,BSP_IN1_CHANNEL,TIMER_OC_SHADOW_DISABLE); // 配置定时器通道输出影子寄存器
timer_channel_output_shadow_config(BSP_IN2_TIMER,BSP_IN2_CHANNEL,TIMER_OC_SHADOW_DISABLE); // 配置定时器通道输出影子寄存器
timer_channel_output_shadow_config(BSP_IN1_TIMER,BSP_IN3_CHANNEL,TIMER_OC_SHADOW_DISABLE); // 配置定时器通道输出影子寄存器
timer_channel_output_shadow_config(BSP_IN2_TIMER,BSP_IN4_CHANNEL,TIMER_OC_SHADOW_DISABLE); // 配置定时器通道输出影子寄存器
/* 只有高级定时器使用 */
timer_auto_reload_shadow_enable(BSP_IN1_TIMER);
timer_auto_reload_shadow_enable(BSP_IN2_TIMER);
timer_auto_reload_shadow_enable(BSP_IN3_TIMER);
timer_auto_reload_shadow_enable(BSP_IN4_TIMER);
timer_primary_output_config(BSP_IN1_TIMER, ENABLE);
timer_primary_output_config(BSP_IN2_TIMER, ENABLE);
timer_primary_output_config(BSP_IN3_TIMER, ENABLE);
timer_primary_output_config(BSP_IN4_TIMER, ENABLE);
/* 使能定时器 */
timer_enable(BSP_IN1_TIMER);
timer_enable(BSP_IN2_TIMER);
timer_enable(BSP_IN3_TIMER);
timer_enable(BSP_IN4_TIMER);
}
/******************************************************************
* 函 数 名 称:AO_Control
* 函 数 说 明:A端口电机控制
* 函 数 形 参:dir旋转方向 1正转0反转 speed旋转速度,范围(0 ~ per-1)
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void AO_Control(uint8_t dir, uint32_t speed)
{
if( dir == 1 )
{
//AO1输出
timer_channel_output_pulse_value_config(BSP_IN1_TIMER,BSP_IN1_CHANNEL, 0 );
//AO2输出
timer_channel_output_pulse_value_config(BSP_IN2_TIMER,BSP_IN2_CHANNEL, speed );
}
else
{
//AO1输出
timer_channel_output_pulse_value_config(BSP_IN1_TIMER,BSP_IN1_CHANNEL, speed );
//AO2输出
timer_channel_output_pulse_value_config(BSP_IN2_TIMER,BSP_IN2_CHANNEL, 0 );
}
}
/******************************************************************
* 函 数 名 称:B0_Control
* 函 数 说 明:B端口电机控制
* 函 数 形 参:dir旋转方向 1正转0反转 speed旋转速度,范围(0 ~ per-1)
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void BO_Control(uint8_t dir, uint32_t speed)
{
if( dir == 1 )
{
//BO1输出
timer_channel_output_pulse_value_config(BSP_IN3_TIMER,BSP_IN3_CHANNEL, 0 );
//BO2输出
timer_channel_output_pulse_value_config(BSP_IN4_TIMER,BSP_IN4_CHANNEL, speed );
}
else
{
//BO1输出
timer_channel_output_pulse_value_config(BSP_IN3_TIMER,BSP_IN3_CHANNEL, speed );
//BO2输出
timer_channel_output_pulse_value_config(BSP_IN4_TIMER,BSP_IN4_CHANNEL, 0 );
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
在文件 bsp_L298N.h 中,编写如下代码。
#ifndef _BSP_L298N_H
#define _BSP_L298N_H
#include "gd32f4xx.h"
#include "systick.h"
#define RCU_IN1 RCU_GPIOB
#define PORT_IN1 GPIOB
#define GPIO_IN1 GPIO_PIN_14
#define AF_IN1 GPIO_AF_9
#define RCU_IN2 RCU_GPIOB
#define PORT_IN2 GPIOB
#define GPIO_IN2 GPIO_PIN_15
#define AF_IN2 GPIO_AF_9
#define RCU_IN3 RCU_GPIOB
#define PORT_IN3 GPIOB
#define GPIO_IN3 GPIO_PIN_1
#define AF_IN3 GPIO_AF_2
#define RCU_IN4 RCU_GPIOB
#define PORT_IN4 GPIOB
#define GPIO_IN4 GPIO_PIN_0
#define AF_IN4 GPIO_AF_2
#define RCU_IN1_TIMER RCU_TIMER11
#define BSP_IN1_TIMER TIMER11 // 定时器
#define BSP_IN1_CHANNEL TIMER_CH_0 // 定时器通道
#define RCU_IN2_TIMER RCU_TIMER11
#define BSP_IN2_TIMER TIMER11 // 定时器
#define BSP_IN2_CHANNEL TIMER_CH_1 // 定时器通道
#define RCU_IN3_TIMER RCU_TIMER2
#define BSP_IN3_TIMER TIMER2 // 定时器
#define BSP_IN3_CHANNEL TIMER_CH_3 // 定时器通道
#define RCU_IN4_TIMER RCU_TIMER2
#define BSP_IN4_TIMER TIMER2 // 定时器
#define BSP_IN4_CHANNEL TIMER_CH_2 // 定时器通道
#define IN1_OUT(X) gpio_bit_write(PORT_IN1, GPIO_IN1, X?SET:RESET)
#define IN2_OUT(X) gpio_bit_write(PORT_IN2, GPIO_IN2, X?SET:RESET)
#define IN3_OUT(X) gpio_bit_write(PORT_IN3, GPIO_BIN3, X?SET:RESET)
#define IN4_OUT(X) gpio_bit_write(PORT_IN4, GPIO_BIN4, X?SET:RESET)
void L298N_Init(uint16_t pre,uint16_t per);
void AO_Control(uint8_t dir, uint32_t speed);
void BO_Control(uint8_t dir, uint32_t speed);
#endif /* BSP_L298N_H */2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
4.7.4 移植验证
在自己工程中的 main 主函数中,编写如下。
/********************************************************************************
* 文 件 名: main.c
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2022年04月19日
* 功能介绍:
******************************************************************************
* 开发板官网:www.lckfb.com
*********************************************************************************/
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "bsp_usart.h"
#include "bsp_L298N.h"
/************************************************
函数名称 : main
功 能 : 主函数
参 数 : 无
返 回 值 : 无
作 者 : LC
*************************************************/
int main(void)
{
int i = 0;
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); // 优先级分组
systick_config(); // 滴答定时器初始化
usart_gpio_config(9600U); // 串口0初始化
L298N_Init(10,8000);
while(1)
{
i += 100;
if( i > 8000 ) i = 0;
AO_Control(0,i);
BO_Control(1,i);
delay_1ms(50);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
移植现象:两个电机速度由慢变快的正反转。
移植成功示例,见文件 4.7.4-1 。
文件 4.7.4-1 移植成功示例
通过网盘分享的文件:立创·梁山派GD32F470ZGT6开发板【模块移植手册代码】
链接: https://pan.baidu.com/s/1pp44yjD1Dhh7U9iZ2a11IA 提取码: LCKF