前言
本次驱动用的是这款超声波,超声波的驱动大同小异,均可参考
一、引脚定义
引脚 | 功能 |
---|---|
VCC | 接直流5V电 |
TRIG | 接外部电路的TRIG端,向此引脚输入10us以上的高电平可触发超声波测距 |
ECHO | 接外部电路的ECHO端,测距结束时该引脚会输出一个高电平,电平宽度为超声波往返时间之和 |
GND | 接地 |
二、工作原理
1、采用 IO 触发测距,给至少 10us 的高电平信号;
2、模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
3、有信号返回,通过 IO 输出一高电平,高电平持续的时间就是超声波从发射到返回的时间
4、测试距离=(高电平时间*声速(340M/S))/2;
三、引脚时序图
建议测量周期在60ms以上,防止发射信号对回响信号的有影响
四、创建RTT工程(开始动手)
五、打开CubeMX
六、配置串行调试口
七、配置使用外部高速晶振
八、创建工程时默认使用了串口一,这里也打开串口一
九、开启定时器三,定时器三是用来给超声波回波信号计时的,计算高电平时间从而得到测量距离
十、配置时钟线
十一、生成代码
十二、打开定时器设备驱动程序
十三、使能定时器模块
十四、打开定时器三的注释(使用哪个定时器就打开哪个,没有的就自己写上去)
十五、在主函数中写入如下代码
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-05-10 先睡个好觉 first version
*/
#include <rtthread.h>
#include <rtdevice.h> //加载设备驱动头文件
#include <board.h>
#include <hwtimer.h>
#define HWTIMER_DEV_NAME "timer3" /* 定时器名称 */
rt_device_t hw_dev; /* 定时器设备句柄 */
rt_err_t ret = RT_EOK; //返回值判断是否成功
rt_uint32_t timer_cb_num = 0; /*进定时器超调函数次数 */
rt_uint32_t level_flag = 1; /*判断超声波接受引脚是否是第一个上升沿*/
rt_uint32_t echo_high_time = 0; //超声波接受引脚高电平总时间,单位为us
rt_uint32_t freq = 1000000; /* 计数频率 */
rt_hwtimer_mode_t mode; /* 定时器模式 */
rt_hwtimerval_t timeout_s; /* 定时器超时值 */
rt_uint32_t distance_cm = 0; //超声波测量出的距离
#define SR04T_PIN_TRIG GET_PIN(C, 9) //获取sr04t超声波触发引脚号
#define SR04T_PIN_ECHO GET_PIN(C, 8) //获取sr04t超声波接收引脚号
/* 定时器3超时回调函数,每10us会进来一次*/
static rt_err_t timeout3_cb(rt_device_t dev, rt_size_t size)
{
timer_cb_num++;//每进一次超调函数,该变量加一
if((rt_pin_read(SR04T_PIN_ECHO) == PIN_HIGH)&&(level_flag))
{
timer_cb_num = 0; //如果超声波接收引脚被拉高了,重新进行计数
level_flag = 0;
}
if ((rt_pin_read(SR04T_PIN_ECHO) == PIN_LOW)&&(level_flag == 0))
{
echo_high_time = timer_cb_num*10; //一个timer_cb_num是10us
level_flag = 1;
rt_kprintf("%d\n",timer_cb_num/9);
}
return 0;
}
int sr04_Init(void)
{
//设置sr04t超声波引脚的模式
rt_pin_mode(SR04T_PIN_TRIG, PIN_MODE_OUTPUT);//设置引脚为输出模式
rt_pin_mode(SR04T_PIN_ECHO, PIN_MODE_INPUT_PULLDOWN);//设置ECHO引脚为输入模式
rt_pin_write(SR04T_PIN_TRIG, PIN_LOW);//拉低引脚
rt_pin_write(SR04T_PIN_ECHO, PIN_LOW);//拉低引脚
/* 查找定时器设备 */
hw_dev = rt_device_find(HWTIMER_DEV_NAME);
if(hw_dev == RT_NULL)
{
rt_kprintf("hwtimer sample run failed! can't find %s device! \n",HWTIMER_DEV_NAME);
return RT_ERROR;
}
/* 以读写方式打开设备 */
rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
if(ret != RT_EOK)
{
rt_kprintf("open %s device failed!\n",RT_DEVICE_OFLAG_RDWR);
return ret;
}
/* 设置超时回调函数 */
rt_device_set_rx_indicate(hw_dev, timeout3_cb);
/* 设置计数频率(若未设置该项,默认为1Mhz 或 支持的最小计数频率) */
rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);
/* 设置模式为周期性定时器(若未设置,默认是HWTIMER_MODE_ONESHOT)*/
mode = HWTIMER_MODE_PERIOD;
rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
/* 设置定时器超时值为10us并启动定时器 */
timeout_s.sec = 0; /* 秒 */
timeout_s.usec = 10; /* 微秒 */
if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
{
rt_kprintf("set timeout value failed\n");
return RT_ERROR;
}
return RT_EOK;
}
//信号触发
void US_SendStartSignal(void)
{
rt_pin_write(SR04T_PIN_TRIG, PIN_HIGH);//拉高引脚,触发信号
rt_hw_us_delay(20); //给20us的延时
//rt_thread_mdelay(5);
rt_pin_write(SR04T_PIN_TRIG, PIN_LOW);//拉低引脚
}
//数据处理
//count传进去的参数是us
float SR04T_DataConversion(rt_uint32_t *count)
{
float result = 0;
result = (float)((float)(*count * 340) / 2000000.0);
*count = 0;
result = result*100.0; //将米转化为厘米
return result;
}
//-------------------超声波线程-----------------------------------------------
rt_thread_t Sr04Th_Handler; //姿态解算线程句柄
#define Sr04_TH_PRIO 10 //姿态解算线程优先级
#define Sr04_STK_SIZE 700 //姿态解算线程堆栈大小
#define Sr04_TICK_LEN 5 //姿态解算线程执行时间
void th_sr04_entry(void *parameter)
{
rt_uint16_t num_trig_time=0;
while(1)
{
num_trig_time++;
if(num_trig_time>12)
{
num_trig_time = 0;
US_SendStartSignal();//超声波信号触发
}
distance_cm = SR04T_DataConversion(&timer_cb_num);//超声波数据处理
//rt_kprintf("%d\n",echo_high_time/28);
rt_thread_mdelay(5);
}
}
int sr04_th_creat(void)
{
//超声波线程
Sr04Th_Handler = rt_thread_create("th_sr04_entry",th_sr04_entry,NULL,Sr04_STK_SIZE,Sr04_TH_PRIO,Sr04_TICK_LEN);
if(Sr04Th_Handler == NULL)
{
rt_kprintf("th_sr04_entry(create)failed...\n");
return -ENOMEM;
}
return RT_EOK;
}
void th_start(void)
{
rt_thread_startup(Sr04Th_Handler); //开启超声波线程线程调度
}
int main(void)
{
sr04_Init(); //超声波初始化
sr04_th_creat();//超声波线程创建
th_start();//开启线程调度
return RT_EOK;
}
十六、编译,有如下报错,先双击进入第一个错误
十七、把这段代码进行注释
十八、再编译还剩这个报错,找不到hwtimer.h文件
十九、跳转进入这个头文件
二十、找到它的文件路径
二十一、打开构建配置,进行路径包含,应用后关闭
二十二、再次编译,报错解决
二十三、连接好硬件
二十四、下载程序,查看串口一,有数据输出,并且随着遮挡物的远近,数据大小有变化
二十五、这里需要注意一下,如果你使用的定时器里面没有,需要模仿里面的结构自行添加
二十六、最后提醒一下,代码中输出的并不是准确的cm数,我只是随意除了一个数字就输出了,数据转换函数在代码中我也写了,不过没有使用,因为它输出的是浮点数,rtthread要想打印浮点数需要另行配置,在这个工程里我没有配置,所以要想得到精确的cm数,请自行数据转换。
rtthread输出浮点数,可以参考我的这篇文章
⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇
RT-Thread(RTT)如何打印输出浮点数