基于stm32的超声波HC-SR04测距仪含距离报警(温度补偿)_超声波测距温度补偿

对BEEP模块感兴趣的读者朋友可以试试用PWM调节去控制BEEP模块,感受一下BEPP放出的另类音乐

四、OLED模块

关于OLED的使用与原理不熟悉的笔者欢迎去笔者另一篇文章学习。【强烈推荐】基于stm32的OLED各种显示实现(含动态图)_混分巨兽龙某某的博客-CSDN博客_stm32使用oled显示屏手把手教你彻底搞懂基于stm32的OLED的使用,教程中包含各种API函数的使用。满足几乎所有OLED显示的需要。文章末尾附带源码,强烈推荐!!!外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传https://blog.csdn.net/black_sneak/article/details/125418537?spm=1001.2014.3001.5501

五、CubexMX配置

1、RCC配置外部高速晶振(精度更高)——HSE;

2、SYS配置:Debug设置成Serial Wire否则可能导致芯片自锁);

3.1、GPIO配置:PB1设置为普通输出(DHT11的DATA接线引脚);

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

3.3、GPIO配置:PB8板子上默认接通BEEP的引脚,默认低电平;

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

5、TIM2配置:设置定时器TIM2每1us向上计数一次通道1为上升沿捕获并连接到超声波模块的ECHO引脚,记得开启定时器中断(涉及到捕获中断+定时器溢出中断)。

6、I2C2配置:作为OLED的通讯方式;

7、时钟树配置:

8**、工程配置**

六、代码

6.1、超声波HC-SR04模块代码

其实,超声波HC-SR04的驱动就是基于GPIO口的调用。同时,由于超声波测距模块是基于超声波的物理性质,去进行距离测量,故此其精度受到很多因素影响(这里我们考虑温度堆砌影响)

HC-SR04.h:

#ifndef HCSR04_H_
#define HCSR04_H_
 
#include "main.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"
#include "tim.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);
  Tims_delay_us(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;
}

由于利用中断去读取定时测算的脉冲距离,所以这里需要重写定时器的中断服务函数。(这部分放在main.c最后即可)

/* 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 */

6.2、温湿度DTH11模块代码

DTH11.H代码:

#ifndef __DHT11_H__
#define __DHT11_H__
 
/* Private includes ----------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
#include "stdio.h"
#include "tim.h"
#include "stm32f1xx.h"
 
/* Private define ------------------------------------------------------------*/
#define DHT11_PIN_SET   HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET)                                            //  ??GPIO??
#define DHT11_PIN_RESET HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET)                                          //  ??GPIO??
#define DHT11_READ_IO   HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_9)                                                          //  DHT11 GPIO??
 
#define DLY_TIM_Handle (&htim2)                                                                                     //  ?????
 
 
/* Private variables ---------------------------------------------------------*/
 
/* Private typedef -----------------------------------------------------------*/
 
/* Private function prototypes -----------------------------------------------*/
void DHT11(void);
void DHT11_START(void);
unsigned char DHT11_READ_BIT(void);
unsigned char DHT11_READ_BYTE(void);
unsigned char DHT11_READ_DATA(void);
unsigned char DHT11_Check(void);
static void DHT11_GPIO_MODE_SET(uint8_t mode);
void delay_us(uint16_t nus);
float data_compensate();        //★补偿函数
    
#endif

DTH11.C代码:

#include "dht11.h"
#include "oled.h" 
#include "hc-sr04.h"

/**
  * @brief  DHT11Çý¶¯º¯Êý
  * @param  void
  * @retval None
  */
void DHT11(void)
{
		DHT11_READ_DATA();
    HAL_Delay(50);  		             //  ãÐÉèÑÓ³Ù
}
 
/**
  * @brief  ????????????
  * @param  void
  * @retval None
  */
