基于RT-Thread的HC-SR04超声波驱动

前言

本次驱动用的是这款超声波,超声波的驱动大同小异,均可参考
在这里插入图片描述

一、引脚定义

引脚功能
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)如何打印输出浮点数
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

先睡个好觉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值