写点什么

RT-Thread 记录(十八、I2C 软件包 — 温湿度传感器 SHT21 与 EEPROM 24C02)

作者:矜辰所致
  • 2022 年 8 月 27 日
    江苏
  • 本文字数:5701 字

    阅读完需:约 19 分钟

RT-Thread记录(十八、I2C软件包 — 温湿度传感器 SHT21与EEPROM 24C02)
本文学习测试一下几款典型设备的 RT-Thread  I2C软件包
复制代码


前言

组件与软件包部分之前文章我们学习了 2 个组件: SFUD 组件与 AT 组件。 RT-Thread 丰富的生态系统,除了一些标准的组件, 还支持各种各样的软件包,上一篇文章我们已经接触过 at_device 软件包。在实际应用中很多常用的设备,都有开发者已经写好了软件包,我们可以直接添加到自己的工程使用。


本文我们就以我们常用的 I2C 设备为例,说明一下软件包的使用方式。


专栏更新到这里已经可以结尾了,组件与软件包我们只做使用记录说明,目的在于介绍一下如何使用现成的组件和软件包, 所有的包中都有作者写的 README 文件,这是最权威也最值得参考的文件,大家都可以看到说明和使用方式。


说明,本文的 I2C 接口为软件 I2C。


在开发板上,我们有 2 个 I2C 设备,一个是 EEPROM 24C02 和 一个 温湿度传感器 SHT21。


EEPROM:



温湿度传感器:



在 RT-Thread 专栏应用篇中,我们已经实现过 I2C 代码的移植,成功读取到了 温湿度的数据,这里我再次测试,是通过 RT-Thread 软件包的使用实现数据读取。


本 RT-Thread 专栏记录的开发环境:

RT-Thread 记录(一、RT-Thread 版本、RT-Thread Studio 开发环境 及 配合 CubeMX 开发快速上手)

https://xie.infoq.cn/article/44be1057caace7a6a2c4c4b59

RT-Thread 记录(二、RT-Thread 内核启动流程 — 启动文件和源码分析)

https://xie.infoq.cn/article/44be1057caace7a6a2c4c4b59

RT-Thread 内核篇系列博文链接:

RT-Thread 记录(三、RT-Thread 线程操作函数及线程管理与 FreeRTOS 的比较)

https://xie.infoq.cn/article/1d2e8e030ae689d6b8ee44b05

RT-Thread 记录(四、RT-Thread 时钟节拍和软件定时器)

https://xie.infoq.cn/article/3198c9b741782036bfd6e54e9

