RT-Thread Env开发探索——以HC-SR04超声波传感器为例

RT-Thread Env开发探索——以HC-SR04超声波传感器为例

  • 0.前言
  • 一、BSP优化
    • 1.修改芯片功能配置
    • 2.修改RTT配置菜单
  • 二、软件包加载
    • 1.外设配置
    • 2.驱动框架配置
    • 3.软件包配置
  • 三、编译及运行
  • 四、源码分析
  • 五、总结


参考文章:RT Thread Env + CLion环境搭建

0.前言

  对比使用RT Thread Stduio开发程序,使用Env工具的开发流程还是比较繁琐的,但是为了使用最新内核和现代化的IDE工具,不得不做出一些妥协。笔者这里就以开发HC-SR04超声波传感器为例,来介绍一下相关的开发流程。此外笔者在实际的开发过程中,觉得这种开发模式还是有一定的提升空间,所以后续还是暂时使用FreeRTOS吧,RTT的使用会先告一段落。

一、BSP优化

  使用Env工具进行开发时,最重要的就是做好板级支持包BSP文件,在上一篇文章中提到,rt-thread源码目录中的bsp目录下,已经适配好了一些板级支持包,如果没有自己所使用的芯片信号,可以参考RT Thread官方的文档手册进行制作。笔者这篇就主要介绍如何在已有的bsp上制作最小支持包,以及一些简单功能的适配。

1.修改芯片功能配置

  在上一篇文章中,通过scons --dist命令已经生成了现有芯片的板级支持包,生成了project工程模板后,复制一份作为自己的初始工程,在此项目目录中找到CubeMX_Config目录,打开CubeMX工程,即可修改一些现有的芯片配置:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里笔者只开启了基础的SW调试口、UART1串口,以及TIM7定时器供后续超声波传感器使用,然后配置好芯片时钟即可一键生成初始化代码,生成的代码只需要保留以下四个文件即可,其他文件是否保留无关紧要:
注:此处生成的代码,和系统时钟有关的初始化代码会被自动加载到工程中,但如果想自己添加一些其他的外设,则需要自行手动移植对应的配置代码。
在这里插入图片描述

2.修改RTT配置菜单

  修改了芯片配置后,原先的板级配置文件可能就无法生效了,甚至可能造成一些问题,所以需要针对自己已使能的外设,重新修改相关的配置文件。用文本方式打开board目录下的KConfig文件,将其修改成如下内容:

menu "Hardware Drivers Config"menu "Onboard Peripheral Drivers"endmenumenu "On-chip Peripheral Drivers"config BSP_USING_GPIObool "Enable GPIO"select RT_USING_PINdefault ymenuconfig BSP_USING_UARTbool "Enable UART"default yselect RT_USING_SERIALif BSP_USING_UARTconfig BSP_USING_UART1bool "Enable UART1"default yconfig BSP_UART1_RX_USING_DMAbool "Enable UART1 RX DMA"depends on BSP_USING_UART1 && RT_SERIAL_USING_DMAdefault nendifmenuconfig BSP_USING_TIMbool "Enable Hardware TIM"default nselect RT_USING_HWTIMERif BSP_USING_TIMconfig BSP_USING_TIM7bool "Enable TIM7"default nendifmenuconfig BSP_USING_SPIbool "Enable SPI BUS"default nselect RT_USING_SPIif BSP_USING_SPIconfig BSP_USING_SPI1bool "Enable SPI1 BUS"default nconfig BSP_SPI1_TX_USING_DMAbool "Enable SPI1 TX DMA"depends on BSP_USING_SPI1default nconfig BSP_SPI1_RX_USING_DMAbool "Enable SPI1 RX DMA"depends on BSP_USING_SPI1select BSP_SPI1_TX_USING_DMAdefault nendifmenuconfig BSP_USING_I2C1bool "Enable I2C1 BUS (software simulation)"default nselect RT_USING_I2Cselect RT_USING_I2C_BITOPSselect RT_USING_PINif BSP_USING_I2C1config BSP_I2C1_SCL_PINint "i2c1 scl pin number"range 1 216default 15config BSP_I2C1_SDA_PINint "I2C1 sda pin number"range 1 216default 16endifmenuconfig BSP_USING_PWMbool "Enable PWM"default nselect RT_USING_PWMif BSP_USING_PWMmenuconfig BSP_USING_PWM2bool "Enable timer2 output PWM"default nif BSP_USING_PWM2config BSP_USING_PWM2_CH1bool "Enable PWM2 channel 1"default nconfig BSP_USING_PWM2_CH2bool "Enable PWM2 channel 2"default nconfig BSP_USING_PWM2_CH3bool "Enable PWM2 channel 3"default nendifendifsource "$BSP_DIR/libraries/HAL_Drivers/drivers/Kconfig"endmenumenu "Board extended module Drivers"endmenuendmenu

  这里是一些常见外设的添加模版,需要开发人员有一些KConfig的编辑基础,或者其实找一些其他的模版文件照着修改也可以。这里笔者使能了PIN设备驱动、UART驱动和TIM驱动,其他的外设驱动设置default n默认关闭,后续有需要再开启。这个配置文件本质上就是通过在menuconfig中选择是否开启相关功能,来设置是否开启代码中的一些相关的宏定义,进而就可以控制是否添加相关的功能模块源码。
  至此,一个最小BSP支持包就制作完毕,不过有一点还需要注意:在这个模板中,笔者使用了TIM7作为超声波传感器的硬件定时器依赖,但是默认的RT Thread内核中,为STM32F1系列声明的定时器名称并没有这么多,所以需要在tim_config.h中手动添加
