实验三---红外超声波雷达测距

一. 采用stm32F103和HC-SR04超声波模块, 使用标准库或HAL库+ 定时器中断,完成1或2路的超声波障碍物测距功能。

CubeMX配置:

1、RCC配置外部高速晶振——HSE

2、SYS配置:Debug设置成Serial Wire 

 ADC1配置:配置ADC-IN1模数转换

 TIM2配置:设置定时器TIM2每1us向上计数一次,通道1为上升沿捕获并连接到超声波模块的ECHO引脚

GPIO配置:PA5接到了HC-SR04的TRIG触发引脚,默认输出低电平 

TIM1配置:由上面可知HC-SR04的使用需要us级的延迟函数,HAL库自带只有ms的,所以需要自己设计一个定时器 

 

超声波模块代码:

HC-SR04.h:

#ifndef HCSR04_H_
#define HCSR04_H_
 
#include "main.h"
#include "delay.h"
 
typedef struct
{
	uint8_t  edge_state;
	uint16_t tim_overflow_counter;
	uint32_t prescaler;
	uint32_t period;
	uint32_t t1;	//	上升沿时间
	uint32_t t2;	//	下降沿时间
	uint32_t high_level_us;	//	高电平持续时间
	float    distance;
	TIM_TypeDef* instance;
    uint32_t ic_tim_ch;
	HAL_TIM_ActiveChannel active_channel;
}Hcsr04InfoTypeDef;
 
extern Hcsr04InfoTypeDef Hcsr04Info;
 
/**
 * @description: 超声波模块的输入捕获定时器通道初始化
 * @param {TIM_HandleTypeDef} *htim
 * @param {uint32_t} Channel
 * @return {*}
 */
void Hcsr04Init(TIM_HandleTypeDef *htim, uint32_t Channel);
 
/**
 * @description: HC-SR04触发
 * @param {*}
 * @return {*}
 */
void Hcsr04Start();
 
/**
 * @description: 定时器计数溢出中断处理函数
 * @param {*}    main.c中重定义void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
 * @return {*}
 */
void Hcsr04TimOverflowIsr(TIM_HandleTypeDef *htim);
 
/**
 * @description: 输入捕获计算高电平时间->距离
 * @param {*}    main.c中重定义void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
 * @return {*}
 */
void Hcsr04TimIcIsr(TIM_HandleTypeDef* htim);
 
/**
 * @description: 读取距离 
 * @param {*}
 * @return {*}
 */
float Hcsr04Read();
 
#endif /* HCSR04_H_ */

HC-SR04.c:

#include "hc-sr04.h"
 
Hcsr04InfoTypeDef Hcsr04Info;
 
/**
 * @description: 超声波模块的输入捕获定时器通道初始化
 * @param {TIM_HandleTypeDef} *htim
 * @param {uint32_t} Channel
 * @return {*}
 */
void Hcsr04Init(TIM_HandleTypeDef *htim, uint32_t Channel)
{
  /*--------[ Configure The HCSR04 IC Timer Channel ] */
  // MX_TIM2_Init();  // cubemx中配置
  Hcsr04Info.prescaler = htim->Init.Prescaler; //  72-1
  Hcsr04Info.period = htim->Init.Period;       //  65535
 
  Hcsr04Info.instance = htim->Instance;        //  TIM2
  Hcsr04Info.ic_tim_ch = Channel;
  if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_1)
  {
    Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_1;             //  TIM_CHANNEL_4
  }
  else if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_2)
  {
    Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_2;             //  TIM_CHANNEL_4
  }
  else if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_3)
  {
    Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_3;             //  TIM_CHANNEL_4
  }
  else if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_4)
  {
    Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_4;             //  TIM_CHANNEL_4
  }
  else if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_4)
  {
    Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_4;             //  TIM_CHANNEL_4
  }
  /*--------[ Start The ICU Channel ]-------*/
  HAL_TIM_Base_Start_IT(htim);
  HAL_TIM_IC_Start_IT(htim, Channel);
}
 
