STM32
直播中

叹久

9年用户 704经验值
擅长:可编程逻辑 光电显示 接口/总线/驱动
私信 关注
[问答]

怎样去设计一种基于超声波模块的智能避障小车呢

超声波模块的工作原理是什么?
怎样去设计一种基于超声波模块的智能避障小车呢?

回帖(1)

丁峙昌

2021-11-17 09:56:18
  五、避障小车制作
  1.超声波模块接线
  
  从商家的资料知道,TRIG和ECHO接单片机引脚,而OUT口,在我学习这个模块的过程中发现很多文章都没用这个东西,因此在这里我也不打算用,VCC口接5V。
  从上篇的原理图看,我本来打算超声波的TRIG和ECHO引脚分别接PB8和PB9的,但在上篇中我也提到了我的c8t6的PB引脚有问题。所以在接线时,我放弃了接PB引脚改为接PA11、PA12。
  如图,通过飞线的方法从PA11、PA12中引出两条线在连接超声波,于是超声波就可以用了。
  2.工作原理
  
  还是商家的资料,我们就知道了超声波模块的大致原理。更加详细的超声波介绍可以看看这个文章:STM32的超声波测距程序
  3. 超声波避障程序
  cs.c
  #include “cs.h”
  #include “stm32f10x.h”
  #include “delay.h”
  /*记录定时器溢出次数*/
  uint overcount=0;
  /*设置中断优先级*/
  void NVIC_Config(void)
  {
  NVIC_InitTypeDef NVIC_InitStructer;
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  NVIC_InitStructer.NVIC_IRQChannelPreemptionPriority=0;
  NVIC_InitStructer.NVIC_IRQChannelSubPriority=0;
  NVIC_InitStructer.NVIC_IRQChannel=TIM4_IRQn;
  NVIC_InitStructer.NVIC_IRQChannelCmd=ENABLE;
  NVIC_Init(&NVIC_InitStructer);
  }
  /*初始化模块的GPIO以及初始化定时器TIM2*/
  void CH_SR04_Init(void)
  {
  GPIO_InitTypeDef GPIO_InitStructer;
  TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructer;
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
  /*TRIG触发信号*/
  GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz; //原来接PB 8、PB 9不能用,后改为PA 11,PA 12就能用
  GPIO_InitStructer.GPIO_Mode=GPIO_Mode_Out_PP;
  GPIO_InitStructer.GPIO_Pin=GPIO_Pin_11;
  GPIO_Init(GPIOA, &GPIO_InitStructer);
  /*ECHO回响信号*/
  GPIO_InitStructer.GPIO_Mode=GPIO_Mode_IN_FLOATING;
  GPIO_InitStructer.GPIO_Pin=GPIO_Pin_12;
  GPIO_Init(GPIOA, & GPIO_InitStructer);
  GPIO_ResetBits(GPIOA,GPIO_Pin_4);
  /*定时器TIM2初始化*/
  TIM_DeInit(TIM4);
  TIM_TimeBaseInitStructer.TIM_Period=999;//定时周期为1000
  TIM_TimeBaseInitStructer.TIM_Prescaler=71; //分频系数72
  TIM_TimeBaseInitStructer.TIM_ClockDivision=TIM_CKD_DIV1;//不分频
  TIM_TimeBaseInitStructer.TIM_CounterMode=TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructer);
  TIM_ClearFlag(TIM4,TIM_FLAG_Update);
  TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);//开启更新中断
  NVIC_Config();
  TIM_Cmd(TIM4,DISABLE);//关闭定时器使能
  }
  float Senor_Using(void) //测距函数
  {
  float length=0,sum=0;
  u16 tim;
  uint i=0;
  /*测5次数据计算一次平均值*/
  while(i!=5)
  {
  PAout(11)=1; //拉高信号,作为触发信号
  delay_us(20); //高电平信号超过10us
  PAout(11)=0;
  /*等待回响信号*/
  while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_12)==RESET);
  TIM_Cmd(TIM4,ENABLE);//回响信号到来,开启定时器计数
  i+=1; //每收到一次回响信号+1,收到5次就计算均值
  while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_12)==SET);//回响信号消失
  TIM_Cmd(TIM4,DISABLE);//关闭定时器
  tim=TIM_GetCounter(TIM4);//获取计TIM4数寄存器中的计数值,一边计算回响信号时间
  length=(tim+overcount*1000)/58.0;//通过回响信号计算距离
  sum=length+sum;
  TIM4-》CNT=0; //将TIM4计数寄存器的计数值清零
  overcount=0; //中断溢出次数清零
  delay_ms(10);
  }
  length=sum/5;
  return length;//距离作为函数返回值
  }
  void TIM4_IRQHandler(void) //中断,当回响信号很长是,计数值溢出后重复计数,用中断来保存溢出次数
  {
  if(TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET)
  {
  TIM_ClearITPendingBit(TIM4,TIM_IT_Update);//清除中断标志
  overcount++;
  }
  }
  cs.h
  #ifndef __CS_H
  #define __CS_H
  #include “stm32f10x.h”
  #include “delay.h”
  #include “sys.h”
  #define uint unsigned int
  #define TRIG_Send PBout(8)
  #define ECHO_Reci PBin(9)
  void CH_SR04_Init(void); //超声波模块相关配置初始化
  float Senor_Using(void); //测距函数,返回值即为距离
  void NVIC_Config(void); //中断配置
  #endif
  避障主函数
  注意因为我没用舵机,所以自己打算通过小车自身的转动来代替舵机,于是就有了这样奇怪的代码。
  //头文件
  #include “stm32f10x.h”
  #include “moter.h”
  #include “cs.h”
  #include “xunji.h”
  #include “delay.h”
  #include “sys.h”
  #include “lanya.h”
  int main(void)
  {
  float length_res[5]; //用来存放测距结果
  SystemInit(); // 配置系统时钟为72M
  delay_init(); //延时初始化
  xunji_config(); //循迹初始化
  TIM3_PWM_Init(); //电机pwm TIM3
  CH_SR04_Init(); //超声波定时器 TIM4
  USART_Config(); //蓝牙串口
  //避障循环
  while(1)
  {
  length_res[0] =Senor_Using(); //测前方距离放在数组里
  delay_ms(100);
  if(length_res[0]》30.00) //如果前方距离大于30cm 前进
  {
  CarGo();
  }
  if(length_res[0]《30.00) //如果前方距离小于30厘米 停车测左右距离
  {
  CarStop();
  delay_ms(100);
  CarRightAround(); //掉头
  delay_ms(1000);
  CarStop();
  delay_ms(100);
  CarLeftAround();
  delay_ms(370); //检测左边约45度的距离
  CarStop();
  delay_ms(100);
  length_res[1] =Senor_Using(); //把测量结果放进数组
  CarRightAround();
  delay_ms(600); //检测右边约45度的距离
  CarStop();
  delay_ms(100);
  length_res[4] =Senor_Using(); //把测量结果放进数组
  CarLeftAround();
  delay_ms(370); //回正
  CarStop();
  delay_ms(100);
  if(length_res[1]》length_res[4]) //如果左边的距离大于右边的距离
  {
  do
  {
  length_res[0] =Senor_Using(); //重复测前方的距离同时左转
  delay_ms(10);
  CarLeft();
  delay_ms(100);
  }
  while(length_res[0]《30.00); //一直转到前方距离大于30cm
  }
  if(length_res[1]《length_res[4]) //如果右边的距离大于左边的距离
  {
  do
  {
  length_res[0] =Senor_Using(); //重复测前方的距离同时右转
  delay_ms(10);
  CarRight();
  delay_ms(100);
  }
  while(length_res[0]《30.00); //一直转到前方距离大于30cm
  }
  }
  }
  }
  六、蓝牙遥控小车制作
  1.模块介绍+接线
  JDY-31有六个脚我只用了这四个就可以实现蓝牙控制。
  引脚说明
  1 、 TXD 串口输出,接开发板上的UART-Rx
  2 、 RXD 串口输入,接开发板上的UART-Tx
  3、 GND接地
  4、 VCC接3.6V-6V(我接了5V)
  接线
  RXD接PA9
  TXD接PA10
  3.蓝牙遥控小车程序
  lanya.c
  #include “lanya.h”
  static void NVIC_Configuration(void) //中断配置
  {
  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
  NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
  }
  void USART_Config(void)
  {
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
  // USART1_TX PA.9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9
  //USART1_RX PA.10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA10
  /* USARTx configured as follow:
  - BaudRate = 9600 baud 波特率
  - Word Length = 8 Bits 数据长度
  - One Stop Bit 停止位
  - No parity 校验方式
  - Hardware flow control disabled (RTS and CTS signals) 硬件控制流
  - Receive and transmit enabled 使能发送和接收
  */
  // 配置串口的工作参数
  // 配置波特率
  USART_InitStructure.USART_BaudRate = 9600;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USART1, &USART_InitStructure);
  // 串口中断优先级配置
  NVIC_Configuration();
  // 使能串口接收中断
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
  // 使能串口
  USART_Cmd(USART1, ENABLE);
  // 清除发送完成标志
  //USART_ClearFlag(USART1, USART_FLAG_TC);
  }
  //串口的中断服务函数
  void USART1_IRQHandler(void)
  {
  if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) //检查指定的 USART1 中断发生与否
  {
  USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除 USART1 的中断待处理位
  }
  }
  lanya.h
  #ifndef __LANYA_H
  #define __LANYA_H
  #include “stm32f10x.h”
  #include 《stdio.h》
  void USART_Config(void);
  #endif
  主函数
  //头文件
  #include “stm32f10x.h”
  #include “moter.h”
  #include “cs.h”
  #include “xunji.h”
  #include “delay.h”
  #include “sys.h”
  #include “lanya.h”
  u8 flag; //定义一个蓝牙的标志位
  int main(void)
  {
  SystemInit(); // 配置系统时钟为72M
  delay_init(); //延时初始化
  xunji_config(); //循迹初始化
  TIM3_PWM_Init(); //电机pwm TIM3
  CH_SR04_Init(); //超声波定时器 TIM4
  USART_Config(); //蓝牙串口
  //蓝牙数据接收判断函数
  while(1)
  {
  flag= USART_ReceiveData(USART1); //返回 USART1 最近接收到的数据
  switch(flag)
  {
  case ‘0’: CarStop(); break ;
  case ‘1’: CarLeft(); break ;
  case ‘2’: CarRight(); break ;
  case ‘3’: CarBack(); break ;
  case ‘4’: CarGo(); break ;
  case ‘5’: CarLeftAround(); break ;
  case ‘6’: CarRightAround(); break ;
  default: CarStop(); break ;
  }
  }
  }
  4.蓝牙串口APP
  APP设置介绍
  总结
  至此,制作智能小车的经历就记录和分享完了。
  请记住:本文的智能小车的代码都只是为了实现每个模块能使用,所以这些代码只处于能用的水准。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分