在CLion中全局搜索一个现有定时器,找到对应的板级配置头文件,然后仿照现有的新建一个即可。除此之外,如果使用一些其他硬件外设,编译时提示找不到对应的设备,也可以看看对应的声明有没有添加。
在这里插入图片描述
在这里插入图片描述

二、软件包加载

  修改完BSP后,就可以在menuconfig中开启对应的功能,加载一些需要的软件包以便后续开发。在项目根目录下打开Env窗口,然后打开menuconfig菜单选项:

1.外设配置

Hardware Drivers Config ---> On-chip Peripheral Drivers栏中,即可看到之前在KConfig中设置的一些外设选项。
在这里插入图片描述

2.驱动框架配置

  一些外设或者软件包都需要与内核的驱动框架进行对接,所以需要在RT-Thread Components ---> Device Drivers目录下,使能对应的驱动框架,这里笔者只使能了超声波传感器需要使用的Sensor框架,需要根据实际的需求自行选择:
在这里插入图片描述

3.软件包配置

  RT-Thread已经集成的软件包较多,手动在RT-Thread online packages目录下搜索会比较麻烦,可以按下键盘上的/键,然后输入关键字进行检索,找到想要的条目后,输入对应的序号就可以直接跳入:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
选择完毕后,保存并退出,在Env窗口中输入pkgs --update即可自动将软件包加载到项目中:
在这里插入图片描述

然后使用scons --targer=cmake重新更新一下工程即可。
在这里插入图片描述

三、编译及运行

在CLion中打开项目,直接编译时会报一些错误:
1.头文件未找到
在这里插入图片描述
将这些地方修改为<drivers/sensor.h>
在这里插入图片描述
2.RT_WEAK识别错误:
在这里插入图片描述
将RT_WEAK修改为rt_weak
在这里插入图片描述
3.找不到pin脚
在这里插入图片描述
添加<drv_gpio.h>头文件
在这里插入图片描述
最后修改sr04_sample.c中的设备相关引脚定义和使用的硬件定时器声明,即可编译下载。
在这里插入图片描述
在这里插入图片描述

四、源码分析

sr04的软件包中,主要内容是这个sensor_hc_sr04.c文件,其中实现了向内核注册sensor设备的流程,以及从设备读取数据的接口:
sensor_hc_sr04.c:

