N20带编码器减速电机是一种小型的直流电机,通常用于一些较小的电子设备和机器人,它可以通过减速器(齿轮传动)来提供更大的扭矩和更低的速度。编码器是一种用于记录电机旋转角度和速度的传感器,可以帮助控制电机的位置和速度。因此,带编码器的N20减速电机常用于需要准确控制位置和旋转角度的应用,比如机械臂、小车和舵机等。通过编码器的反馈信号,可以精确地控制电机的运动,从而提高机器人或设备的精度和稳定性。
一、模块来源
二、规格参数
驱动电压:根据采购的电机确定,比如我买的是6V300转
驱动电流:根据电机输入电压决定
控制方式:PWM
以上信息见厂家资料文件
三、移植过程
我们的目标是将例程移植至MSPM0G3507开发板上【能够控制电机旋转速度的功能】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
1、查看资料
直流有刷减速电机,转速越高,力量越小。转速越小,力量越大。
2、引脚选择
我们使用的是DRV8833芯片驱动的电路,所以我们需要4个PWM通道和4个编码输入通道。
VCC | 3V3 |
GND | GND |
LENCODE1 | PA27 |
LENCODE2 | PA26 |
RENCODE1 | PA31 |
RENCODE2 | PA28 |
PWML1 | PA25 |
PWML2 | PA24 |
PWMR1 | PA08 |
PWMR2 | PB04 |
接下来我们配置 SYSCONFIG
- 双击 empty.syscfg 文件,打开它。
- 点击 ADD 添加GPIO配置
- 添加四个引脚
- 配置GPIO
- 添加Timer
- 配置Timer
- 添加PWM
添加2个
- 配置PWM
Ctrl + S
保存配置文件然后点击编译(可能会报错,我们不用管!)
- 然后我们所有设定的引脚和功能就会在 ti_msp_dl_config.h 中定义。因为这个文件我们包含进了 board.h 所以我们只需要引用 board.h 即可。【这里的 board.h 就充当了芯片头文件的作用】
3、代码编写
我们在 BSP文件夹
中新建inc和src文件夹,新建两个文件 bsp_motor_hallencoder.c
和 bsp_motor_hallencoder.h
,并且将头文件路径添加到编译器中。
在文件bsp_motor_hallencoder.c中,编写如下代码。
c
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#include "bsp_motor_hallencoder.h"
static volatile Encoder Encoder_A;
static volatile Encoder Encoder_B;
/******************************************************************
* 函 数 名 称:Motor_Init
* 函 数 说 明:电机与编码器初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:无
******************************************************************/
void Motor_Init(void)
{
//编码器引脚外部中断
NVIC_ClearPendingIRQ(ENCODER_INT_IRQN);
NVIC_EnableIRQ(ENCODER_INT_IRQN);
//定时器中断
NVIC_ClearPendingIRQ(TIMER_0_INST_INT_IRQN);
NVIC_EnableIRQ(TIMER_0_INST_INT_IRQN);
lc_printf("Motor initialized successfully\r\n");
}
/******************************************************************
* 函 数 名 称:Motor_Set_PWM
* 函 数 说 明:左右电机速度控制
* 函 数 形 参:pwma左电机PWM值 pwmb右电机PWM值
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:PWM值范围0-9999
******************************************************************/
void Motor_Set_PWM(int pwma,int pwmb)
{
if(pwma > 0)
{
DL_TimerG_setCaptureCompareValue(PWM_0_INST,ABS(pwma),GPIO_PWM_0_C3_IDX);
DL_TimerG_setCaptureCompareValue(PWM_1_INST,0,GPIO_PWM_1_C1_IDX);
}
else
{
DL_TimerG_setCaptureCompareValue(PWM_0_INST,0,GPIO_PWM_0_C3_IDX);
DL_TimerG_setCaptureCompareValue(PWM_1_INST,ABS(pwma),GPIO_PWM_1_C1_IDX);
}
if(pwmb > 0)
{
DL_TimerG_setCaptureCompareValue(PWM_0_INST,ABS(pwma),GPIO_PWM_0_C0_IDX);
DL_TimerG_setCaptureCompareValue(PWM_1_INST,0,GPIO_PWM_1_C0_IDX);
}
else
{
DL_TimerG_setCaptureCompareValue(PWM_0_INST,0,GPIO_PWM_0_C0_IDX);
DL_TimerG_setCaptureCompareValue(PWM_1_INST,ABS(pwma),GPIO_PWM_1_C0_IDX);
}
}
/******************************************************************
* 函 数 名 称:Motor_Stop
* 函 数 说 明:电机停止
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:无
******************************************************************/
void Motor_Stop(void)
{
DL_TimerG_setCaptureCompareValue(PWM_0_INST,9999,GPIO_PWM_0_C3_IDX);
DL_TimerG_setCaptureCompareValue(PWM_1_INST,9999,GPIO_PWM_1_C1_IDX);
DL_TimerG_setCaptureCompareValue(PWM_0_INST,9999,GPIO_PWM_0_C0_IDX);
DL_TimerG_setCaptureCompareValue(PWM_1_INST,9999,GPIO_PWM_1_C0_IDX);
}
/******************************************************************
* 函 数 名 称:Motor_Get_Encoder
* 函 数 说 明:获取编码器的值
* 函 数 形 参:dir=0获取左轮编码器值 dir=1获取右轮编码器值
* 函 数 返 回:返回对应的编码器值
* 作 者:LCKFB
* 备 注:无
******************************************************************/
int Motor_Get_Encoder(int dir)
{
if( !dir )
return Encoder_A.Obtained_Get_Encoder_Count;
return Encoder_B.Obtained_Get_Encoder_Count;
}
/*******************************************************
函数功能:外部中断模拟编码器信号
入口函数:无
返回 值:无
***********************************************************/
void GROUP1_IRQHandler(void)
{
uint32_t gpio_interrup = 0;
//获取中断信号
gpio_interrup = DL_GPIO_getEnabledInterruptStatus(ENCODER_PORT,ENCODER_E1A_PIN|ENCODER_E1B_PIN|ENCODER_E2A_PIN|ENCODER_E2B_PIN);
// encoderA
if((gpio_interrup & ENCODER_E1A_PIN)==ENCODER_E1A_PIN)
{
if(!DL_GPIO_readPins(ENCODER_PORT,ENCODER_E1B_PIN))
{
Encoder_A.Should_Get_Encoder_Count--;
}
else
{
Encoder_A.Should_Get_Encoder_Count++;
}
}
else if((gpio_interrup & ENCODER_E1B_PIN)==ENCODER_E1B_PIN)
{
if(!DL_GPIO_readPins(ENCODER_PORT,ENCODER_E1A_PIN))
{
Encoder_A.Should_Get_Encoder_Count++;
}
else
{
Encoder_A.Should_Get_Encoder_Count--;
}
}
// encoderB
if((gpio_interrup & ENCODER_E2A_PIN)==ENCODER_E2A_PIN)
{
if(!DL_GPIO_readPins(ENCODER_PORT,ENCODER_E2B_PIN))
{
Encoder_B.Should_Get_Encoder_Count--;
}
else
{
Encoder_B.Should_Get_Encoder_Count++;
}
}
else if((gpio_interrup & ENCODER_E2B_PIN)==ENCODER_E2B_PIN)
{
if(!DL_GPIO_readPins(ENCODER_PORT,ENCODER_E2A_PIN))
{
Encoder_B.Should_Get_Encoder_Count++;
}
else
{
Encoder_B.Should_Get_Encoder_Count--;
}
}
DL_GPIO_clearInterruptStatus(ENCODER_PORT,ENCODER_E1A_PIN|ENCODER_E1B_PIN|ENCODER_E2A_PIN|ENCODER_E2B_PIN);
}
//电机编码器脉冲计数
void TIMER_0_INST_IRQHandler(void)
{
//编码器速度计算
if( DL_TimerG_getPendingInterrupt(TIMER_0_INST) == DL_TIMER_IIDX_ZERO )
{
/* 两个电机安装相反,所以编码器值也要相反 */
Encoder_A.Obtained_Get_Encoder_Count = Encoder_A.Should_Get_Encoder_Count;
Encoder_B.Obtained_Get_Encoder_Count = -Encoder_B.Should_Get_Encoder_Count;
/* 编码器计数值清零 */
Encoder_A.Should_Get_Encoder_Count = 0;
Encoder_B.Should_Get_Encoder_Count = 0;
}
}
1
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
175
176
177
178
179
180
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
175
176
177
178
179
180
在文件bsp_motor_hallencoder.h中,编写如下代码。
c
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#ifndef __BSP_MOTOR_HALLENCODER_H__
#define __BSP_MOTOR_HALLENCODER_H__
#include "board.h"
// 获得绝对值
#define ABS(a) (a>0 ? a:(-a))
typedef struct{
int Should_Get_Encoder_Count; // 将要获得的编码器计数
int Obtained_Get_Encoder_Count; // 得到的编码器的计数
}Encoder;
void Motor_Init(void);
int Motor_Get_Encoder(int dir);
void Motor_Set_PWM(int pwma,int pwmb);
void Motor_Stop(void);
#endif
1
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
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
四、移植验证
在empty.c中输入代码如下:
c
#include "ti_msp_dl_config.h"
#include "board.h"
#include "bsp_motor_hallencoder.h"
int main(void)
{
int a = -500;
int b = -500;
SYSCFG_DL_init();
Motor_Init();
lc_printf("\nDemo Start .....\r\n");
while (1)
{
Motor_Set_PWM(a,b);
a += 10;
b += 10;
if(a > 9000 || b > 9000)
{
a = -500;
b = -500;
Motor_Stop();
lc_printf("\nMotor_Stop !!!\r\n");
delay_ms(2000);
}
lc_printf("[ %d ] | [ %d ]\r\n",Motor_Get_Encoder(0),Motor_Get_Encoder(1));
delay_ms(20);
}
}
1
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
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
【代码下载】
- 跳转到
下载中心
去下载CCS模块移植代码:【点击跳转🚀】