当前位置:   article > 正文

基于STM32的智能循迹避障小车实验(超声波部分)_自动循迹避障小车超声波避障模块

自动循迹避障小车超声波避障模块

接上一篇基于STM32的智能循迹避障小车实验(舵机旋转部分)

最后这部分我们实现超声波部分和最后代码的整合

实验所用器件及其介绍

本部分实验采用的是超声波模块HC-SR04,它长这样:

 

买这个的时候最好再买一个支架,可以直接架在舵机上,探查周围的距离。

超声波模块有4个引脚,分别为Vcc Trig(控制端)、 Echo(接收端)、 GND;其中VCCGND接上电源和地, Trig(控制端)控制发出的超声波信号,Echo(接收端)接收反射回来的超声波信号。

控制端的控制原理:通过Trig引脚发一个 10US 以上的高电平,就可以在Echo接收口等待高电平输出;一有输出就可以开定时器计时,当此口变为低电平时就可以读定时器的值,此时就为此次测距的时间,方可算出距离.如此不断的周期测,就可以达到你移动测量的值了。(这个时间最好大于60us,以防检测和发送的声波冲突)。

 

了解了超声波模块的基本工作原理后就可以完成程序设计了。

程序实现

和之前操作一样,我们在之前代码的基础上直接打开CobeMX。

代码实现顺序:先设置触发信号,这里我们使用一个普通的GPIO口输出一个高电平,等待Echo发出脉冲,然后启动定时器,等待Echo变为低电平即为一次定时时间,根据数学公式我们可以将这个时间转化为距离。

CubeMX设置

这里我们还是设置一个普通的GPIO口为输出模式,再使用通用定时器作为测量时间的工具。

这里使用PG11作为GPIO输出口和Trig引脚相连,然后打开TIM4通道1设置为Input Capture direct mode模式,然后再在NVIC中配置主优先级为1次优先级为0,具体配置如图:

 

配置完成后生成代码,

代码实现

和之前实现定时器的中断相似的步骤,但是我们这里要实现另外的中断回调函数:

  1. uint8_t TIM4CH1_CAP_STA = 0;                        // 输入捕获状态
  2. uint16_t TIM4CH1_CAP_VAL;                           // 输入捕获值
  3. // 中断服务函数里面会自动调用这个回调函数,这个是定时器更新中断处理的函数(更新时间回调函数,这里更新溢出的时间)
  4. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  5. {
  6.     if(htim->Instance == TIM4)       // 判断定时器4是否发生中断
  7.     {
  8.         if((TIM4CH1_CAP_STA & 0X80) == 0)           // 还未成功捕获
  9.         {
  10.             if(TIM4CH1_CAP_STA & 0X40)   // 已经捕获到高电平
  11.             {         
  12.                 if((TIM4CH1_CAP_STA & 0X3F) == 0X3F)// 高电平时间太长了,做溢出处理
  13.                 { 
  14.                     TIM4CH1_CAP_STA |= 0X80;   // 标记为完成一次捕获
  15.                     TIM4CH1_CAP_VAL += 1;       // 计数器值
  16.                 }
  17.                 else
  18.                 {
  19.                     TIM4CH1_CAP_STA++;    // 若没有溢出,就只让TIM5CH1_CAP_STA自加
  20.                 }               
  21.             }  
  22.         }
  23.     }
  24. }
  25. // 定时器输入捕获中断处理回调函数,该函数在 HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim) 中会被调用(通道输入捕获)
  26. void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
  27. {
  28.     if((TIM4CH1_CAP_STA & 0X80) == 0)               // 还未成功捕获
  29.     {
  30.          if(TIM4CH1_CAP_STA & 0X40)         // 捕获到一个下降沿
  31.         {          
  32.                      TIM4CH1_CAP_STA |= 0X80;   // 标记成功捕获到一次高电平脉宽
  33.                      TIM4CH1_CAP_VAL = HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_1); // 获取当前的计数器值
  34.                      TIM_RESET_CAPTUREPOLARITY(&htim4, TIM_CHANNEL_1);                 // 清除原来的设置        
  35.                      TIM_SET_CAPTUREPOLARITY(&htim4,TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);// 设置上升沿捕获
  36.               }
  37.               else
  38.         {
  39.                      TIM4CH1_CAP_STA = 0;     // 清空自定义的状态寄存器
  40.                      TIM4CH1_CAP_VAL = 0;        // 清空捕获值
  41.                      TIM4CH1_CAP_STA |= 0X40;        // 标记捕获到上升沿
  42.                      __HAL_TIM_DISABLE(&htim4);    // 关闭定时器
  43.                      __HAL_TIM_SET_COUNTER(&htim4, 0);   // 计数器值清零
  44.                      TIM_RESET_CAPTUREPOLARITY(&htim4,TIM_CHANNEL_1);  // 一定要先清除原来的设置   !!              
  45.                  TIM_SET_CAPTUREPOLARITY(&htim4,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);   // 设置下降沿捕获
  46.                      __HAL_TIM_ENABLE(&htim4);         // 使能定时器     
  47.               }     
  48.        }
  49. }