/** Copyright (c) 2006-2020, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2020-05-07     shany       the first version*/#include "sensor_hc_sr04.h"
#include "drivers/sensor.h"
#include "board.h"
#include <rtdbg.h>#define DBG_TAG "sensor.hc.sr04"
#define DBG_LVL DBG_INFO#define SENSOR_DISTANCE_RANGE_MAX (400)
#define SENSOR_DISTANCE_RANGE_MIN (2)static struct sr04_device *sr04_dev;rt_weak void rt_hw_us_delay(rt_uint32_t us)
{rt_uint32_t delta;us = us * (SysTick->LOAD / (1000000 / RT_TICK_PER_SECOND));delta = SysTick->VAL;while (delta - SysTick->VAL < us) continue;
}static rt_err_t _sr04_hwtimer_cb(rt_device_t dev, rt_size_t size)
{sr04_dev->err = 0x88;return 0;
}static rt_device_t _sr04_hwtimer_init(void)
{rt_device_t dev;rt_err_t ret = RT_EOK;dev = rt_device_find(sr04_dev->hwtimer);if (dev == RT_NULL) {rt_kprintf("can't find %s device!\n", sr04_dev->hwtimer);return RT_NULL;}ret = rt_device_open(dev, RT_DEVICE_OFLAG_RDWR);if (ret != RT_EOK) {rt_kprintf("open hwtimer device failed!\n");return RT_NULL;}rt_device_set_rx_indicate(dev, _sr04_hwtimer_cb);static rt_hwtimer_mode_t hw_mode = HWTIMER_MODE_PERIOD;ret = rt_device_control(dev, HWTIMER_CTRL_MODE_SET, &hw_mode);if (ret != RT_EOK) {rt_kprintf("set hwtimer mode failed!\n");return RT_NULL;}return dev;
}static rt_err_t _sr04_hwtimer_start(rt_device_t dev)
{rt_hwtimerval_t hw_val;hw_val.sec = 1;hw_val.usec = 0;if (rt_device_write(dev, 0, &hw_val, sizeof(hw_val)) != sizeof(hw_val)) {rt_kprintf("set value failed\n");return RT_ERROR;}return RT_EOK;
}static int32_t _sr04_hwtimer_stop(rt_device_t dev)
{rt_hwtimerval_t hw_val;rt_device_read(dev, 0, &hw_val, sizeof(hw_val));// rt_kprintf("read: sec = %d, usec = %d\n", hw_val.sec, hw_val.usec);rt_device_close(dev);return (int32_t)(hw_val.sec * 1000000 + hw_val.usec);
}int32_t sr04_get_distance(void)
{int32_t duration = 0, distance = 0;rt_device_t dev;dev = _sr04_hwtimer_init();rt_pin_write(sr04_dev->trig_pin, PIN_LOW);rt_hw_us_delay(2);rt_pin_write(sr04_dev->trig_pin, PIN_HIGH);rt_hw_us_delay(10);rt_pin_write(sr04_dev->trig_pin, PIN_LOW);while ((rt_pin_read(sr04_dev->echo_pin) == PIN_LOW));_sr04_hwtimer_start(dev);while ((rt_pin_read(sr04_dev->echo_pin) == PIN_HIGH) && (sr04_dev->err != 0x88));duration = _sr04_hwtimer_stop(dev);distance = (int32_t)(duration * 340.0 / 2000.0 + 0.5);return distance;
}static rt_size_t _sr04_polling_get_data(rt_sensor_t sensor, struct rt_sensor_data *data)
{rt_int32_t distance_x10;if (sensor->info.type == RT_SENSOR_CLASS_PROXIMITY) {distance_x10 = sr04_get_distance();data->data.proximity = distance_x10;data->timestamp = rt_sensor_get_ts();}return 1;
}static rt_size_t sr04_fetch_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len)
{RT_ASSERT(buf);if (sensor->config.mode == RT_SENSOR_MODE_POLLING) {return _sr04_polling_get_data(sensor, buf);}else {return 0;}
}static rt_err_t sr04_control(struct rt_sensor_device *sensor, int cmd, void *args)
{rt_err_t ret = RT_EOK;return ret;
}static struct rt_sensor_ops sensor_ops =
{sr04_fetch_data,sr04_control
};static sr04_device_t _sr04_init(struct rt_sensor_config *cfg)
{rt_base_t *pins;sr04_device_t dev;dev = rt_calloc(1, sizeof(struct sr04_device));if (dev == RT_NULL) {LOG_E("Can't allocate memory for sr04 device on '%s'.\n", cfg->intf.dev_name);return RT_NULL;}dev->hwtimer = cfg->intf.dev_name;rt_kprintf("hwtimer: %s\n", dev->hwtimer);pins = (rt_base_t *)cfg->intf.user_data;// rt_kprintf("trig: %d, echo: %d\n", pins[0], pins[1]);dev->trig_pin = pins[0];dev->echo_pin = pins[1];// rt_kprintf("trig: %d, echo: %d\n", dev->trig_pin, dev->echo_pin);rt_pin_mode(dev->trig_pin, PIN_MODE_OUTPUT);rt_pin_mode(dev->echo_pin, PIN_MODE_INPUT);return dev;
}int rt_hw_sr04_init(const char *name, struct rt_sensor_config *cfg)
{rt_int8_t result;rt_sensor_t sensor_sr04 = RT_NULL;sr04_dev = _sr04_init(cfg);/* sr04 sensor register */sensor_sr04 = rt_calloc(1, sizeof(struct rt_sensor_device));if (sensor_sr04 == RT_NULL) {return -1;}sensor_sr04->info.type       = RT_SENSOR_CLASS_PROXIMITY;sensor_sr04->info.vendor     = RT_SENSOR_VENDOR_UNKNOWN;sensor_sr04->info.model      = "sr04";sensor_sr04->info.unit       = RT_SENSOR_UNIT_CM;sensor_sr04->info.intf_type  = RT_SENSOR_INTF_ONEWIRE;sensor_sr04->info.range_max  = SENSOR_DISTANCE_RANGE_MAX;sensor_sr04->info.range_min  = SENSOR_DISTANCE_RANGE_MIN;sensor_sr04->info.period_min = 5;rt_memcpy(&sensor_sr04->config, cfg, sizeof(struct rt_sensor_config));sensor_sr04->ops = &sensor_ops;result = rt_hw_sensor_register(sensor_sr04, name, RT_DEVICE_FLAG_RDONLY, RT_NULL);if (result != RT_EOK) {LOG_E("device register err code: %d", result);goto __exit;}return RT_EOK;__exit:if (sensor_sr04)rt_free(sensor_sr04);return -RT_ERROR;
}

