描述
这一篇文章紧接上一篇文章stm32按钮控制直流有刷电机(一)(Develop文章3.1)的内容,上一篇文章利用CubeMX对stm32已经进行了配置
这一篇文章将利用代码开发,产生PWM信号完成按钮控制直流有刷减速电机的过程。
研发平台:淘宝上购买的野火店铺的一款单片机,名字叫骄阳开发板,核心芯片是
stm32F407IGT6
电机及驱动板:电机使用的是一款直流有刷减速电机。电机驱动板也是野火家的,型号是L298N电机驱动板
研发步骤
-
我们要实现的目的,是按键控制电机的运转。我们的设置是这样的,5个设置管脚的按钮分别负责:电机使能、电机失能、电机速度加快、电机速度减小、电机运转方向转换。我们在生成的工程中,进行一些功能性的代码添加。
在main.c
中的头文件用户自定义添加部分#include <stdio.h> #include <string.h> #define abs(x) ((x)>0?(x):-(x)) #define MOTOR_SPEED_MAX 5500 #define MOTOR_SPEED_MIN 1000 #define MOTOR_SPEED_INITIAL 2000 #define MOTOR_SPEED_DELTA 100
我们定义了几个宏定义,
MOTOR_SPEED_MAX
、MOTOR_SPEED_MIN
、MOTOR_SPEED_INITIAL
和MOTOR_SPEED_DELTA
分别代表了电机的最大速度、最小速度、初始速度和变化速度。可以看出它们的值,都是和我们之前在CubeMX设置的重装载值是相关的,这些值都是PWM值。最大速度的最小被设置为了5500和1000,我们之后再来讨论
-
在
main.c
中的主函数运行之前的自定义部分,用于捕捉按键事件int get_key_status(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { if (HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) == GPIO_PIN_SET) { while(HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) == GPIO_PIN_SET); return 1; } else { return 0; } }
按键被摁下后进入循环,放开后,返回1;否则返回0。
-
在
main.c
中的主函数运行中,while函数运行之前的自定义部分,用于初始设置HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2); int motor_1_direction = 1; int motor_1_speed_current = MOTOR_SPEED_INITIAL; printf("hello FUXI ROBOT!\n");
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
和HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
的功能,就是使能电机的1通道和2通道 -
在
main.c
中的主函数运行中的while函数中的自定义部分,用于处理按钮被摁下后的电机控制代码。这段代码是包在while函数里的,我的工程下while函数中只有以下的部分。if (get_key_status(GPIOA, GPIO_PIN_0)) // enable motor { HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2); if (motor_1_direction == 1) { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, motor_1_speed_current); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0); } else { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, abs(motor_1_speed_current)); } printf("motor 1 on\n"); printf("motor 1 speed up, current speed:%d, direction:%d\n", motor_1_speed_current, motor_1_direction); } if (get_key_status(GPIOG, GPIO_PIN_2)) // disable motor { HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_1); HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_2); motor_1_speed_current = MOTOR_SPEED_INITIAL * motor_1_direction; printf("motor 1 off\n"); } if (get_key_status(GPIOC, GPIO_PIN_13)) // motor speed up { motor_1_speed_current = motor_1_speed_current + MOTOR_SPEED_DELTA * motor_1_direction; if (abs(motor_1_speed_current) >= abs(MOTOR_SPEED_MAX)) { motor_1_speed_current = MOTOR_SPEED_MAX * motor_1_direction; } if (abs(motor_1_speed_current) <= abs(MOTOR_SPEED_MIN)) { motor_1_speed_current = MOTOR_SPEED_MIN * motor_1_direction; } if (motor_1_direction == 1) { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, motor_1_speed_current); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0); } else { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, abs(motor_1_speed_current)); } printf("motor 1 speed up, current speed:%d, direction:%d\n", motor_1_speed_current, motor_1_direction); } if (get_key_status(GPIOG, GPIO_PIN_3)) // motor speed down { motor_1_speed_current = motor_1_speed_current - MOTOR_SPEED_DELTA * motor_1_direction; if (abs(motor_1_speed_current) >= abs(MOTOR_SPEED_MAX)) { motor_1_speed_current = MOTOR_SPEED_MAX * motor_1_direction; } if (abs(motor_1_speed_current) <= abs(MOTOR_SPEED_MIN)) { motor_1_speed_current = MOTOR_SPEED_MIN * motor_1_direction; } if (motor_1_direction == 1) { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, motor_1_speed_current); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0); } else { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, abs(motor_1_speed_current)); } printf("motor 1 speed down, current speed:%d, direction:%d\n", motor_1_speed_current, motor_1_direction); } if (get_key_status(GPIOG, GPIO_PIN_4)) // motor direction reverse { motor_1_direction = - motor_1_direction; motor_1_speed_current = -motor_1_speed_current; if (motor_1_direction == 1) { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, motor_1_speed_current); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0); } else { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, abs(motor_1_speed_current)); } printf("motor 1 direction reverse, current speed:%d, direction:%d\n", motor_1_speed_current, motor_1_direction); }
代码阅读起来很容易,明显的每个按钮的功能分别被实现了。只说一点`__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, motor_1_speed_current);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0);` 这两句就是通道1输出PWM,电机正转;else语句中写的,就是通道2输出PWM,电机反转。
- 除此之外,和之前读取串口数据一样,我们还需要在
usart.c
中的头文件用户定义部分添加#include "stm32f4xx_hal.h" #include <stdio.h>
在`usart.c`用户代码部分添加
```c
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
```
- 编译并将代码下载到单片机上。
连接说明
代码说完了,接下来我们来说一下,配合本篇文章所提到的工程,完成任务的管脚连接。根据步骤4,我们设置了PWM的单片机输出管脚,打开本工程的CubeMX,我们可以看到TIm1的PWM波生成通道CH1和CH2的输出管脚分别是PE9和PE11。
连接单片机——驱动板:我们首先将,单片机的PE9、PE11连接到L298N电机驱动板上的PWM1和PWM2管脚上(L298N上还有PWM3和PWM4管脚,下一篇用到双电机时我再进行讲解),将单片机上的GND管脚连接到L298N驱动板的GND上。驱动板上的EMA和ENB连接到5V上(我的板子上有两个跳帽,已经帮我连接好了)。完成了单片机到驱动板的连接
连接驱动板——直流电机:我使用的直流电机,上面引出了六根线。根据电机说明,我知道其中的4条是编码器的线,这里我们暂时不用。剩下的两条线,管脚上分别写着“M+”和“M-”,这就是直流电机的两根控制线了。我们将电机的“M+”连接到驱动板上电机A输出的1号管脚上,将电机的“M-”连接到驱动板上电机A输出的2号管脚上。完成了驱动板到电机的连接
连接驱动板——直流24V电源,驱动板上的“+”连接到24V电源正极,“-”连接到24V电源负极。
实验现象
我们会发现,按下不同的按钮可以实现不同的电机控制功能,有对应的输出提示,同时电机翻转后加速减速,是与现实一致的。
总结
本文讲述了如何利用CubeMX,对单片机进行设置,实现了按钮控制直流有刷电机的功能。接下来一篇文章,我们来进一步的学习直流电机的控制,包括这篇文章还没有解释清楚的参数设置问题。
最终下一篇文章将完成双直流电机的控制。
评论(0)
您还未登录,请登录后发表或查看评论