完成中断回调函数之后,就可以在主函数中启动中断了,最后我这里使用了串口输出相关的距离、时间,也可以使用其他的方式输出,因为最后整合代码时不需要串口输出,所以我对串口配置没有说明。

主函数部分

  1. int main(void)
  2. {
  3.   /* USER CODE BEGIN 1 */
  4. //    uint8_t i = 0;
  5.       
  6.        uint8_t length_res[10];  // 定义一个数组存放前方的距离
  7. //    uint8_t Car_Command= 4;
  8.   /* USER CODE END 1 */
  9.   /* MCU Configuration--------------------------------------------------------*/
  10.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  11.   HAL_Init();
  12.   /* USER CODE BEGIN Init */
  13.   /* USER CODE END Init */
  14.   /* Configure the system clock */
  15.   SystemClock_Config();
  16.   /* USER CODE BEGIN SysInit */
  17.   /* USER CODE END SysInit */
  18.   /* Initialize all configured peripherals */
  19.   MX_GPIO_Init();
  20.   MX_TIM2_Init();
  21.   MX_USART1_UART_Init();
  22.   MX_TIM3_Init();
  23.   MX_TIM4_Init();
  24.   /* USER CODE BEGIN 2 */
  25.       
  26.        printf("这是智能小车方向控制测试程序");
  27.        HAL_TIM_Base_Start_IT(&htim3);  // 这个中断是之前的舵机中断
  28.        HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_1);
  29.        HAL_TIM_IC_Start_IT(&htim4,TIM_CHANNEL_1);  // 一定要开启TIM4通道1的捕获中断,这个是超声波中断
  30.   __HAL_TIM_ENABLE_IT(&htim4,TIM_IT_UPDATE);  // 一定要开启TIM4的更新中断
  31.   printf("This is TIM_CAP test...\n");   
  32.   /* USER CODE END 2 */
  33.   /* Infinite loop */
  34.   /* USER CODE BEGIN WHILE */
  35.   while (1)
  36.   {
  37.               HAL_GPIO_WritePin(GPIOG, GPIO_PIN_12, GPIO_PIN_SET);
  38.               HAL_Delay(1);
  39.               HAL_GPIO_WritePin(GPIOG, GPIO_PIN_12, GPIO_PIN_RESET);
  40.              
  41.               HAL_Delay(500);
  42.    if(TIM4CH1_CAP_STA & 0X80)    // 完成一次高电平捕获
  43.    {
  44.      temp = TIM4CH1_CAP_STA & 0X3F;
  45.       temp *= 1000;            // 溢出总时间
  46.      temp = (temp+TIM4CH1_CAP_VAL)/58.0; // temp+TIM4CH1_CAP_VAL是总的时间,除以58是距离
  47.       printf("High level duration:%lld cm\r\n",temp);  // 输出每次测出的距离,单位是cm
  48.       TIM4CH1_CAP_STA = 0;             // 准备下一次捕获
  49.        }
  50.              
  51.     /* USER CODE END WHILE */
  52.              
  53.     /* USER CODE BEGIN 3 */
  54.   }
  55.                     
  56.   /* USER CODE END 3 */
  57. }

这样就完成了超声波部分的测试,最后我们将代码整合,就可以完成小车自动识别障碍物然后前进

代码整合