测距的主要流程:
首先TRIG引脚产生一个10us的高电平信号,即代表开启一次测距,读取到ECHO引脚高电平后,在_sr04_hwtimer_start函数中将定时器的超时时间设置成了1s,如果超时就会触发_sr04_hwtimer_cb回调函数,将标志位置成0x88,在读取ECHO引脚的死循环中,如果高电平结束或者超时标志位被置0x88,则结束本次测距。
问题1:SR04的最大测距量程为4米,所以超时时间可以调小一些,按照一个来回最大量程,预留30ms左右的超时时间即可。(影响不大)
问题2:没有对测距超时的结果做出舍弃,无论本次测距成功或者超时,都会将结果输出。(影响较大)

五、总结

  RT Thread的亮点就是实现了不少驱动框架封装,使得应用层代码可以与底层分离开来,这样如果更换了底层硬件平台,上层的应用代码改动就不是很大。但在笔者的实际使用中发现,目前实现的框架大多只有一些基本功能,比如想要实现STM32的多个ADC外设交替采样,那么还是只能通过手动移植HAL库来实现。
  软件层面的软件包以及驱动框架,目前看起来确实有一些独到之处,毕竟参考了linux内核的实现方式来做的,对于有一定的linux基础的开发人员来说还是比较容易上手。不过软件包的质量良莠不齐,此外在资源有限的单片机上,这种框架所带来的开销也确实需要仔细考量。所以笔者目前对RT Thread的探索就先到这,再观望一阵RTT的发展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/15359.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mac下安装airflow