RT-Thread 记录(五、RT-Thread 临界区保护

https://xie.infoq.cn/article/7a41020e03184950664df7391

RT-Thread 记录(六、IPC 机制之信号量、互斥量和事件集)

https://xie.infoq.cn/article/1f49bfd6c69377deb9eee838f

RT-Thread 记录(七、IPC 机制之邮箱、消息队列)

https://xie.infoq.cn/article/360b04e7bc6024917afecef1d

RT-Thread 记录(八、理解 RT-Thread 内存管理)

https://xie.infoq.cn/article/bd5d8f8a19fa11ea9feacf34d

RT-Thread 记录(九、RT-Thread 中断处理与阶段小结)

https://xie.infoq.cn/article/3da9530cfac06feece3523a0c

RT-Thread 设备篇系列博文链接:

RT-Thread 记录(十、全面认识 RT-Thread I/O 设备模型)

https://xie.infoq.cn/article/40536d29988d683c78b4ba5ff

RT-Thread 记录(十一、I/O 设备模型之 UART 设备 — 源码解析)

https://xie.infoq.cn/article/38bb4bf15cb81f1fdb060b29e

RT-Thread 记录(十二、I/O 设备模型之 UART 设备 — 使用测试)

https://xie.infoq.cn/article/1df47f3ae5174dfcb418b07b6

RT-Thread 记录(十三、I/O 设备模型之 PIN 设备)

https://xie.infoq.cn/article/af3ff1066f61cddeb134c3c88

RT-Thread 记录(十四、I/O 设备模型之 ADC 设备)

https://xie.infoq.cn/article/2eda5e23a77db3a60d2595d97

RT-Thread 记录(十五、I/O 设备模型之 SPI 设备)

https://xie.infoq.cn/article/33dcc6fdc5169c287078a2bbb

RT-Thread 记录(十六、SFUD 组件 — SPI Flash 的读写)

https://xie.infoq.cn/article/d163b38baf9f10c289cd8a361

RT-Thread 记录(十七、AT 组件 — ESP8266 使用 at_device 软件包联网)

https://xie.infoq.cn/article/c909d2b503f4325ae6ab1b923

一、RT-Thread I2C 总线注册

我们以前博文讲过,RT-Thread 组件和软件包基本都是基于 RT-Thread 的设备模型,和前面讲的 SPI 设备类似,I2C 设备软件包的使用也需要先注册 I2C 总线设备到 RT-Thread 的设备管理器。


如果没有注册总线,是无法使用软件包的,比如温湿度传感器的 sht2x 软件包测试如下:



.

1.1 I2C 设备使用步骤

有了以前的学习,注册 I2C 总线对我们来说已经是小菜一碟,直接在board.h中查看软件 I2C 使用步骤:



1、首先,在 RT-Thread Studio 工程中,打开 RT-Thread Settings,使能 软件 I2C 驱动,如下图所示:



.


2、根据说明和原理图修改宏定义:



.


只需要上面 2 步,I2C 设备的使用前提就准备好了,我们把程序烧录开发本,就可以看到系统在初始化的时候已经自动注册好了 2 个 I2C 总线:


(出问题了,并没有 i2c 总线设备!!!!!!)


.

1.2 检查问题

上面使用 I2C 设备使能,一切看上去都是没问题了:



我一开始很懵,这么简单的操作我哪里会出问题了,想了很久,然后还搞不明白为什么初始化不会注册 i2c 总线,最后还是得去看驱动代码?


但是压根没有看到注册总线的驱动函数……


(后面发现并不是 studio 的问题,应该是自己很久以前的误操作,删除了文件……)



………… 花了 …… 好多时间……



.


最后我直接从以前的工程中复制了一份文件进来:



/* * Copyright (c) 2006-2018, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date           Author       Notes * 2018-11-08     balanceTWK   first version */
#include <board.h>#include "drv_soft_i2c.h"#include "drv_config.h"
#ifdef RT_USING_I2C
//#define DRV_DEBUG#define LOG_TAG "drv.i2c"#include <drv_log.h>
#if !defined(BSP_USING_I2C1) && !defined(BSP_USING_I2C2) && !defined(BSP_USING_I2C3) && !defined(BSP_USING_I2C4)#error "Please define at least one BSP_USING_I2Cx"/* this driver can be disabled at menuconfig → RT-Thread Components → Device Drivers */#endif
static const struct stm32_soft_i2c_config soft_i2c_config[] ={#ifdef BSP_USING_I2C1 I2C1_BUS_CONFIG,#endif#ifdef BSP_USING_I2C2 I2C2_BUS_CONFIG,#endif#ifdef BSP_USING_I2C3 I2C3_BUS_CONFIG,#endif#ifdef BSP_USING_I2C4 I2C4_BUS_CONFIG,#endif};
static struct stm32_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
/** * This function initializes the i2c pin. * * @param Stm32 i2c dirver class. */static void stm32_i2c_gpio_init(struct stm32_i2c *i2c){ struct stm32_soft_i2c_config* cfg = (struct stm32_soft_i2c_config*)i2c->ops.data;
rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD); rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
rt_pin_write(cfg->scl, PIN_HIGH); rt_pin_write(cfg->sda, PIN_HIGH);}
/** * This function sets the sda pin. * * @param Stm32 config class. * @param The sda pin state. */static void stm32_set_sda(void *data, rt_int32_t state){ struct stm32_soft_i2c_config* cfg = (struct stm32_soft_i2c_config*)data; if (state) { rt_pin_write(cfg->sda, PIN_HIGH); } else { rt_pin_write(cfg->sda, PIN_LOW); }}
/** * This function sets the scl pin. * * @param Stm32 config class. * @param The scl pin state. */static void stm32_set_scl(void *data, rt_int32_t state){ struct stm32_soft_i2c_config* cfg = (struct stm32_soft_i2c_config*)data; if (state) { rt_pin_write(cfg->scl, PIN_HIGH); } else { rt_pin_write(cfg->scl, PIN_LOW); }}
/** * This function gets the sda pin state. * * @param The sda pin state. */static rt_int32_t stm32_get_sda(void *data){ struct stm32_soft_i2c_config* cfg = (struct stm32_soft_i2c_config*)data; return rt_pin_read(cfg->sda);}
/** * This function gets the scl pin state. * * @param The scl pin state. */static rt_int32_t stm32_get_scl(void *data){ struct stm32_soft_i2c_config* cfg = (struct stm32_soft_i2c_config*)data; return rt_pin_read(cfg->scl);}/** * The time delay function. * * @param microseconds. */static void stm32_udelay(rt_uint32_t us){ rt_uint32_t ticks; rt_uint32_t told, tnow, tcnt = 0; rt_uint32_t reload = SysTick->LOAD;
ticks = us * reload / (1000000 / RT_TICK_PER_SECOND); told = SysTick->VAL; while (1) { tnow = SysTick->VAL; if (tnow != told) { if (tnow < told) { tcnt += told - tnow; } else { tcnt += reload - tnow + told; } told = tnow; if (tcnt >= ticks) { break; } } }}
static const struct rt_i2c_bit_ops stm32_bit_ops_default ={ .data = RT_NULL, .set_sda = stm32_set_sda, .set_scl = stm32_set_scl, .get_sda = stm32_get_sda, .get_scl = stm32_get_scl, .udelay = stm32_udelay, .delay_us = 1, .timeout = 100};
/** * if i2c is locked, this function will unlock it * * @param stm32 config class * * @return RT_EOK indicates successful unlock. */static rt_err_t stm32_i2c_bus_unlock(const struct stm32_soft_i2c_config *cfg){ rt_int32_t i = 0;
if (PIN_LOW == rt_pin_read(cfg->sda)) { while (i++ < 9) { rt_pin_write(cfg->scl, PIN_HIGH); stm32_udelay(100); rt_pin_write(cfg->scl, PIN_LOW); stm32_udelay(100); } } if (PIN_LOW == rt_pin_read(cfg->sda)) { return -RT_ERROR; }
return RT_EOK;}
/* I2C initialization function */int rt_hw_i2c_init(void){ rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct stm32_i2c); rt_err_t result;
for (int i = 0; i < obj_num; i++) { i2c_obj[i].ops = stm32_bit_ops_default; i2c_obj[i].ops.data = (void*)&soft_i2c_config[i]; i2c_obj[i].i2c2_bus.priv = &i2c_obj[i].ops; stm32_i2c_gpio_init(&i2c_obj[i]); result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c2_bus, soft_i2c_config[i].bus_name); RT_ASSERT(result == RT_EOK); stm32_i2c_bus_unlock(&soft_i2c_config[i]); LOG_D("software simulation %s init done, pin scl: %d, pin sda %d", soft_i2c_config[i].bus_name, soft_i2c_config[i].scl, soft_i2c_config[i].sda); }
return RT_EOK;}INIT_BOARD_EXPORT(rt_hw_i2c_init);
#endif /* RT_USING_I2C */
复制代码