在整合之前,我们需要修改之前的代码,现在我们要实现的目的是:超声波模块测量前面的距离,如果距离大于30cm,就让小车直走,距离小于30cm,停车,测量左侧和右侧45°的距离,然后比较这两个数,向距离大的一侧前进。

  1. // 小车停止代码
  2. void Car_Stop(void)
  3. {
  4.        HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, GPIO_PIN_RESET);
  5.        HAL_GPIO_WritePin(IN3_GPIO_Port, IN3_Pin, GPIO_PIN_RESET);
  6. }
  7. Uint8_t a;
  8. // 上节中我们有个关于舵机旋转方向的表格,在这里我们定义90°为正前方
  9. // 右转45°
  10. void SG90_Right_45(void)
  11. {
  12.        a = 1;
  13. }
  14. // 舵机转向前方
  15. void SG90_Front(void)
  16. {
  17.        a = 2;
  18. }
  19. // 左转45°
  20. void SG90_Left_45(void)
  21. {
  22.        a = 3;
  23. }
  24. // 这里我们之前的回调函数也得重新实现,以保证我们可以调整想要的角度
  25. /* TIM3 init function */
  26. void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
  27. {
  28.        // 舵机的回调函数,使舵机转向
  29.        if(htim->Instance == TIM3)  // 判断是否是定时器3引起的中断
  30.        {
  31.               if(a == 1// 判断是具体是哪个转向
  32.               {
  33.                      __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,10);
  34.               }
  35.               if(a == 2)
  36.               {
  37.                      __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,15);
  38.               }
  39.               if(a == 3)
  40.               {
  41.                      __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,20);
  42.               }
  43.        }
  44. }
  45. 剩下的就是主函数部分的重新实现:
  46. int main(void)
  47. {
  48.   /* USER CODE BEGIN 1 */
  49. //    uint8_t i = 0;
  50.       
  51.        uint8_t length_res[10];  // 定义一个数组存放前方的距离
  52. //    uint8_t Car_Command= 4;
  53.   /* USER CODE END 1 */
  54.   /* MCU Configuration--------------------------------------------------------*/
  55.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  56.   HAL_Init();
  57.   /* USER CODE BEGIN Init */
  58.   /* USER CODE END Init */
  59.   /* Configure the system clock */
  60.   SystemClock_Config();
  61.   /* USER CODE BEGIN SysInit */
  62.   /* USER CODE END SysInit */
  63.   /* Initialize all configured peripherals */
  64.   MX_GPIO_Init();
  65.   MX_TIM2_Init();
  66.   MX_USART1_UART_Init();
  67.   MX_TIM3_Init();
  68.   MX_TIM4_Init();
  69.   /* USER CODE BEGIN 2 */
  70.       
  71.        printf("这是智能小车方向控制测试程序");
  72.        HAL_TIM_Base_Start_IT(&htim3);
  73.        HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_1);
  74. //    Car_Dir_Com(Car_Command);            
  75. //    Car_Go();
  76.        HAL_TIM_IC_Start_IT(&htim4,TIM_CHANNEL_1);  // 一定要开启TIM4通道1的捕获中断
  77.   __HAL_TIM_ENABLE_IT(&htim4,TIM_IT_UPDATE);  // 一定要开启TIM4的更新中断
  78.   printf("This is TIM_CAP test...\n");
  79.              
  80.   /* USER CODE END 2 */
  81.   /* Infinite loop */
  82.   /* USER CODE BEGIN WHILE */
  83.   while (1)
  84.   {
  85.               SG90_Front();   //舵机摆正
  86.               HAL_Delay(100);
  87.               length_res[0] =Senor_Using();  //测前方距离放在数组里
  88.               HAL_Delay(100);
  89.               if(length_res[0]>30.00)       //如果前方距离大于30cm  前进
  90.               {
  91.                      Car_Go();
  92.               }     
  93.                            
  94.               if(length_res[0]<30.00)     //如果前方距离小于30厘米  停车测左右距离
  95.               {
  96.                      Car_Stop(); 
  97.                      SG90_Left_45();      //舵机左转45度测距
  98.                      HAL_Delay(700);       
  99.                      length_res[1] =Senor_Using();    //把测量结果放进数组
  100.                     
  101.                      SG90_Right_45();     //舵机右转45度测距
  102.                      HAL_Delay(700);
  103.                      length_res[4] =Senor_Using();     //把测量结果放进数组                    
  104.                            
  105.                      SG90_Front();           //舵机摆正
  106.                      HAL_Delay(100);
  107.                      if(length_res[1]>length_res[4])    //如果左边的距离大于右边的距离
  108.                      {
  109.                             do                        //舵机摆正
  110.                             {
  111.                             SG90_Front();
  112.                             HAL_Delay(10);
  113.                             length_res[0] =Senor_Using(); //重复测前方的距离同时左转
  114.                             HAL_Delay(10);                                     
  115.                             Car_Left();
  116.                             }
  117.                             while(length_res[0]<30.00);           //一直转到前方距离大于30cm             
  118.                      }
  119.                      if(length_res[1]<length_res[4])    //如果右边的距离大于左边的距离
  120.                      {
  121.                             do
  122.                             {
  123.                             SG90_Front();
  124.                             HAL_Delay(10);
  125.                             length_res[0] =Senor_Using();  //重复测前方的距离同时右转
  126.                             HAL_Delay(10);                                     
  127.                             Car_Right();
  128.                             }
  129.                             while(length_res[0]<30.00);           //一直转到前方距离大于30cm
  130.                      }
  131.                            
  132.               }
  133. // 这部分函数是之前测试超声波的函数,现在不需要
  134. //           HAL_GPIO_WritePin(GPIOG, GPIO_PIN_12, GPIO_PIN_SET);
  135. //           HAL_Delay(1);
  136. //           HAL_GPIO_WritePin(GPIOG, GPIO_PIN_12, GPIO_PIN_RESET);
  137. //          
  138. //           HAL_Delay(500);
  139. //    if(TIM4CH1_CAP_STA & 0X80)    // 完成一次高电平捕获
  140. //    {
  141. //      temp = TIM4CH1_CAP_STA & 0X3F;
  142. //      temp *= 1000;            // 溢出总时间
  143. //      temp = (temp+TIM4CH1_CAP_VAL)/58.0;  // 总的高电平时间
  144. //      printf("High level duration:%lld cm\r\n",temp);
  145. //      TIM4CH1_CAP_STA = 0;          // 准备下一次捕获
  146. //           }
  147.              
  148.     /* USER CODE END WHILE */
  149.              
  150.     /* USER CODE BEGIN 3 */
  151.   }
  152.                     
  153.   /* USER CODE END 3 */
  154. }

这样就完成了整个项目的书写,最后附上整个项目的HAL库源码:

百度网盘 请输入提取码

提取码:1234

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/46290
推荐阅读
相关标签
  

闽ICP备14008679号