背景&#xff1a;因为用的是Mac的M芯片的电脑&#xff0c;安装很多东西都经常报错&#xff0c;最近在研究怎么把大数据集群上的crontab下的任务都配置到一个可视化工具中&#xff0c;发现airflow好像是个不错的选择&#xff0c;然后就研究怎么先安装使用起来&#xff0c;后面再…

部署LAMP平台

目录 一、LAMP简介与概述 1.1 各组件作用 1.2 LAMP平台搭建时各组件安装顺序 1.3 httpd服务的目录结构 1.4 httpd.conf配置文件 二、编译安装Apache httpd服务 2.1 关闭防火墙&#xff0c;将安装Apache所需软件包传到/opt目录下 2.2 安装环境依赖包 ​2.3 配置软件模块…

基于RK3588的AI边缘计算网关设计

随着物联网和人工智能技术的飞速发展&#xff0c;边缘计算逐渐成为数据处理和分析的重要趋势。RK3588作为一款高性能的处理器&#xff0c;具备强大的计算能力和丰富的接口&#xff0c;为构建AI边缘计算网关提供了有力的支持。本文将介绍基于RK3588的AI边缘计算网关设计&#xf…

【Redis】 关于 Redis 哈希类型

文章目录 &#x1f343;前言&#x1f38b;命令介绍&#x1f6a9;hset&#x1f6a9;hget&#x1f6a9;hexists&#x1f6a9;hdel&#x1f6a9;hkeys&#x1f6a9;hvals&#x1f6a9;hgetall&#x1f6a9;hmget&#x1f6a9;hlen&#x1f6a9;hsetnx&#x1f6a9;hincrby&#x1…

弹性盒子布局,flex布局

弹性盒子布局&#xff08;Flexbox&#xff09;是CSS3引入的一种新的布局模式&#xff0c;它提供了一种更加有效的方式来设计、布局和对齐容器中的项目&#xff0c;即使容器的大小动态改变或者项目的数量未知。 弹性盒子布局的主要特点是能够轻松地在不同的屏幕大小和设备上实现…

使用VCPKG编译并使用Qt5

一、背景 Qt就不介绍了。VCPKG可以看这里VCPKG资料记录_vcpkg boost 多久-CSDN博客 为什么搞Qt5而不是Qt6&#xff1f;因为Qt5比较稳定吧。而且我公司也是用的Qt5。 为什么要自己编译而不是去下载Qt5&#xff1f; 第一&#xff0c;因为Qt5在Qt在线安装版本只提供到Qt5.15.2&…

【CTF Web】CTFShow web3 Writeup(SQL注入+PHP+UNION注入)

web3 1 管理员被狠狠的教育了&#xff0c;所以决定好好修复一番。这次没问题了。 解法 注意到&#xff1a; <!-- flag in id 1000 -->但是拦截很多种字符。 if(preg_match("/or|\-|\\|\*|\<|\>|\!|x|hex|\/i",$id)){die("id error"); }使用…

Linux驱动设备导论(1)

最近本人在学习Linux驱动&#xff0c;本系列教程是本人在一边学习&#xff0c;一边总结的系列教程&#xff0c;希望能够给很多刚学驱动小伙伴一些总结。 1.Linux设备分类 驱动针对的对象是存储器和外设&#xff0c;不是针对CPU&#xff0c;可以分为以下三大类&#xff1a; 1.…

『Stable Diffusion 』AI绘画,不会写提示词怎么办?

提示词 有没有想过&#xff0c;为什么你用 SD 生成的猫是长这样的。 而其他人可以生成这样的猫。 虽然生成的都是猫&#xff0c;但猫与猫之间还是有差距的。 如果你的提示词只是“cat”&#xff0c;那大概率就会出现本文第一张图的那个效果。而如果你加上一些形容词&#xff…

C#应用的用户配置窗体方案 - 开源研究系列文章

这次继续整理以前的代码。本着软件模块化的原理&#xff0c;这次笔者对软件中的用户配置窗体进行剥离出来&#xff0c;单独的放在一个Dll类库里进行操作&#xff0c;这样在其它应用程序里也能够快速的复用该类库&#xff0c;达到了快速开发软件的效果。 笔者其它模块化应用的例…

