一、小车1.0——基本蓝牙小车(仅蓝牙遥控小车运动方向)
二、小车2.0——蓝牙小车PLUS(可以蓝牙控制方向+蓝牙直接调节车速)
三、小车3.0——避障小车(超声波+舵机云台)
四、小车4.0——手柄方向感知操控小车(mpu6050+双蓝牙透传)
提示:学习这篇文章《超声波避障小车》之前还需要掌握小车驱动以及超声波测距的相关内容
学习完HC-SR04超声波模块的使用以及怎样驱动小车之后,就可以通过简单的代码实现基础的蓝牙避障小车了。
HC-SR04超声波模块的使用详见----->《超声波模块的使用》
小车驱动程序的讲解详见 ----------->小车驱动(这个链接是蓝牙小车的,驱动部分不用看usart中内容)
提示:以下是本篇文章正文内容,下面案例可供参考
需要准备
STM32F103C8T6 —————————— 1个
12V电池————–—————————— 1个
L298N电机驱动 ——————————— 2个
小车底座 —————————————— 1个
稳压模块或者可调降压模块 —————— 1个
超声波模块HC-SR04————————— 1个
舵机SG90 -————————————— 1个
(1)点击RCC开启HSE和LSE,并选择RC或晶体作为时钟源
(2)配置时钟树
(1)点击TIM2,在Mode选项中设置Clock Source为Internal Clock。设置Channel1为PWM Generation CH1,Channel2为PWM Generation CH2,其余默认即可。
(2)在Mode下面的Configuration选项中Parameter Settings的参数设置
(3)TIM2 的GPIO参数设置
CH1,CH2都设置为推挽输出,高速
(1)点击TIM3,在Mode选项中设置Clock Source为Internal Clock。
(2)在Mode下面的Configuration选项中Parameter Settings的参数设置
(3)TIM3中NVIC设置
(1)点击TIM4,在Mode选项中设置Clock Source为Internal Clock,并将TIM4_CH4设置为输入捕获模式
(2)在Mode下面的Configuration选项中Parameter Settings的参数设置
(3)TIM4中NVIC设置
(4)TIM4 的GPIO参数设置
注意:这里的GPIO设置只用添加电机模块的INx以及超声波的发送端Trig,其余的已经在TIM的设置中配置过了
8个INx与PA11的参数设置一致,但是User Label不一样,对应如下:
IN1——PA8
IN2——PA12
IN3——PA13
IN4——PA14
IN11——PA15
IN22——PB0
IN33——PB1
IN44——PB2
最终结果为:
注意:这里我仅添加了超声波输入捕获测距程序和舵机PWM调速,小车驱动的程序见前言的链接
#ifndef CHAOSHENGBO_CHAOSHENGBO_H_
#define CHAOSHENGBO_CHAOSHENGBO_H_
#include "stm32f1xx_hal.h" //HAL库文件声明
#include
#include "../delay/delay.h"
#define TRIG_ON HAL_GPIO_WritePin(GPIOB, TRIG_Pin, GPIO_PIN_SET) //定义TRIG输出高电平
#define TRIG_OFF HAL_GPIO_WritePin(GPIOB, TRIG_Pin, GPIO_PIN_RESET)//定义TRIG输出低电平
extern TIM_HandleTypeDef htim4;//声明TIM4的HAL库结构体
extern TIM_HandleTypeDef htim3;//声明TIM3的HAL库结构体
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);//定时器中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);//定时器输入捕获中断回调函数
#endif /* CHAOSHENGBO_CHAOSHENGBO_H_ */
#include "chaoshengbo.h"
/********************************************************************************************
*设置变量
*distances:超声波所测距离
*t :回响信号脉冲持续时间
*high_time[0]:回响信号脉冲上升沿发生时间
*high_time[1]:回响信号脉冲下降沿发生时间
*c_values :标志值,用于定时器输入捕获回调函数
********************************************************************************************/
float distances;
uint32_t t=0;
uint32_t high_time[2]={0};
uint8_t c_values=0;
/********************************************************************************************
* 定时器中断回调函数 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
*
* 说明:
* 因为SR04每次发送超声波的时间间隔要大于60ms,
* 故通过Cube MX 已经将TIM3设置为100ms的定时器,每隔100ms才执行一次这个定时器中断回调函数
* 即每隔100ms发送一个20us的高电平脉冲,同时开启定时器4输入捕获并设置为上升沿捕获
*
********************************************************************************************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==&htim3) //判断是否为TIM3溢出中断
{
TRIG_OFF; //先将超声波模块SR04的发送端TRIG拉低
TRIG_ON; //再将超声波模块SR04的发送端TRIG拉高,并且持续20ms后再拉低
delay_us(20);
TRIG_OFF;
__HAL_TIM_SET_CAPTUREPOLARITY(&htim4,TIM_CHANNEL_4,TIM_ICPOLARITY_RISING);//设置为上升沿捕获
HAL_TIM_IC_Start_IT(&htim4,TIM_CHANNEL_4);//开启定时器输入捕获
}
}
/********************************************************************************************
* 定时器输入捕获回调函数 void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
*
*说明:
*ECHO接收回响信号脉冲,这个回调函数要被执行2次
*这个回调函数在类似于一个分叉路口,上升沿捕获走路口0,下降沿捕获走路口1
*
********************************************************************************************/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim==&htim4)
{
switch(c_values)
{//标志值c_values初始设定值为0,上升沿输入捕获,先执行回调函数执行case(0)中内容
case(0): high_time[0]=HAL_TIM_ReadCapturedValue(&htim4,TIM_CHANNEL_4);//获取上升沿的捕获值,即接收的高电平开始时间
__HAL_TIM_SET_CAPTUREPOLARITY(&htim4,TIM_CHANNEL_4,TIM_ICPOLARITY_FALLING);//设置为下降沿捕获
c_values++;//标志值c_values值变为1,下次回调函数执行case(1)中内容
break;
case(1): high_time[1]=HAL_TIM_ReadCapturedValue(&htim4,TIM_CHANNEL_4);//获取下降沿的捕获值,即接收的高电平结束时间
HAL_TIM_IC_Stop_IT(&htim4,TIM_CHANNEL_4); //关闭TIM4输入捕获
c_values=0; //标志值清零,用于下次输入捕获回调函数
htim4.Instance->CNT=0; //TIM4计数值清零
t=high_time[1]-high_time[0];//下降沿捕获值-上升沿捕获值=回响信号高电平脉冲持续时间t
distances= t*0.017; //速度0.034cm/us,计算出的距离要除以2,distances的单位是cm
break;
default: break;
}
}
}
我直接将这个舵机PWM调速.c写到了control.c中
void SG90_Init()//舵机转90°
{
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2,1500); //sg90是逆时针转动
}
void SG90_Turn_L()//舵机转135°
{
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2,2000);
}
void SG90_Turn_R()//舵机转45°
{
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2,1000);
}
#ifndef DELAY_DELAY_H_
#define DELAY_DELAY_H_
#include "stm32f1xx_hal.h" HAL库文件声明
void delay_us(uint32_t us); //us级延时函数
#endif /* DELAY_DELAY_H_ */
#include "delay.h"
void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数
{
uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数
while (delay--); //循环delay次,达到1微秒延时
}
略,小车驱动的程序见前言的链接,我写的《蓝牙小车》中有十分详细的介绍,
唯一不同的是因为TIM2设置的预分频以及计时周期的不同,__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1,5000);的设定值有所改变。
/* USER CODE BEGIN Includes */
#include "../../icode/control/control.h"
#include "../../icode/chaoshengbo/chaoshengbo.h"
/* USER CODE END Includes */
/* USER CODE BEGIN 1 */
extern float distances;
uint32_t S=20;//设定距离标准值
uint32_t LS,RS=0;//测定的左右两边距离值
/* USER CODE END 1 */
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim3);//开启定时器3中断
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //直流电机PWM
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); //SG90PWM
SG90_Init();//SG90舵机初始化,也就是转90°,朝向小车前方
CAR_STOP();
HAL_Delay(500);
/* USER CODE END 2 */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(distances>S)
{
CAR_GO();
}
else
{
CAR_STOP();
SG90_Turn_L();
HAL_Delay(1500);
LS=distances;
SG90_Turn_R();
HAL_Delay(1500);
RS=distances;
SG90_Init();
if(LS>RS&&LS>S)
{
CAR_LGO();
HAL_Delay(500);
}
else if(RS>LS&&RS>S)
{
CAR_RGO();
HAL_Delay(500);
}
else
{
CAR_BACK();
HAL_Delay(500);
}
}
}
/* USER CODE END 3 */
总体说来,这个避障小车的避障功能不是很完善,还存在一些视野盲区。因为通过舵机的转动,超声波模块只能监测到小车车头90°的范围,只能算是个半成品吧,这个项目目前是将所学的PWM控制,以及超声波整合在一起作为一个小整体,也算是小车之路的必经处吧。。。
欢迎大家积极交流,本文未经允许谢绝转载!!!