然后就一切正常了:



最开始我以为是设置问题,当时陷入里面想不明白,隔了几天回头想想,好像是以前博客中有人问我加载软件包没用,我自己测试了一下给了回复,但是当时还是 RT-Thread 记录专栏刚开始,不需要用到软件包,然后自己因为一些警告误删除了 这个文件 (灬ꈍ ꈍ灬)...


到头来想起来原来还是自己曾经的误操作... 尴尬…… 这种问题确实在实际中会遇到……,所以提醒一下自己。.

二、温湿度传感器软件包

前面的莫名的问题太影响心情了,缓一缓希望接下来一切顺利。

2.1 添加及基本测试

对于我们使用的温湿度传感器,原理图上画的是 HTU21D ,是和 sht21 pin to pin 的程序也一样的温湿度传感器,我们在软件包中心找到 sht2x 软件包,如下图:



软件包并不需要过多的设置:



添加软件包完成,保存后重新编译工程烧录,可以看到有 sht20 的指令:



温湿度读取测试:


2.2 程序中使用

上面我们通过命令行测试了软件包,使用起来感觉特别简单是不是,那么我们在程序中怎么调用呢?


从软件包的说明文档里面可以查看到他的操作 API(只看我们测试用到的几个):


/*根据总线名称,自动初始化对应的 SHT20 设备参数  描述name  i2c 设备名称返回  描述!= NULL  将返回 sht20 设备对象= NULL  查找失败*/sht20_device_t sht20_init(const char *i2c_bus_name)
/*读取温度参数 描述dev sht20 设备对象返回 描述!= 0.0 测量温度值=0.0 测量失败*/float sht20_read_temperature(sht20_device_t dev)
/*读取湿度参数 描述dev sht20设备对象返回 描述!= 0.0 测量湿度值=0.0 测量失败*/float sht20_read_humidity(sht20_device_t dev)
复制代码