void DHT11_START(void)
{
    DHT11_GPIO_MODE_SET(0);                         //  ?????????
    
    DHT11_PIN_RESET;                                //  ??????
    
    HAL_Delay(20);                                  //  ???? 18 < ms > 30
    
    DHT11_GPIO_MODE_SET(1);                         //  ?????????,??DHT11??
}                                                   //  ?????????,GPIO -> 1
 
/**
  * @brief  ?????? 1bit
  * @param  void
  * @retval 0/1
  */
unsigned char DHT11_READ_BIT(void)
{
    while(!DHT11_READ_IO);                          //  ???????? 
    
    Tims_delay_us(40);                              //  ????????
    
    if(DHT11_READ_IO)                               //  ????????????? 1
    {
        while(DHT11_READ_IO);                       //  ????????
        return 1;
    }   
    else                                            //  ??????? 0
    {
        return 0;
    }
}
 
/**
  * @brief  ???????? 1byte / 8bit
  * @param  void
  * @retval temp
  */
unsigned char DHT11_READ_BYTE(void)
{
    uint8_t i,temp = 0;                             //  ??????
    
    for(i=0; i<8 ;i++)
    {
        temp <<= 1;                                 
        if(DHT11_READ_BIT())                        //  1byte -> 8bit
        {
            temp |= 1;                              //  0000 0001
        }
    }
    return temp;
}
 
/**
  * @brief  ?????????? 5byte / 40bit
  * @param  void
  * @retval 0/1/2
  */
float DHT11_READ_DATA(void)
{
    uint8_t i;
    uint8_t data[5] = {0};
    
    DHT11_START();                                  //  ????????
    
    if(DHT11_Check())                               //  ??DHT11??     
    {  
        while(!DHT11_READ_IO);                      //  ??DHT11????????
        while(DHT11_READ_IO);                       //  ??DHT11????????
        
        for(i=0; i<5; i++)
        {                        
            data[i] = DHT11_READ_BYTE();            //  ?? 5byte
        }
        
        if(data[0] + data[1] + data[2] + data[3] == data[4])
        {
					//温度显示
					OLED_ShowCN_STR(0,2,5,2);
					OLED_ShowStr(32,2,":",2);
                    OLED_ShowNum(40,2,data[2],2,16);
					OLED_ShowCN_STR(59,2,7,1);

					OLED_ShowCN_STR(0,6,11,3);
					OLED_ShowStr(48,6,":",2);
					OLED_Showdecimal(55,6,data_compensate(data[2]),3,2,16);
					OLED_ShowStr(100,6,"cm",2);
					
//				//ʪ¶ÈÏÔʾ
//				OLED_ShowCN_STR(0,6,2,2);
//				OLED_ShowStr(32,6,":",2);
//				OLED_ShowNum(40,6,data[0],2,16);
//				OLED_ShowStr(59,6,"HR",2);
            return data_compensate(data[2]);                               //  ??????
        }
        else
        {
            return 0;                               //  ??????
        }
    }
    else                                            //  ??DHT11???
    {
        return 2;
    }
}
 
/**
  * @brief  ????????????(??DHT11?????)
  * @param  void
  * @retval 0/1
  */
unsigned char DHT11_Check(void)
{
    Tims_delay_us(40);
    if(DHT11_READ_IO == 0)                          //  ???DHT11??
    {
        return 1;
    }
    else                                            //  ???DHT11???
    {
        return 0;
    }
}
 
/**
  * @brief  ??????
  * @param  mode: 0->out, 1->in
  * @retval None
  */
static void DHT11_GPIO_MODE_SET(uint8_t mode)
{
    if(mode)
    {
        /*  ??  */
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.Pin = GPIO_PIN_1;                   //  9???
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;             //  ????
        GPIO_InitStruct.Pull = GPIO_PULLUP;                 //  ????
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    }
    else 
    {
        /*  ??  */
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.Pin = GPIO_PIN_1;                //  9???
        GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;      //  Push Pull ??????
        GPIO_InitStructure.Pull = GPIO_PULLUP;              //  ????
        GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;    //  ??
        HAL_GPIO_Init(GPIOB,&GPIO_InitStructure);
    }
}