/**
 * @description: HC-SR04触发
 * @param {*}
 * @return {*}
 */
void Hcsr04Start()
{
  HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);
  DelayUs(10);  //  10us以上
  HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
}
 
/**
 * @description: 定时器计数溢出中断处理函数
 * @param {*}    main.c中重定义void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
 * @return {*}
 */
void Hcsr04TimOverflowIsr(TIM_HandleTypeDef *htim)
{
  if(htim->Instance == Hcsr04Info.instance) //  TIM2
  {
    Hcsr04Info.tim_overflow_counter++;
  }
}
 
/**
 * @description: 输入捕获计算高电平时间->距离
 * @param {*}    main.c中重定义void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
 * @return {*}
 */
void Hcsr04TimIcIsr(TIM_HandleTypeDef* htim)
{
  if((htim->Instance == Hcsr04Info.instance) && (htim->Channel == Hcsr04Info.active_channel))
  {
    if(Hcsr04Info.edge_state == 0)      //  捕获上升沿
    {
      // 得到上升沿开始时间T1,并更改输入捕获为下降沿
      Hcsr04Info.t1 = HAL_TIM_ReadCapturedValue(htim, Hcsr04Info.ic_tim_ch);
      __HAL_TIM_SET_CAPTUREPOLARITY(htim, Hcsr04Info.ic_tim_ch, TIM_INPUTCHANNELPOLARITY_FALLING);
      Hcsr04Info.tim_overflow_counter = 0;  //  定时器溢出计数器清零
      Hcsr04Info.edge_state = 1;        //  上升沿、下降沿捕获标志位
    }
    else if(Hcsr04Info.edge_state == 1) //  捕获下降沿
    {
      // 捕获下降沿时间T2,并计算高电平时间
      Hcsr04Info.t2 = HAL_TIM_ReadCapturedValue(htim, Hcsr04Info.ic_tim_ch);
      Hcsr04Info.t2 += Hcsr04Info.tim_overflow_counter * Hcsr04Info.period; //  需要考虑定时器溢出中断
      Hcsr04Info.high_level_us = Hcsr04Info.t2 - Hcsr04Info.t1; //  高电平持续时间 = 下降沿时间点 - 上升沿时间点
      // 计算距离
      Hcsr04Info.distance = (Hcsr04Info.high_level_us / 1000000.0) * 340.0 / 2.0 * 100.0;
      // 重新开启上升沿捕获
      Hcsr04Info.edge_state = 0;  //  一次采集完毕,清零
      __HAL_TIM_SET_CAPTUREPOLARITY(htim, Hcsr04Info.ic_tim_ch, TIM_INPUTCHANNELPOLARITY_RISING);
    }
  }
}
 
/**
 * @description: 读取距离 
 * @param {*}
 * @return {*}
 */
float Hcsr04Read()
{
  // 测距结果限幅
  if(Hcsr04Info.distance >= 500)
  {
    Hcsr04Info.distance = 500;        //元器件资料说是600cm最高距离,这里保守一点
  }
  return Hcsr04Info.distance;
}
/* USER CODE BEGIN 4 */
/**
 * @description: 定时器输出捕获中断
 * @param {TIM_HandleTypeDef} *htim
 * @return {*}
 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)    //捕获回调函数
{
  Hcsr04TimIcIsr(htim);
}
 
/**
 * @description: 定时器溢出中断
 * @param {*}
 * @return {*}
 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)    //在中断回调函数中添加用户代码
{
  Hcsr04TimOverflowIsr(htim);
}
/* USER CODE END 4 */

ranging.h:

#ifndef __SHARP2Y0A21_H
#define __SHARP2Y0A21_H	
 
#include "main.h"
 
 
#define Adc1IN1Distance_READ_TIMES	10		//定义红外传感器读取次数,以便取平均值
 
void DistanceSensor_Init(void); 				//初始化红外传感器
float DistanceSensor_Get_Val(void);				//读取红外传感器的值
 
 
#endif 

ranging.c:

