该模块相对于传统的L298N效率上提高很多,体积上也大幅度减少,在额定范围内,芯片基本不发热,当然也就显得更加娇贵,所以我们建议有一定动手能力的朋友使用,接线的时候务必细心细心再细心,注意正负极性。
模块来源
规格参数
VM电机电压:< 12V
VCC芯片电压:2.7~5.5V
输出电流:1A
控制方式:PWM
以上信息见厂家资料文件
移植过程
我们的目标是将例程移植至开发板上【能够控制电机旋转速度的功能】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
查看资料
STBY口接单片机的IO口,STBY置0电机全部停止,置1才能工作。STBY置1后通过AIN1、AIN2、BIN1、BIN2 来控制正反转。
这里将STBY接入3.3V,让其一直为高电平,后续的电机停止控制通过IN1与IN2进行控制。
其中A端(AIN1与AIN2)只能控制AO1与AO2端。B端(BIN1与BIN2)只能控制BO1与BO2端。因此是双路电机驱动。
引脚选择
PWMA为控制A端电机速度的引脚,通过PWM的占空比大小控制电机速度。这里选择PA6,其有复用功能TIMER3_CH1,意为定时器3的PWM通道1。
这里将STBY接入3.3V,让其一直为高电平,后续的电机停止控制通过IN1与IN2进行控制。
这里选择的引脚见引脚接线表
代码移植
下载为大家准备的驱动代码文件夹,复制到自己工程中\luban-lite\application\rt-thread\helloworld\user-bsp
文件夹下
提示
如果未找到 user-bsp
这个文件夹,说明你未进行模块移植的前置操作。请转移到手册使用必要操作(点击跳转)中进行必要的配置操作!!!
接下来打开自己的工程,开始修改Kconfig文件。
1、在 VSCode 中打开 application\rt-thread\helloworld\Kconfig 文件
2、在该文件的 #endif
前面添加该模块的 Kconfig路径语句
# TB6612电机驱动模块
source "application/rt-thread/helloworld/user-bsp/tb6612-motor-drive-module/Kconfig"
2
menuconfig操作
1、我们 双击 luban-lite
文件夹下的 win_env.bat
脚本打开env工具:
2、输入以下命令列出所有可用的默认配置:
scons --list-def
3、选择 d13x_JLC_rt-thread_helloworld
这个配置!这个是我们衡山派开发板的默认配置!输入以下命令即可:
scons --apply-def=7
或者
scons --apply-def=d13x_JLC_rt-thread_helloworld_defconfig
这两个命令作用是一样的,一个是 文件名 ,一个是 编号 !!!
4、输入以下命令进入menuconfig菜单
scons --menuconfig
进入以下界面:
5、选中 Porting code using the LCKFB module
按
Y
选中按
N
取消选中方向键
左右
调整 最下面菜单的选项方向键
上下
调整 列表的选项
回车
执行最下面菜单的选项
6、回车进入 Porting code using the LCKFB module
菜单
7、按方向键 上下
选中 Using TB6612 Motor drive module
后按 Y
键,看到前面括号中出现一个 *
号,就可以下一步了。
8、按方向键 左右
选中 <Save>
然后一路回车
,然后 退出
即可
编译
我们 保存并退出menuconfig菜单 之后,输入以下命令进行编译:
scons
或
scons -j16
-j 用来选择参与编译的核心数: 我这里是选择16
大家可以根据自己的电脑来选择
核心越多编译越快
如果写的数量高于电脑本身,那么就自动按照最高可用的来运行!
镜像烧录
编译完成之后会在 \luban-lite\output\d13x_JLC_rt-thread_helloworld\images
文件夹下生成一个 d13x_JLC_v1.0.0.img
镜像文件!
然后我们烧录镜像,具体的教程请查看:镜像烧录(点击跳转🚀)
到这里完成了,请移步到 最后一节 进行移植验证。
工程代码解析
bsp_tb6612.c
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <sys/time.h>
#include <rtthread.h>
#include "hal_adcim.h"
#include "rtdevice.h"
#include "aic_core.h"
#include "aic_log.h"
#include "hal_gpai.h"
#include <stdio.h>
#include "aic_hal_gpio.h"
#include "bsp_tb6612.h"
#define TB6612_DEV_NAME "pwm"
#define PWM1 1
#define TB6612_PWMA_CHANNEL PWM1
#define TB6612_AIN1_PIN rt_pin_get("PE.14")
#define TB6612_AIN2_PIN rt_pin_get("PE.12")
#define TB6612_AIN1_SET_LEVEL(x) rt_pin_write(TB6612_AIN1_PIN, x ? PIN_HIGH : PIN_LOW)
#define TB6612_AIN2_SET_LEVEL(x) rt_pin_write(TB6612_AIN2_PIN, x ? PIN_HIGH : PIN_LOW)
static struct rt_device_pwm *pwm_dev = RT_NULL;
static uint32_t tb6612_period = 0;
static uint32_t tb6612_pulse = 0;
/**********************************************************
* 函 数 名 称:TB6612_GPIO_Init
* 函 数 功 能:AIN-GPIO进行初始化
* 传 入 参 数:无
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:LP
**********************************************************/
static void TB6612_GPIO_Init()
{
rt_pin_mode(TB6612_AIN1_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(TB6612_AIN2_PIN, PIN_MODE_OUTPUT);
TB6612_AIN1_SET_LEVEL(0);
TB6612_AIN2_SET_LEVEL(0);
}
/**********************************************************
* 函 数 名 称:TB6612_Init
* 函 数 功 能:配置tb6612进行初始化
* 传 入 参 数:periodPWM - 周期时间 (单位纳秒 ns)
* pulse - PWM 脉冲宽度时间 (单位纳秒 ns)
* 函 数 返 回:RT_EOK成功 -RT_ERROR失败
* 作 者:LCKFB
* 备 注:LP
**********************************************************/
int TB6612_Init(uint32_t period, uint32_t pulse)
{
int ret = 0;
/* 查找设备 */
pwm_dev = (struct rt_device_pwm *)rt_device_find(TB6612_DEV_NAME);
if (pwm_dev == NULL)
{
LOG_E("can't find %s device!",TB6612_DEV_NAME);
return -RT_ERROR;
}
/* 不大于周期时间 */
if(pulse >= period)
{
pulse = period - 1;
}
/* 保存初始化数值 */
tb6612_period = period;
tb6612_pulse = pulse;
/* 设置PWM的周期和脉冲宽度 */
ret = rt_pwm_set(pwm_dev, TB6612_PWMA_CHANNEL, period, pulse);
if(ret != RT_EOK)
{
LOG_E("%s--->rt_pwm_set failed !!",__FUNCTION__);
return -RT_ERROR;
}
/* 使能设备 */
ret = rt_pwm_enable(pwm_dev, TB6612_PWMA_CHANNEL);
if(ret != RT_EOK)
{
LOG_E("%s--->rt_pwm_enable failed !!",__FUNCTION__);
return -RT_ERROR;
}
TB6612_GPIO_Init();
return RT_EOK;
}
/**********************************************************
* 函 数 名 称:TB6612_DeInit
* 函 数 功 能:清除tb6612初始化
* 传 入 参 数:无
* 函 数 返 回:RT_EOK成功 -RT_ERROR失败
* 作 者:LCKFB
* 备 注:LP
**********************************************************/
int TB6612_DeInit(void)
{
if(RT_EOK != rt_pwm_disable(pwm_dev, TB6612_PWMA_CHANNEL))
{
LOG_E("%s--->rt_pwm_disable failed !!",__FUNCTION__);
return -RT_ERROR;
}
return RT_EOK;
}
/**********************************************************
* 函 数 名 称:AO_Control
* 函 数 功 能:A端口电机控制
* 传 入 参 数:dir旋转方向 1正转 0反转
* speed旋转速度,范围(0 ~ tb6612_period-1)
* 函 数 返 回:RT_EOK成功 -RT_ERROR失败
* 作 者:LCKFB
* 备 注:LP
**********************************************************/
int AO_Control(uint8_t dir, uint32_t speed)
{
if(speed >= tb6612_period)
{
speed = tb6612_period - 1;
}
if( dir == 1 )
{
TB6612_AIN1_SET_LEVEL(0);
TB6612_AIN2_SET_LEVEL(1);
}
else
{
TB6612_AIN1_SET_LEVEL(1);
TB6612_AIN2_SET_LEVEL(0);
}
/* 设置PWM的周期和脉冲宽度 */
if(RT_EOK != rt_pwm_set(pwm_dev, TB6612_PWMA_CHANNEL, tb6612_period, speed))
{
LOG_E("%s--->rt_pwm_set failed !!",__FUNCTION__);
return -RT_ERROR;
}
return RT_EOK;
}
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
bsp_tb6612.h
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#ifndef __BSP_TB6612_H__
#define __BSP_TB6612_H__
#include "stdio.h"
int TB6612_Init(uint32_t period, uint32_t pulse);
int TB6612_DeInit(void);
int AO_Control(uint8_t dir, uint32_t speed);
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Kconfig
这个是一个menuconfig中的选项,如果在菜单中选中该选项,就会在rtconfig.h
中定义一个语句,用来if判断条件编译之类的。
config LCKFB_TB6612_MOTOR_DRIVE_MODULE
bool "Using TB6612 Motor drive module"
select AIC_USING_PWM1
default n
help
More information is available at: https://wiki.lckfb.com/
2
3
4
5
6
SConscript
自动化构建文件,如果定义了 LCKFB_TB6612_MOTOR_DRIVE_MODULE
和 USING_LCKFB_TRANSPLANT_CODE
就自动编译当前目录下的文件!!
Import('RTT_ROOT')
Import('rtconfig')
import rtconfig
from building import *
cwd = GetCurrentDir()
CPPPATH = [cwd]
src = []
if GetDepend('LCKFB_TB6612_MOTOR_DRIVE_MODULE') and GetDepend('USING_LCKFB_TRANSPLANT_CODE'):
src = Glob(os.path.join(cwd, '*.c'))
group = DefineGroup('lckfb-tb6612-motor-drive-module', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
test_tb6612_motor_drive_module.c
这个文件定义了一个处理TB6612电机驱动模块的线程,初始化了TB6612模块的板级支持包(BSP),并设置了线程的优先级、栈大小和时间片。
线程的主要任务是控制TB6612模块输出PWM信号,以控制电机转速和方向。以下是代码中的关键点:
THREAD_PRIORITY
、THREAD_STACK_SIZE
和THREAD_TIMESLICE
分别定义了线程的优先级、栈大小和时间片。tb6612_thread
是线程控制块的指针,初始为RT_NULL
。tb6612_thread_entry
是线程的入口函数,它执行TB6612模块的初始化、PWM信号输出控制,并在循环中提示用户如何退出线程。TB6612_Init
函数用于初始化TB6612电机驱动模块,设置PWM信号的周期和脉冲宽度。AO_Control
函数用于控制TB6612模块输出PWM信号,参数flag
用于控制电机的方向,i
用于控制电机的速度。aicos_mdelay
函数用于实现毫秒级的延时。LOG_E
宏用于打印错误信息。test_tb6612_module
函数用于创建并启动线程。MSH_CMD_EXPORT
宏用于将函数导出为命令行接口,使得用户可以在命令行中直接调用这些函数。
在 tb6612_thread_entry
函数中,首先调用 TB6612_Init
初始化模块,然后进入一个无限循环,循环中通过 AO_Control
函数输出PWM信号,并通过 flag
变量切换电机的方向。循环中还会检查是否需要提示用户退出命令。
test_tb6612_module
函数用于创建并启动 tb6612_thread
线程。
用户可以通过在命令行中输入 test_tb6612_module
来启动TB6612电机驱动模块的测试线程。这个线程会执行上述的操作,并在控制台上打印退出命令的提示。
test_exit_tb6612_module
函数用于退出TB6612电机驱动模块的测试线程。它首先尝试删除线程,然后调用 TB6612_DeInit
反初始化模块,并打印退出成功的消息。
用户可以通过在命令行中输入 test_exit_tb6612_module
来退出TB6612电机驱动模块的测试线程。如果退出成功,控制台上会显示相应的成功消息。如果退出失败,会打印错误信息。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <sys/time.h>
#include <rtthread.h>
#include "rtdevice.h"
#include "aic_core.h"
#include "aic_hal_gpio.h"
#include "bsp_tb6612.h"
#define THREAD_PRIORITY 25 // 线程优先级
#define THREAD_STACK_SIZE 4096 // 线程大小
#define THREAD_TIMESLICE 25 // 时间片
static rt_thread_t tb6612_thread = RT_NULL; // 线程控制块
// 线程入口函数
static void tb6612_thread_entry(void *param)
{
int while_count = 1;
uint32_t i = 0;
uint8_t flag = 0;
uint32_t period = 1000000; // 单位ns
uint32_t pulse = 0; // 单位ns
/* TB6612初始化 */
if(RT_EOK != TB6612_Init(period, pulse))
{
LOG_E("Failed to TB6612_Init!!");
}
while(while_count++)
{
i += 10000;
if(i >= period)
{
i = 0;
flag ^= 1; // 切换flag状态
}
if(RT_EOK != AO_Control(flag, i))
{
LOG_E("Failed to AO_Control!!");
}
// 循环提示
if (while_count >= 1000)
{
while_count = 1;
rt_kprintf("\nType [test_exit_tb6612_module] command to exit \n");
rt_kprintf("Note: Pressing [TAB] as you type will autocomplete the command\n");
}
rt_thread_mdelay(100);
}
}
static void test_tb6612_module(int argc, char **argv)
{
/* 创建线程,名称是 tb6612_thread,入口是 tb6612_thread_entry */
tb6612_thread = rt_thread_create("tb6612_thread",
tb6612_thread_entry, RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
/* 如果获得线程控制块,启动这个线程 */
if (tb6612_thread != RT_NULL)
rt_thread_startup(tb6612_thread);
}
// 导出函数为命令
MSH_CMD_EXPORT(test_tb6612_module, tb6612 module test);
/* 退出函数 */
void test_exit_tb6612_module(void)
{
int ret = rt_thread_delete(tb6612_thread);
if(ret != RT_EOK)
{
LOG_E("failed to rt_thread_delete !!");
return;
}
ret = TB6612_DeInit();
if(ret != RT_EOK)
{
LOG_E("failed to TB6612_DeInit !!");
return;
}
rt_kprintf("\n========tb6612 module exit successful !!========\n");
}
// 导出函数为命令
MSH_CMD_EXPORT(test_exit_tb6612_module, exit tb6612 module test);
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
移植验证
我们使用串口调试,将 USB转TTL模块 连接到衡山派开发板上面!!
具体的教程查看:串口调试(点击跳转🚀)
串口波特率默认为
115200
我们在输入下面的命令运行该模块的线程:
输入的时候按下
TAB键
会进行命令补全!!
test_tb6612_module
模块上电效果:电机速度由慢变快的正反转。