我的 CSDN 用于记录我的学习历程,以便有时忘记了还能继续查找,同时也希望能够结识更多的朋友,共同学习,互相帮助,共同进步。
要制作一个智能小车,最基础的是让小车动起来,因此驱动电机尤为重要。随着所需功能的增多,不可能将所有代码都写在主函数里面。同样,智能小车是由各个模块将所得到的数据传输回单片机,再由单片机控制电机 PWM 输出以控制电机。为了避免主函数过于复杂,以及在修改代码过程中因改错而导致完全无法使用,对每个模块的代码进行封装就很有必要了。今天所介绍的便是对电机代码的封装。
对于cubmx的配置请参考我的上一篇博客,按照那个配置就可以,我这里使用的是stm32f411ret6,对于其他的也可以模仿配置使用,可能需要改一下代码中的引脚。
上面是我的配置,引脚可以自己选,修改代码里的引脚即可。
首先从keil5中增加一个文件夹,右击项目,选择Add Group
之后点击两次新创建的文件夹,改名为BSP.同时点开cubmx生成文件里的Drivers
在Drivers里面新建一个文件夹,命名为BSP
右击BSP,点击第二个。
分别选择生成.c和.h文件,并命名
之后点开MDK-ARM
将生成的.c文件和.h文件复制到BSP中
再复制完成后,点击魔术棒按钮
点进去选择c/c++,并点击三个点
之后将刚才创建的文件选择进去,记住一定要点到最后,不要出现中文路径
点击选择文件夹之后,一直点击ok
再点开魔术棒,选择dubug,2是选择所用的转接器,之后点击settings
进入settings里面选择flash download,将reset and run勾选,点击确定,如果programming algorithm里面没任何东西,需要点击Add添加闪存,每种型号不一样
之后就是代码部分
首先是motor.c
#include "stm32f4xx_hal.h" // Device header
#include "motor.h"
#include "gpio.h"
#include "tim.h"
/**
* @brief 使智能小车停止
*/
void Car_Stop()
{
motorControlL(1,0); // 控制左电机停止
motorControlR(1,0); // 控制右电机停止
}
/**
* @brief 使智能小车前进
* @param Speed 前进速度
*/
void Car_Forward(uint16_t Speed)
{
motorControlL(1,Speed); // 控制左电机正转,设置速度
motorControlR(1,Speed); // 控制右电机正转,设置速度
}
/**
* @brief 使智能小车后退
* @param Speed 后退速度
*/
void Car_Backward(uint16_t Speed)
{
motorControlL(0,Speed); // 控制左电机反转,设置速度
motorControlR(0,Speed); // 控制右电机反转,设置速度
}
/**
* @brief 使智能小车向左转
* @param Speed 转弯速度
*/
void Car_TurnLeft(uint16_t Speed)
{
motorControlL(0,Speed); // 控制左电机反转,设置速度
motorControlR(1,Speed); // 控制右电机正转,设置速度
}
/**
* @brief 使智能小车向右转
* @param Speed 转弯速度
*/
void Car_TurnRight(uint16_t Speed)
{
motorControlL(1,Speed); // 控制左电机正转,设置速度
motorControlR(0,Speed); // 控制右电机反转,设置速度
}
/*****************************************************/
// Dir = 1,电机往车头方向转动(正转)
// Dir = 0,电机往车尾 方向转动(反转)
// PA0->TIM2_CH1->MOTOR1A->Backward
// PA1->TIM2_CH2->MOTOR1B->Forward
/**
* @brief 控制左电机
* @param Dir 电机转动方向(1 为正转,0 为反转)
* @param Speed 电机速度
*/
void motorControlL(uint8_t Dir, uint16_t Speed)
{
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); // 启动 TIM2 通道 2 的 PWM 输出
/* 根据方向设置 IN1 和 IN2 引脚 */
HAL_GPIO_WritePin(GPIOC, BIN1_Pin, (Dir & 0x01)); // 设置左电机 IN1 引脚状态
HAL_GPIO_WritePin(GPIOC, BIN2_Pin, ((Dir & 0x01) ^ 0x01)); // 设置左电机 IN2 引脚状态
/* 设置 PWM 引脚以控制速度 */
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, Speed); // 设置 TIM2 通道 2 的比较值以控制速度
if (Speed>=1000) Speed = 1000; // 限制速度最大值为 1000
if (Dir)
{
motorControlL(Dir,0); // 处理正转时的特殊情况
motorControlR(Dir,Speed);
}
else if (!Dir)
{
motorControlL(Dir,0); // 处理反转时的特殊情况
motorControlL(Dir,Speed);
}
}
// PA2->TIM2_CH3->MOTOR2A->Backward
// PA3->TIM2_CH4->MOTOR2B->Forward
/**
* @brief 控制右电机
* @param Dir 电机转动方向(1 为正转,0 为反转)
* @param Speed 电机速度
*/
void motorControlR(uint8_t Dir, uint16_t Speed)
{
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); // 启动 TIM2 通道 1 的 PWM 输出
/* 根据方向设置 IN1 和 IN2 引脚 */
HAL_GPIO_WritePin(GPIOC, AIN1_Pin, (Dir & 0x01)); // 设置右电机 IN1 引脚状态
HAL_GPIO_WritePin(GPIOC, AIN2_Pin, ((Dir & 0x01) ^ 0x01)); // 设置右电机 IN2 引脚状态
/* 设置 PWM 引脚以控制速度 */
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, Speed); // 设置 TIM2 通道 1 的比较值以控制速度
if (Speed>=1000) Speed = 1000; // 限制速度最大值为 1000
if (Dir)
{
motorControlL(Dir,0); // 处理正转时的特殊情况
motorControlR(Dir,Speed);
}
else if (!Dir)
{
motorControlL(Dir,0); // 处理反转时的特殊情况
motorControlR(Dir,Speed);
}
}
对于motor.h
#ifndef _MOTOR_H_
#define _MOTOR_H_
#include "main.h"
#include "tim.h"
void Motor_Init(void);
void Car_Stop(void);
void Car_Forward(uint16_t Speed);
void Car_Backward(uint16_t Speed);
void Car_TurnLeft(uint16_t Speed);
void Car_TurnRight(uint16_t Speed);
void Car_TransLeft(uint16_t Speed);
void Car_TransRight(uint16_t Speed);
void motorControlL(uint8_t Dir, uint16_t Speed);
void motorControlR(uint8_t Dir, uint16_t Speed);
#endif
之后在main.c中引用所创建头文件
/* USER CODE BEGIN Includes */
#include "motor.h"
/* USER CODE END Includes */
在while循环中输入你所需要的操作
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE BEGIN 3 */
Car_Forward(500);
HAL_Delay(5000);
Car_Backward(500);
HAL_Delay(5000);
Car_TurnLeft(500);
HAL_Delay(5000);
Car_TurnRight(500);
HAL_Delay(5000);
Car_Stop();
}
/* USER CODE END 3 */
}
然后对设备进行连线,烧录代码进行测试,此次记录结束。其他模块也可以仿造此步骤进行封装,之后调用头文件即可。