#include "sharp.h"
#include "adc.h"
#include "main.h"
#include "stdio.h"
 
//初始化ADC,不用修改
//这里我们仅以规则通道为例														   
		  
//初始化传感器,需要修改端口和引脚号,这里是c出口,c1引脚,ADC1的IN1
void DistanceSensor_Init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  __HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIOA时钟
	
  //先初始化ADC1通道11 IO口
  GPIO_InitStructure.Pin = GPIO_PIN_1;//PA1
  GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;//模拟输入
  GPIO_InitStructure.Pull = GPIO_NOPULL ;//不带上下拉
  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化  
	
 
	MX_ADC1_Init();//初始化ADC1
}
//PA1=IN1
float DistanceSensor_Get_Val(void)
{
	uint32_t temp_val=0;
	float distemp=0.0;
	uint8_t t;
	for(t=0;t<Adc1IN1Distance_READ_TIMES;t++)
	{
		temp_val+=HAL_ADC_GetValue(&hadc1);	//读取ADC值,通道1
		HAL_Delay(5);
	}
	temp_val/=Adc1IN1Distance_READ_TIMES;//得到平均值,这个是平均的ADC,
	distemp=temp_val*3.3/4095;
 
	//电压对应距离
	distemp=(-13.2*distemp*distemp*distemp)+72.84*distemp*distemp-140*distemp+107.12;
  return distemp;
 
}

main 函数:

int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* 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_I2C2_Init();
  MX_ADC1_Init();
  MX_TIM2_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */
  OLED_Init();
  OLED_CLS();
  Hcsr04Init(&htim2, TIM_CHANNEL_1);  // 通道选择
  Hcsr04Start();  //  启动超声波
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
		
		//显示实验对比
		OLED_ShowCN_STR(30,0,0,4);
		
		//红外测距显示
		HAL_ADC_Start(&hadc1);
        adcx=HAL_ADC_GetValue(&hadc1);
		distance=DistanceSensor_Get_Val();
		OLED_ShowCN_STR(0,2,4,5);
		OLED_Showdecimal(80,2,distance,3,2,16);
		
		
		//超声波测距显示
		Hcsr04Start();
		OLED_ShowCN_STR(0,4,9,5);
		OLED_Showdecimal(80,4,Hcsr04Read(),3,2,16);
 
		//显示单位
		OLED_ShowCN_STR(30,6,14,5);
				
  }
  /* USER CODE END 3 */
}

二. 当前智能汽车上一般配置有12路超声波雷达,这些专用超声波雷达内置了MCU,直接输出数字化的测距结果,一般硬件接口采用串口RS485,通信协议采用modbus。请思考:
1)RS485与RS232(UART)有什么不同?

  1. 电气特性

    • RS485:RS485是一种差分信号标准,可以支持多个设备(最多32个),并且可以在较长距离(最高达1200米)内进行通信。它使用两根信号线(A和B线)来传输数据,具备良好的抗干扰能力。
    • RS232:RS232是单端信号标准,一般用于较短距离(通常不超过15米)的通信。它使用一个发送线(TX)和一个接收线(RX),并且通常包括地线(GND)作为信号参考。
  2. 信号电平

    • RS485:RS485的逻辑高低电平范围较广,典型的逻辑高电平为+1.5V至+5V,逻辑低电平为-1.5V至-5V。
    • RS232:RS232的逻辑高低电平一般为+3V至+15V的正电平和-3V至-15V的负电平。
  3. 通信距离

    • RS485:由于其差分信号特性和抗干扰能力,RS485可以支持较长的通信距离,通常在工业控制和长距离传输中被广泛应用。
    • RS232:由于是单端信号,通信距离相对较短,主要用于个人计算机和外围设备之间的短距离通信。
  4. 应用领域

    • RS485:常用于需要多设备连接和远距离传输的场合,例如工业控制系统、自动化设备、仪器仪表等。
    • RS232:常见于个人计算机与打印机、调制解调器、串口设备等之间的连接。

2)Modbus协议是什么?

