接上一篇基于STM32的智能循迹避障小车实验(舵机旋转部分)
最后这部分我们实现超声波部分和最后代码的整合
实验所用器件及其介绍
本部分实验采用的是超声波模块HC-SR04,它长这样:
买这个的时候最好再买一个支架,可以直接架在舵机上,探查周围的距离。
超声波模块有4个引脚,分别为Vcc、 Trig(控制端)、 Echo(接收端)、 GND;其中VCC、GND接上电源和地, Trig(控制端)控制发出的超声波信号,Echo(接收端)接收反射回来的超声波信号。
控制端的控制原理:通过Trig引脚发一个 10US 以上的高电平,就可以在Echo接收口等待高电平输出;一有输出就可以开定时器计时,当此口变为低电平时就可以读定时器的值,此时就为此次测距的时间,方可算出距离.如此不断的周期测,就可以达到你移动测量的值了。(这个时间最好大于60us,以防检测和发送的声波冲突)。
了解了超声波模块的基本工作原理后就可以完成程序设计了。
程序实现
和之前操作一样,我们在之前代码的基础上直接打开CobeMX。
代码实现顺序:先设置触发信号,这里我们使用一个普通的GPIO口输出一个高电平,等待Echo发出脉冲,然后启动定时器,等待Echo变为低电平即为一次定时时间,根据数学公式我们可以将这个时间转化为距离。
CubeMX设置
这里我们还是设置一个普通的GPIO口为输出模式,再使用通用定时器作为测量时间的工具。
这里使用PG11作为GPIO输出口和Trig引脚相连,然后打开TIM4通道1设置为Input Capture direct mode模式,然后再在NVIC中配置主优先级为1次优先级为0,具体配置如图:
配置完成后生成代码,
代码实现
和之前实现定时器的中断相似的步骤,但是我们这里要实现另外的中断回调函数:
uint8_t TIM4CH1_CAP_STA = 0; // 输入捕获状态
uint16_t TIM4CH1_CAP_VAL; // 输入捕获值
// 中断服务函数里面会自动调用这个回调函数,这个是定时器更新中断处理的函数(更新时间回调函数,这里更新溢出的时间)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM4) // 判断定时器4是否发生中断
{
if((TIM4CH1_CAP_STA & 0X80) == 0) // 还未成功捕获
{
if(TIM4CH1_CAP_STA & 0X40) // 已经捕获到高电平
{
if((TIM4CH1_CAP_STA & 0X3F) == 0X3F)// 高电平时间太长了,做溢出处理
{
TIM4CH1_CAP_STA |= 0X80; // 标记为完成一次捕获
TIM4CH1_CAP_VAL += 1; // 计数器值
}
else
{
TIM4CH1_CAP_STA++; // 若没有溢出,就只让TIM5CH1_CAP_STA自加
}
}
}
}
}
// 定时器输入捕获中断处理回调函数,该函数在 HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim) 中会被调用(通道输入捕获)
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if((TIM4CH1_CAP_STA & 0X80) == 0) // 还未成功捕获
{
if(TIM4CH1_CAP_STA & 0X40) // 捕获到一个下降沿
{
TIM4CH1_CAP_STA |= 0X80; // 标记成功捕获到一次高电平脉宽
TIM4CH1_CAP_VAL = HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_1); // 获取当前的计数器值
TIM_RESET_CAPTUREPOLARITY(&htim4, TIM_CHANNEL_1); // 清除原来的设置
TIM_SET_CAPTUREPOLARITY(&htim4,TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);// 设置上升沿捕获
}
else
{
TIM4CH1_CAP_STA = 0; // 清空自定义的状态寄存器
TIM4CH1_CAP_VAL = 0; // 清空捕获值
TIM4CH1_CAP_STA |= 0X40; // 标记捕获到上升沿
__HAL_TIM_DISABLE(&htim4); // 关闭定时器
__HAL_TIM_SET_COUNTER(&htim4, 0); // 计数器值清零
TIM_RESET_CAPTUREPOLARITY(&htim4,TIM_CHANNEL_1); // 一定要先清除原来的设置 !!
TIM_SET_CAPTUREPOLARITY(&htim4,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING); // 设置下降沿捕获
__HAL_TIM_ENABLE(&htim4); // 使能定时器
}
}
}
完成中断回调函数之后,就可以在主函数中启动中断了,最后我这里使用了串口输出相关的距离、时间,也可以使用其他的方式输出,因为最后整合代码时不需要串口输出,所以我对串口配置没有说明。
主函数部分
int main(void)
{
/* USER CODE BEGIN 1 */
// uint8_t i = 0;
uint8_t length_res[10]; // 定义一个数组存放前方的距离
// uint8_t Car_Command= 4;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
MX_TIM4_Init();
/* USER CODE BEGIN 2 */
printf("这是智能小车方向控制测试程序");
HAL_TIM_Base_Start_IT(&htim3); // 这个中断是之前的舵机中断
HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim4,TIM_CHANNEL_1); // 一定要开启TIM4通道1的捕获中断,这个是超声波中断
__HAL_TIM_ENABLE_IT(&htim4,TIM_IT_UPDATE); // 一定要开启TIM4的更新中断
printf("This is TIM_CAP test...\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_12, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_Delay(500);
if(TIM4CH1_CAP_STA & 0X80) // 完成一次高电平捕获
{
temp = TIM4CH1_CAP_STA & 0X3F;
temp *= 1000; // 溢出总时间
temp = (temp+TIM4CH1_CAP_VAL)/58.0; // temp+TIM4CH1_CAP_VAL是总的时间,除以58是距离
printf("High level duration:%lld cm\r\n",temp); // 输出每次测出的距离,单位是cm
TIM4CH1_CAP_STA = 0; // 准备下一次捕获
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
这样就完成了超声波部分的测试,最后我们将代码整合,就可以完成小车自动识别障碍物然后前进
代码整合
在整合之前,我们需要修改之前的代码,现在我们要实现的目的是:超声波模块测量前面的距离,如果距离大于30cm,就让小车直走,距离小于30cm,停车,测量左侧和右侧45°的距离,然后比较这两个数,向距离大的一侧前进。
// 小车停止代码
void Car_Stop(void)
{
HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(IN3_GPIO_Port, IN3_Pin, GPIO_PIN_RESET);
}
Uint8_t a;
// 上节中我们有个关于舵机旋转方向的表格,在这里我们定义90°为正前方
// 右转45°
void SG90_Right_45(void)
{
a = 1;
}
// 舵机转向前方
void SG90_Front(void)
{
a = 2;
}
// 左转45°
void SG90_Left_45(void)
{
a = 3;
}
// 这里我们之前的回调函数也得重新实现,以保证我们可以调整想要的角度
/* TIM3 init function */
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
// 舵机的回调函数,使舵机转向
if(htim->Instance == TIM3) // 判断是否是定时器3引起的中断
{
if(a == 1) // 判断是具体是哪个转向
{
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,10);
}
if(a == 2)
{
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,15);
}
if(a == 3)
{
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,20);
}
}
}
剩下的就是主函数部分的重新实现:
int main(void)
{
/* USER CODE BEGIN 1 */
// uint8_t i = 0;
uint8_t length_res[10]; // 定义一个数组存放前方的距离
// uint8_t Car_Command= 4;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
MX_TIM4_Init();
/* USER CODE BEGIN 2 */
printf("这是智能小车方向控制测试程序");
HAL_TIM_Base_Start_IT(&htim3);
HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_1);
// Car_Dir_Com(Car_Command);
// Car_Go();
HAL_TIM_IC_Start_IT(&htim4,TIM_CHANNEL_1); // 一定要开启TIM4通道1的捕获中断
__HAL_TIM_ENABLE_IT(&htim4,TIM_IT_UPDATE); // 一定要开启TIM4的更新中断
printf("This is TIM_CAP test...\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
SG90_Front(); //舵机摆正
HAL_Delay(100);
length_res[0] =Senor_Using(); //测前方距离放在数组里
HAL_Delay(100);
if(length_res[0]>30.00) //如果前方距离大于30cm 前进
{
Car_Go();
}
if(length_res[0]<30.00) //如果前方距离小于30厘米 停车测左右距离
{
Car_Stop();
SG90_Left_45(); //舵机左转45度测距
HAL_Delay(700);
length_res[1] =Senor_Using(); //把测量结果放进数组
SG90_Right_45(); //舵机右转45度测距
HAL_Delay(700);
length_res[4] =Senor_Using(); //把测量结果放进数组
SG90_Front(); //舵机摆正
HAL_Delay(100);
if(length_res[1]>length_res[4]) //如果左边的距离大于右边的距离
{
do //舵机摆正
{
SG90_Front();
HAL_Delay(10);
length_res[0] =Senor_Using(); //重复测前方的距离同时左转
HAL_Delay(10);
Car_Left();
}
while(length_res[0]<30.00); //一直转到前方距离大于30cm
}
if(length_res[1]<length_res[4]) //如果右边的距离大于左边的距离
{
do
{
SG90_Front();
HAL_Delay(10);
length_res[0] =Senor_Using(); //重复测前方的距离同时右转
HAL_Delay(10);
Car_Right();
}
while(length_res[0]<30.00); //一直转到前方距离大于30cm
}
}
// 这部分函数是之前测试超声波的函数,现在不需要
// HAL_GPIO_WritePin(GPIOG, GPIO_PIN_12, GPIO_PIN_SET);
// HAL_Delay(1);
// HAL_GPIO_WritePin(GPIOG, GPIO_PIN_12, GPIO_PIN_RESET);
//
// HAL_Delay(500);
// if(TIM4CH1_CAP_STA & 0X80) // 完成一次高电平捕获
// {
// temp = TIM4CH1_CAP_STA & 0X3F;
// temp *= 1000; // 溢出总时间
// temp = (temp+TIM4CH1_CAP_VAL)/58.0; // 总的高电平时间
// printf("High level duration:%lld cm\r\n",temp);
// TIM4CH1_CAP_STA = 0; // 准备下一次捕获
// }
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
这样就完成了整个项目的书写,最后附上整个项目的HAL库源码:
百度网盘 请输入提取码文章来源:https://www.toymoban.com/news/detail-471685.html
提取码:1234文章来源地址https://www.toymoban.com/news/detail-471685.html
到了这里,关于基于STM32的智能循迹避障小车实验(超声波部分)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!