我的第一辆智能小车
提示:小编也是初学者,本文适用于想完成一个基础智能四轮车的初学者,大佬还请勿喷,欢迎各位指出错误的地方
暑假在家无聊,刚好也在学习STM32的HAL库,就想着做个小车巩固自己学到的知识,顺便记录自己所遇到的错误
小编也是现学现写,现已学会变速和红外寻迹,准备做一个蓝牙遥控红外寻迹超声波避障小车
这篇博客讲述的就是如何去制作变速和寻迹小车,
1,相关传感器的介绍
1.1TCRT5000红外寻迹模块的介绍
TCRT5000红外寻迹模块是一种基于红外反射原理的传感器,用于检测和跟踪目标物体的位置。
红外对管传感器
其原理很简单:
// 未碰到黑线(接收到红外光):对应状态 = 0
// 碰到黑线(未接收到红外光):对应状态 = 1
1.2L298N直流电机驱动板
L298N直流电机驱动板是一种常用的双H桥驱动器,可控制直流电机的转动方向和速度,适用于机器人、小车等电机驱动应用。
具体的用法:上一期博客
2.stm32f103c8t6对应功能的引脚分配
具体的引脚分配要根据STM32F103C8T6引脚定义表来分配,这个我会放在文末的资源包里面
可以和我的不一样,这里注意了具有PWM输出比较功能的定时器只有通用和高级定时器,基本定时器是没有这个功能的。
STM32F103C8T6微控制器的定时器资源包括:
- 3个通用定时器(TIM2、TIM3、TIM4)
- 1个高级定时器(TIM1)
- 2个基本定时器(TIM6、TIM7)
总共有6个定时器可供使用。
选用控制电极速度的引脚是PB6/7/8/9
分别对应的是TIM4_CH1/CH2/CH3/CH4
都在一起,方便调试
选择控制正反转的引脚是PA0/1/2/3/4/5/6/7 选择GPIO_Output
轮子 EN IN1 IN2 IN3 IN4
左前轮 PB6 PA0 PA1
右前轮 PB7 PA2 PA3
左后轮 PB8 PA6 PA7
右后轮 PB9 PA4 PA5
寻迹模块的使用引脚是PB0/1/3/4 选择GPIO_input
IN1/2/3/4
3.stm32cubeMX的配置
1.引脚的功能分配
2,RCC外部时钟的配置
这里选择的是外部高速晶振HSE
3,时钟树的配置
这里不懂的强烈推荐去看原子哥的时钟树讲解
4,GPIO的设置以及器宏名
5,SYS的配置,我用的是ST-Link烧录器,这里选择的是Serial Wire
6,Timer的配置
这里是使用了TIM4的四个通道,并将对应的ARR和PSC的值分别设置,不懂的可以看看下面这张图片,这里的ARR的值最好设置为100,使得我们调整CCR(0-100)的值就等同于调整占空比
直流电机的PWM(脉宽调制)频率通常会根据具体的应用和需求而有所不同。然而,一般来说,对于直流电机的PWM控制,频率在几千赫兹到几万赫兹之间是常见的范围。
较高的PWM频率可以提供更精确的控制和速度调节,同时减少噪音和振动。然而,较高的频率可能需要更高的计算和驱动能力。
一般来说,对于直流电机的PWM控制,建议选择频率在5kHz到20kHz之间。这个范围通常能够提供良好的控制性能和较低的噪音水平。我这里设置的是20KHZ,对应的PSC+1=36,ARR+1=100。
7,工程文件夹的配置
上面那个Project的配置就不细说了,这里推荐勾选这个,将.C和.H文件分开管理
最后点击创建文件
观看了上面的内容还是不会配置的建议下载文件资源包,里面有具体的配置文件
4,代码展示部分
注意: 因为大部分代码都是软件生成的,里面有很多注释,这里为了直观就都删除了
需要改动的部分都贴出来了
软件生成的代码别乱删
main.c
#include "main.h"
#include "tim.h"
#include "gpio.h"
#include "motor.h"
void SystemClock_Config(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM4_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_4);
Change_speed(62);//初始速度:速度区间0-100
while (1)
{
/* USER CODE END WHILE */
Sensor(70,65);//寻迹
/* USER CODE BEGIN 3 */
}
}
main.h
#include "stm32f1xx_hal.h"
#include "sensor.h"
motor.c
#include "motor.h"
/* 小车轮子转动驱动代码*/
void Forward(void)
{/* 直行 */
HAL_GPIO_WritePin(motorF1_GPIO_Port,motorF1_Pin,GPIO_PIN_SET);//前左轮-IN1 1
HAL_GPIO_WritePin(motorF2_GPIO_Port,motorF2_Pin,GPIO_PIN_RESET);//前左轮-IN2 0 正转
HAL_GPIO_WritePin(motorF3_GPIO_Port,motorF3_Pin,GPIO_PIN_SET);//前右轮-IN3 1
HAL_GPIO_WritePin(motorF4_GPIO_Port,motorF4_Pin,GPIO_PIN_RESET);//前右轮-IN4 0 正转
/* 因为L298N驱动模块是对相安装 */
HAL_GPIO_WritePin(motorR1_GPIO_Port,motorR1_Pin,GPIO_PIN_RESET);//后左轮-IN3 0
HAL_GPIO_WritePin(motorR2_GPIO_Port,motorR2_Pin,GPIO_PIN_SET);//后左轮-IN4 1 反转
HAL_GPIO_WritePin(motorR3_GPIO_Port,motorR3_Pin,GPIO_PIN_RESET);//后右轮-IN1 0
HAL_GPIO_WritePin(motorR4_GPIO_Port,motorR4_Pin,GPIO_PIN_SET);//后右轮-IN2 1 反转
}
void Backward()
{/* 后行 */
HAL_GPIO_WritePin(motorF1_GPIO_Port,motorF1_Pin,GPIO_PIN_RESET);//前左轮-IN1
HAL_GPIO_WritePin(motorF2_GPIO_Port,motorF2_Pin,GPIO_PIN_SET);//前左轮-IN2
HAL_GPIO_WritePin(motorF3_GPIO_Port,motorF3_Pin,GPIO_PIN_RESET);//前右轮-IN3
HAL_GPIO_WritePin(motorF4_GPIO_Port,motorF4_Pin,GPIO_PIN_SET);//前右轮-IN4
/* 因为L298N驱动模块是对相安装 */
HAL_GPIO_WritePin(motorR1_GPIO_Port,motorR1_Pin,GPIO_PIN_SET);//后左轮-IN3
HAL_GPIO_WritePin(motorR2_GPIO_Port,motorR2_Pin,GPIO_PIN_RESET);//后左轮-IN4
HAL_GPIO_WritePin(motorR3_GPIO_Port,motorR3_Pin,GPIO_PIN_SET);//后右轮-IN1
HAL_GPIO_WritePin(motorR4_GPIO_Port,motorR4_Pin,GPIO_PIN_RESET);//后右轮-IN2
}
void Turn_Left()
{/* 左转 */
HAL_GPIO_WritePin(motorF1_GPIO_Port,motorF1_Pin,GPIO_PIN_RESET);//前左轮-IN1 0
HAL_GPIO_WritePin(motorF2_GPIO_Port,motorF2_Pin,GPIO_PIN_SET);//前左轮-IN2 1 反转
HAL_GPIO_WritePin(motorF3_GPIO_Port,motorF3_Pin,GPIO_PIN_SET);//前右轮-IN3 1
HAL_GPIO_WritePin(motorF4_GPIO_Port,motorF4_Pin,GPIO_PIN_RESET);//前右轮-IN4 0正转
/* 因为L298N驱动模块是对相安装 */
HAL_GPIO_WritePin(motorR1_GPIO_Port,motorR1_Pin,GPIO_PIN_RESET);//后左轮-IN3 0
HAL_GPIO_WritePin(motorR2_GPIO_Port,motorR2_Pin,GPIO_PIN_SET);//后左轮-IN4 1反转
HAL_GPIO_WritePin(motorR3_GPIO_Port,motorR3_Pin,GPIO_PIN_SET);//后右轮-IN1 1
HAL_GPIO_WritePin(motorR4_GPIO_Port,motorR4_Pin,GPIO_PIN_RESET);//后右轮-IN2 0 正转
}
void Turn_Right()
{/* 右转 */
HAL_GPIO_WritePin(motorF1_GPIO_Port,motorF1_Pin,GPIO_PIN_SET);//前左轮-IN1 1
HAL_GPIO_WritePin(motorF2_GPIO_Port,motorF2_Pin,GPIO_PIN_RESET);//前左轮-IN2 0 正转
HAL_GPIO_WritePin(motorF3_GPIO_Port,motorF3_Pin,GPIO_PIN_RESET);//前右轮-IN3 0
HAL_GPIO_WritePin(motorF4_GPIO_Port,motorF4_Pin,GPIO_PIN_SET);//前右轮-IN4 1反转
/* 因为L298N驱动模块是对相安装 */
HAL_GPIO_WritePin(motorR1_GPIO_Port,motorR1_Pin,GPIO_PIN_SET);//后左轮-IN3 1
HAL_GPIO_WritePin(motorR2_GPIO_Port,motorR2_Pin,GPIO_PIN_RESET);//后左轮-IN4 0 正转
HAL_GPIO_WritePin(motorR3_GPIO_Port,motorR3_Pin,GPIO_PIN_RESET);//后右轮-IN1 0
HAL_GPIO_WritePin(motorR4_GPIO_Port,motorR4_Pin,GPIO_PIN_SET);//后右轮-IN2 1 反转
}
void Stopward()
{/* 停止 */
HAL_GPIO_WritePin(motorF1_GPIO_Port,motorF1_Pin,GPIO_PIN_SET);//前左轮-IN1
HAL_GPIO_WritePin(motorF2_GPIO_Port,motorF2_Pin,GPIO_PIN_SET);//前左轮-IN2
HAL_GPIO_WritePin(motorF3_GPIO_Port,motorF3_Pin,GPIO_PIN_SET);//前右轮-IN3
HAL_GPIO_WritePin(motorF4_GPIO_Port,motorF4_Pin,GPIO_PIN_SET);//前右轮-IN4
/* 因为L298N驱动模块是对相安装 */
HAL_GPIO_WritePin(motorR1_GPIO_Port,motorR1_Pin,GPIO_PIN_SET);//后左轮-IN3
HAL_GPIO_WritePin(motorR2_GPIO_Port,motorR2_Pin,GPIO_PIN_SET);//后左轮-IN4
HAL_GPIO_WritePin(motorR3_GPIO_Port,motorR3_Pin,GPIO_PIN_SET);//后右轮-IN1
HAL_GPIO_WritePin(motorR4_GPIO_Port,motorR4_Pin,GPIO_PIN_SET);//后右轮-IN2
}
motor.h
#ifndef __MOTOR_H_
#define __MOTOR_H_
#include "main.h"
void Forward(void);
void Backward(void);
void Turn_Left(void);
void Turn_Right(void);
void Stopward(void);
#endif
sensor.c
这里做出了一些改动,现在小车可以寻直线/曲线/直角转弯
#include "sensor.h"
#include "motor.h"
void Change_speed(uint16_t speed)
{/* 变速 */
// 设置电机速度范围(60-100),越大越快
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, speed);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, speed);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, speed);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_4, speed);
}
void Sensor(uint16_t value,uint16_t pos)
{//value是小车正常行驶时候的速度,POS是转弯时候的速度
if(L1==0&&L2==0&&R1==0&&R2==0)//如果4个全部没有读取黑线,直走; Forward();
{
Change_speed(value);
Forward();
HAL_Delay(5);
}
if(L1==0&&L2==1&&R1==1&&R2==0)//如果2,3读取黑线,直走; Forward();
{
Change_speed(value);
Forward();
HAL_Delay(5);
}
if(L1==0&&L2==1&&R1==0&&R2==0)//如果2读取黑线,左转; Turn_Left();
{
Change_speed(pos);
Turn_Left();
HAL_Delay(5);
}
if(L1==0&&L2==0&&R1==1&&R2==0)//如果3读取黑线,右转; Turn_Right();
{
Change_speed(62);
Turn_Right();
HAL_Delay(5);
}
//大左转
if(L1==1&&(L2==1)&&(R1==0)&&R2==0)
{
HAL_Delay(20);//等待响应
while(1)
{
Change_speed(65);
Turn_Left();
HAL_Delay(40);//等待响应
if(L1==0&&(L2==0)&&(R1==1)&&R2==0)
break;
}
}
//大右转
if(L1==0&&(L2==0)&&(R1==1)&&R2==1)
{
HAL_Delay(20);//等待响应
while(1)
{
Change_speed(65);
Turn_Right();
HAL_Delay(40);//等待响应
if(L1==0&&(L2==1)&&(R1==0)&&R2==0)
break;
}
}
}
sensor.h
#ifndef __SENSOR_H_
#define __SENSOR_H_
#include "main.h"
#include "tim.h"
extern void Sensor(uint16_t value,uint16_t pos);
void Change_speed(uint16_t speed);
#define L1 HAL_GPIO_ReadPin(sensor4_GPIO_Port,sensor4_Pin)//左 IN4 B4
#define L2 HAL_GPIO_ReadPin(sensor3_GPIO_Port,sensor3_Pin)//左 IN3 B3
#define R1 HAL_GPIO_ReadPin(sensor2_GPIO_Port,sensor2_Pin)//右 IN2 B2
#define R2 HAL_GPIO_ReadPin(sensor1_GPIO_Port,sensor1_Pin) //右 IN1 B1
#endif
5,总结
代码总体是由stm32cubeMX一键生成的,需要改动和添加的地方都在上面了,源码和资源包我也上传了,需要的自提
工程代码:点击这里
6,效果展示
下一篇博客预知-----蓝牙小车
寻迹小车演示视频