Modbus协议是一种通信协议,通常用于工业自动化领域中的设备间通信。它是一种开放的串行通信协议,最初由Modicon公司开发,现在由Modbus组织(Modbus Organization)管理和推广。

主要特点包括:

  1. 通信方式:Modbus协议可以通过串口(如RS485、RS232)或以太网(TCP/IP)进行通信,因此具有较好的灵活性。

  2. 简单性:它设计简单直接,易于实现和维护,适合于各种工业设备之间的数据交换和控制。

  3. 协议结构:Modbus协议通常包括请求-响应的结构,主要有以下几种常见的变体:

    • Modbus RTU:基于二进制方式在串口上通信,通常用于RS485等串口通信。
    • Modbus ASCII:基于ASCII码在串口上传输,用于一些特殊的应用场景。
    • Modbus TCP/IP:在以太网上使用TCP/IP协议进行通信,支持更高的通信速度和远程访问。
  4. 功能码:Modbus协议使用功能码来指定执行的操作,如读取数据、写入数据或执行特定的控制功能。

应用领域:

  • 工业自动化:控制系统中常用于PLC(可编程逻辑控制器)、传感器、执行器等设备之间的数据交换和控制。
  • 能源管理:用于监测和控制电力系统、能源分配系统等。
  • 建筑自动化:在楼宇自动化系统中应用广泛,用于监控和控制照明、空调、安防系统等。

总体来说,Modbus协议由于其简单性、可靠性和广泛应用性,成为了工业控制领域中的一种主流通信标准,支持多种设备间的数据交换和控制操作。


3)如果让你设计一款 12路车载超声波雷达,采用 stm32F103+HC-SR04超声波模块,对外提供RS485和Modbus协议,你的设计方案是什么?

设计一款12路车载超声波雷达,采用STM32F103和HC-SR04超声波模块,同时支持RS485通信和Modbus协议,可以考虑以下设计方案:

硬件设计:

  1. STM32F103微控制器

    • 使用STM32F103作为主控制器,它具有足够的计算能力和丰富的外设接口,适合于实时数据处理和通信任务。
  2. HC-SR04超声波模块

    • 每路超声波雷达使用HC-SR04模块进行测距,该模块简单实用,能够准确测量距离并输出数字化的距离数据。
  3. RS485通信接口

    • 集成RS485驱动芯片,确保稳定的长距离通信能力。
    • 使用STM32F103的USART(通用同步/异步收发器)接口实现RS485通信,同时支持多个设备连接。

软件设计:

  1. Modbus协议栈实现

    • 在STM32F103上实现Modbus RTU协议栈,支持读取和写入超声波雷达的距离数据。
    • 实现Modbus功能码,包括读取测距数据、设备配置等功能,确保与其他Modbus设备的兼容性。
  2. 实时数据处理

    • 使用STM32F103的定时器和中断功能,实现超声波模块的触发和测量控制,确保精准的距离测量和数据更新。
  3. 多路数据管理

    • 设计合适的数据结构和算法,管理和处理12路超声波雷达的距离数据,确保高效的数据采集和传输。
  4. 通信接口管理

    • 在STM32F103上实现RS485通信协议,包括物理层控制和数据帧格式处理,确保稳定可靠的通信连接。

功能和性能:

  • 实时性:保证测距数据的实时性和精确性,适应车载环境的复杂条件。
  • 稳定性:使用STM32F103的硬件看门狗和软件复位机制,提高系统的稳定性和可靠性。
  • 可扩展性:设计硬件和软件接口,方便将来扩展更多的超声波雷达通道或其他传感器。

软件架构:

  • 采用模块化设计,包括底层驱动、通信协议栈、数据处理模块和应用层接口,确保易于维护和升级。

这样设计的车载超声波雷达能够稳定、精确地测量距离,并通过RS485和Modbus协议与其他设备进行通信,适用于智能汽车等各种应用场景。

                        
部分参考链接:https://blog.csdn.net/qq_65913626/article/details/139239465

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值