我们用图文的方式说明一下,还是很简单的:



测试结果:


三、EEPROM 软件包

我们用的 EEPROM 24C02,也有对应的软件包,有了上面传感器的例子,我们使用起来就很顺手了。

3.1 添加及基本测试

我们在软件包中心找到 at24cxx 软件包,如下图



软件包并不需要过多的设置:



添加软件包完成,保存后重新编译工程烧录,可以看到有 at24cxx 的指令:



EEPROM 读取测试:


这个指令读取有点小疑问,还不确定是从哪里开始读,读多少,也不知道从哪里开始写,写多少。但是没有关系,我们如果在程序中使用,是直接调用软件包提供的 API。


3.2 程序中使用

从软件包的说明文档里面可以查看到他的操作 API,或者直接找软件包的文件:



这几个函数比较简单,从函数声明都能知道其使用方法,我们用图文的方式说明一下,首先是初始化:



接着是读写操作:



测试结果:


结语

本文应该是很简单的软件包使用测试,没想到和上一篇文章一样,测试起来都不是那么顺利,各种坎坷 = =!


也正是说明不管东西有多简单,在实际使用过程中,难免会遇到一些意想不到的问题,理论知识是我们的立根之本,但是实际的操作才能让我们历经洗礼!


RT-Thread 组件与软件包部分使用的方式都差不多,我们暂时就更新这些,那么到目前为止 RT-Thread 专栏部分的内容也差不多可以完结了,有理论,有问题,有测试,有应用。


如果后期还有比较典型的应用,我会继续把专栏完善,希望大家多多支持!谢谢!

发布于: 刚刚阅读数: 3
用户头像

矜辰所致

关注

不浮夸,不将就,认真对待学知识的我们! 2022.08.02 加入

不浮夸,不将就,认真对待学知识的我们,矜辰所致,金石为开! 为了活下去的嵌入式工程师,画画板子,敲敲代码,玩玩RTOS,搞搞Linux ...

评论

发布
暂无评论
RT-Thread记录(十八、I2C软件包 — 温湿度传感器 SHT21与EEPROM 24C02)_软件包_矜辰所致_InfoQ写作社区