赞
踩
接上一篇基于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库源码:
提取码:1234
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。