SQL面试题练习 —— 波峰波谷

来源&#xff1a;字节今日头条 目录 1 题目2 建表语句3 题解 1 题目 有如下数据&#xff0c;记录每天每只股票的收盘价格&#xff0c;请查出每只股票的波峰和波谷的日期和价格&#xff1b; 波峰定义&#xff1a;股票价格高于前一天和后一天价格时为波峰 波谷定义&#xff1a;股…

在linux下的ROS中下载超级终端Terminator ROS开发得力助手

在一般我们运行机器人包时要打开三个终端来运行&#xff0c;关闭时还要一个一个关闭&#xff08;ctrlc&#xff09;过于麻烦 现在下载用了terminator后&#xff0c;就支持一键关闭多个终端了&#xff0c;很方便&#xff0c;具体操作如下&#xff1a; sudo apt install termin…

JDBCTemplate介绍

Spring JDBC Spring框架对Spring的简单封装。提供一个JDBCTemplate对象简化JDBC开发 *步骤&#xff1a; 1、导入jar包 2、创建JDBCTemplate对象。依赖于数据源DataSource *JdbcTemplate templatenew JdbcTemplate(ds); 3、调用JdbcTemplate的方法来完成CRUD的操作 *update()&…

中国企业出海,哪些业务需要负载均衡?

国内企业出海的进程正在加速。中国的出海企业剑指跨境电商、社交、游戏、短剧等市场&#xff0c;其中尤其以跨境电商的数据最为突出。据官方数据&#xff0c;2023年我国跨境电商进出口总额达到2.38万亿元&#xff0c;比2016年增长近50倍&#xff0c;占货物贸易总规模的5.7%。 …

2024-5-9-从0到1手写配置中心Config之@ConfigurationProperties热更新

在PropertySourcesProcessor中&#xff0c;需要通过http从config-server获取配置。 使用ConfigMeta包装服务信息 在MidnightConfigService接口中添加默认实现类 继承MidnightRepositoryChangeListener接口&#xff1b;获取默认的MidnightRepository&#xff1b;创建MidnightCo…

xcode配置快速打开终端命令行工具教程

以往我们使用idea编辑器或者vscode编辑器的时候&#xff0c;我们可以快速的在编辑器下面打开终端进行相关的操作&#xff0c;但是在xcode里面却没有这么方便的功能按钮&#xff0c;真的不是很习惯&#xff0c;所以这次就来给xcode配置这么一个方便的功能。 idea的Terminal 这…

2024年蓝桥杯Web开发【大赛大纲】15届

一、 组别 Web应用开发分为&#xff1a;大学组和职业院校组。 每位选手只能申请参加其中一个组别的竞赛。各个组别单独评奖。 研究生和本科生只能报大学组。 其它高职高专院校可自行选择报任意组别。 二. 竞赛赛程 省赛时长&#xff1a;4小时。 决赛时长&#xff1a;4小…

SpringCloud微服务04-Elasticsearch-DSL查询-聚合

一、Elasticsearch 搜索引擎&#xff0c;响应速度非常快&#xff0c;特别是对大数据量的情况 1.初始elasticsearch 如果只需要商品搜索&#xff0c;百度这种搜索网站&#xff0c;只需要第二个就够了 docker部署&#xff1a;day08-Elasticsearch - 飞书云文档 (feishu.cn) e…

【Andoird开发】android获取蓝牙权限,搜索蓝牙设备MAC

<!-- Android 12以下才需要定位权限&#xff0c; Android 9以下官方建议申请ACCESS_COARSE_LOCATION --><uses-permission android:name"android.permission.ACCESS_COARSE_LOCATION" /><uses-permission android:name"android.permission.ACCES…

创建FreeRTOS工程

创建STM32CubeMX工程 配置时钟 配置FreeRTOS 生成Keil MDK的工程 打开工程 结尾 这就是我们用STM32CubeMX创建的最基本的一个FreeRTOS的工程。可以看到&#xff0c;这个与我们使用stm32开发的裸机程序有相同的地方&#xff0c;也有不同的地方&#xff0c;我们可以发现&am…