【STM32cubeMX+HAL库】US100超声波模块的使用
1、原理简介
US-100超声波测距模块可实现2cm4.5m的非接触测距功能,拥有2.45.5V的宽电压输入范围,静态功耗低于2mA,自带温度传感器对测距结果进行校正,同时具有GPI0,串口等多种通信方式,内带看门狗,工作稳定可靠。
2、电气参数
电气参数 | US-100超声波测距模块 |
---|---|
工作电压 | DC2.4V5.5V |
静态电流 | 2mA |
工作温度 | 20w+70度 |
输出方式 | 电平或UART(跳线帽选择) |
感应角度 | 小于15度 |
探测距离 | 2cm-450cm |
探测精度 | 0.3cm+1% |
UART模式下串口配置 | 波特率9600,起始位1位,停止位1位,数据位8位,无奇偶校验,无流控制 |
3、接口说明
本模块共有两个接口,即模式选择跳线和5Pin接口。模式选择跳线的间距为2.54mm,当插上跳线帽时为UART(串口模式,拔掉时为电平触发模式。
从左到右依次编号1,2,3,4,5。它们的定义如下:
1号Pin:接VCC电源(供电范围2.4V~5.5V)
2号Pin:当为UART模式时,接外部电路UART的TX端;当为电平触发模式 时,接外部电路的Trig端
3号Pin:当为UART模式时,接外部电路UART的RX端;当为电平触发模式 时,接外部电路的Echo端。
4号Pin:接外部电路的地。(接一个就行)
5号Pin:接外部电路的地。
4、产品尺寸
5、 IO模式(电平模式)
在模块上电前,首先去掉模式选择跳线上的跳线帽,使模块处于电平触发模式。电平触发测距的时序如下图所示:
US-100测距时序图表明:只需要在Trig/TX管脚输入一个10US以上的高电平,系统便可发出8个40KHZ的超声波脉冲,然后检测回波信号。当检测到回波信号后,模块还要进行温度值的测量,然后根据当前温度对测距结果进行
校正,将校正后的结果通过Echo/RX管脚输出。在此模式下,模块将距离值转化为340m/s时的时间值的2倍,通过Echo端输出一高电平,可根据此高电平的持续时间来计算距离值。即距离值为:(高电平时间*340m/s)/2。注:因为距离值经经过温度校正,此时无需再根据环境温度对超声波声速进行校正,即不管温度多少,声速选择340/s即可。
6、UART串口模式
6.1、UART串口模式测距
在模块上电前,首先插上模式选择跳线上的跳线帽,使模块处于串口
触发模式。
在此模式下只需要在Trig/TX管脚输入0X55(波特率9600),系统便
可发出8个40KHZ的超声波脉冲,然后检测回波信号。当检测到回波信
号后,模块还要进行温度值的测量,然后根据当前温度对测距结果进
行校正,将校正后的结果通过Echo/RX管脚输出。
输出的距离值共两个字节,个字节是距离的高8位(HDate),第二个
字节为距离的低8位(LData),单位为毫米。即距离值为(HData*256+
LData)mm。
6.2、UART串口模式测温
在模块上电前,首先插上模式选择跳线上的跳线帽,使模块处于串口
触发模式。
在此模式下只需要在Trig/TX管脚输入0X50(波特率9600),系统便
启动温度传感器对当前温度进行测量,然后将温度值通过Echo/RX管
脚输出。
测量完成温度后,本模块会返回一个字节的温度值(TData),实际
的温度值为TData-45。例如通过TX发送完0X50后,在RX端收到0X45,
则此时的温度值为[69(0X45的10进制值)-45]=24度。
7、STM32cubeMX配置
8、程序篇(未完篇)
8.1、 IO模式测距(电平模式)
8.2、定时器输入捕获模式 IO模式测距
搞这个首先吐槽一下这杜邦线,是真的拉,从硬件到软件检查了十几遍,没想到是杜邦线出了问题,建议同学们学习一个模块可以立创EDA自己画个板子,直接插上去,避免这种低级错误!
言归正传,超声波定时器输入捕获模式 IO模式测距的原理就是IO测距的原理,只不过将IO模式下的while(ECNO ==0)变成了HAL_TIM_ReadCapturedValue()而已。大同小异。会这种方式,第一种简单的不要不要的,首先还是编程思路:
开启定时器中断,中断使能,以确保能够进行输入捕获,给TRIG一个高电平,时间大于10US,然后拉低,如果正常,则会触发两种回调,一种中断溢出回调,一种捕获回调
中断溢出:
当计时到达我们预设的装载值时,就会产生溢出,我们本次实验是65535,当到达这个值时,会触发中断溢出,我们可以进行的操作时计数,就是看他离触发捕获回调一共产生了多少个中断溢出,
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (TIM2 == htim->Instance)
{
tim_capture_overflow_count++;
}
}
捕获回调函数:
就是收到了信号,因为ECNO引脚我们设置为输入捕获状态,当其引脚电平变化时,就会触发该回调
逻辑与(&&)的作用是确定定时器和通道正确。
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
/* void US100_Capture_Cb(TIM_HandleTypeDef *htim)//这个函数是自己注册的,也可以使用HAL_TIM_RegisterCallback(&htim2, HAL_TIM_IC_CAPTURE_CB_ID, US100_Capture_Cb)进行注册一个自己定义的回调,都一样*/
{
// printf("US100_Capture_Cb\r\n");
if (( htim->Instance== TIM2) && (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4))
{
switch (tim_capture_cnt)
{
case 1:
{
// printf("case 1\r\n");
capture_Buf[0] = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_4);//捕获到上升沿,获取第一个时间节点
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_4, TIM_ICPOLARITY_FALLING); // 清除上一次的捕获极性,并设置为下降沿捕获
tim_capture_cnt++;
tim_capture_overflow_count = 0;//清除溢出值
break;
}
case 2:
{
// printf("case 2\r\n");
capture_Buf[1] = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_4); // 获取第二个时间节点.
// HAL_TIM_IC_Stop_IT(&htim2, TIM_CHANNEL_4);
us100_rev_flag = 1;// 标志位为1,则为接收到了正确的数据
tim_capture_cnt = 0;//case值记为零
break;
}
}
}
}
然后就是计算高电平时间:
float US100_High_Time(void)
{
uint16_t length;
capture_Buf[1] = capture_Buf[1] + tim_capture_overflow_count*65536;//加上溢出值
high_time[0] = capture_Buf[1] - capture_Buf[0];
//high_time[0]是微秒,先化为秒,high_time[0]/1000000,再通过公式计算距离,high_time[0]/1000000*340/2=Value (m/s),可以再乘以100,就是(cm/s)
length = (high_time[0])*34000/2000000.0;
return length;
}
在TIMz.c文件中,要使能中断
void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 71;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 65535;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_IC_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
// HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_4);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_4, TIM_INPUTCHANNELPOLARITY_RISING);
/* USER CODE END TIM2_Init 2 */
}
main函数中:
while (1)
{
if (us100_rev_flag == 1)
{
us100_rev_flag = 0;
tim_capture_cnt++;
printf("Lengh:%.2fcm\r\n", US100_High_Time());
memset(high_time, 0, HIRG_TIME_LEN);
US100_Start();
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_4, TIM_INPUTCHANNELPOLARITY_RISING);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
bsp_us100.h中
/*
* @Author: MBW
* @Date: 2023-04-14 11:00:56
* @LastEditors: MBW
* @LastEditTime: 2023-04-14 18:06:09
* @FilePath: \stm32f103rct6_us100_tset\bsp\inc\bsp_us100.h
* @Description:
*
* Copyright (c) 2023 by MBW, All Rights Reserved.
*/
#ifndef __BSP_US100_H__
#define __BSP_US100_H__
#include "main.h"
#include "tim.h"
#include "usart.h"
#define HIRG_TIME_LEN 1
extern uint16_t tim_capture_cnt; //溢出次数
extern uint8_t us100_rev_flag; //接收标志位
extern uint16_t capture_Buf[3]; //存放计数值
extern uint16_t high_time[HIRG_TIME_LEN]; //高电平时间
#define TRIG_HIGH HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET)
#define TRIG_LOW HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET)
void US100_Start(void);
float US100_High_Time(void);
#endif // ! __BSP_US100_H__
bsp_us100.c
/*
* @Author: MBW
* @Date: 2023-04-14 11:01:04
* @LastEditors: MBW
* @LastEditTime: 2023-04-14 23:44:38
* @FilePath: \stm32f103rct6_us100_tset\bsp\src\bsp_us100.c
* @Description:
*
* Copyright (c) 2023 by MBW, All Rights Reserved.
*/
#include "bsp_us100.h"
#include "bsp_delay.h"
// high_time = tim_capture_cnt*65536+tim_capture_val
uint16_t tim_capture_cnt = 0; // 计数
uint16_t tim_capture_overflow_count = 0; //溢出值
uint8_t us100_rev_flag = 0; // 接收标志位
uint16_t capture_Buf[3] = {0}; // 存放计数值
uint16_t high_time[HIRG_TIME_LEN]; // 高电平时间
void US100_Start(void);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
void US100_Capture_Cb(TIM_HandleTypeDef *htim);
float US100_High_Time(void);
void US100_Start(void)
{
TRIG_LOW;
HAL_Delay(1);
TRIG_HIGH;
HAL_Delay(1);
TRIG_LOW;
// HAL_TIM_RegisterCallback(&htim2, HAL_TIM_IC_CAPTURE_CB_ID, US100_Capture_Cb);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (TIM2 == htim->Instance)
{
tim_capture_overflow_count++;
}
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
// void US100_Capture_Cb(TIM_HandleTypeDef *htim)
{
if (( htim->Instance== TIM2) && (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4))
{
switch (tim_capture_cnt)
{
case 1:
{
// printf("case 1\r\n");
capture_Buf[0] = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_4);//捕获到上升沿,获取第一个时间节点
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_4, TIM_ICPOLARITY_FALLING); // 清除上一次的捕获极性,并设置为下降沿捕获
tim_capture_cnt++;
tim_capture_overflow_count = 0;//清除溢出值
break;
}
case 2:
{
// printf("case 2\r\n");
capture_Buf[1] = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_4); // 获取第二个时间节点.
us100_rev_flag = 1;// 标志位为1,则为接收到了正确的数据
tim_capture_cnt = 0;//case值记为零
break;
}
}
}
}
float US100_High_Time(void)
{
uint16_t length;
capture_Buf[1] = capture_Buf[1] + tim_capture_overflow_count*65536;//加上溢出值
high_time[0] = capture_Buf[1] - capture_Buf[0];
length = (high_time[0])*34000/2000000.0;
return length;
}