float data_compensate(int data)
{	
	float newspeed = 331.45+0.607*data;
	Hcsr04Info.distance = (Hcsr04Info.high_level_us / 1000000.0) * newspeed / 2.0 * 100.0;
	return Hcsr04Info.distance;
}

///**
//  * @brief  ?????us,Prescaler -> 72-1
//  * @param  us: <= 65535
//  * @retval None
//  */
//void Tims_delay_us(uint16_t nus)
//{
//	__HAL_TIM_SET_COUNTER(DLY_TIM_Handle, 0);
//	__HAL_TIM_ENABLE(DLY_TIM_Handle);
//	while (__HAL_TIM_GET_COUNTER(DLY_TIM_Handle) < nus)
//	{
//	}
//	__HAL_TIM_DISABLE(DLY_TIM_Handle);
//}
 
/**
  * @brief  ???? us , ??? 72M ?????
  * @param  us: <= 4294967295
  * @retval None
  */
void Coarse_delay_us(uint32_t us)
{
    uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);
    while (delay--)
	{
		;
	}
}

6.3、BEEP报警显示模块代码

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

[外链图片转存中…(img-rqWWS3nu-1715685796834)]

[外链图片转存中…(img-JjmTNknt-1715685796834)]

[外链图片转存中…(img-18gmGyvl-1715685796835)]

[外链图片转存中…(img-lk25dccJ-1715685796835)]

[外链图片转存中…(img-NQHAx9zx-1715685796836)]

[外链图片转存中…(img-eKvGd0C9-1715685796836)]

[外链图片转存中…(img-c2yNaNnv-1715685796837)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是基于STM32hc-sr04超声波测距模块的代码示例: ```c #include "stm32f10x.h" #define Trig_Pin GPIO_Pin_0 #define Echo_Pin GPIO_Pin_1 #define Trig_Port GPIOC #define Echo_Port GPIOC void TIM2_Configuration(void); float ultrasonic_measure(void); int main(void) { float distance; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Pin = Trig_Pin; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Trig_Port, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = Echo_Pin; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Echo_Port, &GPIO_InitStruct); TIM2_Configuration(); while(1) { distance = ultrasonic_measure(); } } void TIM2_Configuration(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; TIM_TimeBaseInitStruct.TIM_Prescaler = 72 - 1; TIM_TimeBaseInitStruct.TIM_Period = 0xFFFF; TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); TIM_OCInitTypeDef TIM_OCInitStruct; TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStruct.TIM_Pulse = 0; TIM_OC1Init(TIM2, &TIM_OCInitStruct); TIM_Cmd(TIM2, ENABLE); } float ultrasonic_measure(void) { uint16_t TIM2_CountStart, TIM2_CountEnd; float Distance; GPIO_ResetBits(Trig_Port, Trig_Pin); TIM_SetCounter(TIM2, 0); while(TIM_GetCounter(TIM2) < 10); // delay 10us GPIO_SetBits(Trig_Port, Trig_Pin); while(GPIO_ReadInputDataBit(Echo_Port, Echo_Pin) == RESET); TIM_Cmd(TIM2, ENABLE); while(GPIO_ReadInputDataBit(Echo_Port, Echo_Pin) == SET); TIM_Cmd(TIM2, DISABLE); TIM2_CountStart = TIM2->CCR1; TIM2_CountEnd = TIM_GetCapture1(TIM2); Distance = (float)(TIM2_CountEnd - TIM2_CountStart) * 0.01715f; // Distance = (High level time * sound velocity (340M/S) / 2) return Distance; } ``` 代码中使用了STM32的定时器TIM2进行计时,测量距离的原理是通过发送一个10us的高电平脉冲触发hc-sr04模块,然后接收返回的超声波信号并测量高电平持续时间,最后通过公式计算出距离。需要注意的是,本示例中使用的是72MHz的系统时钟,如果系统时钟不同,需要相应地修改计时器的预分频值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值