锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

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

时间:2022-10-12 14:30:00 rt500传感器

本文学习测试了几种典型设备 RT-Thread  I2C软件包 

目录

  • 前言
  • 一、RT-Thread I2C 总线注册
    • 1.1 I2C 设备使用步骤
    • 1.2 检查问题
  • 二、温湿度传感器软件包
    • 2.1 添加和基本测试
    • 2.2 程序中使用
  • 三、EEPROM 软件包
    • 3.1 添加和基本测试
    • 3.2 程序中使用
  • 结语

前言

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

本文是我们常用的 I2C 以设备为例,说明软件包的使用方法。

专栏更新到此结束,组件和软件包我们只做使用记录说明,目的是介绍如何使用现成的组件和软件包, 所有的包都是作者写的 README 文件,这是最权威、最值得参考的文件,每个人都可以看到解释和使用。

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

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

EEPROM:

在这里插入图片描述

温湿度传感器:

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

??
本 RT-Thread 专栏记录的开发环境:
RT-Thread记录(一、RT-Thread 版本、RT-Thread Studio开发环境 及 配合CubeMX快速开发)
RT-Thread记录(二、RT-Thread内核启动过程 — 启动文件及源码分析)
??
RT-Thread 内核系列博文链接:
RT-Thread记录(三、RT-Thread 线程操作函数和线程管理FreeRTOS的比较)
RT-Thread记录(四、RT-Thread 时钟节拍和软件定时器)
RT-Thread记录(五、RT-Thread 临界保护)
RT-Thread记录(六、IPC信号量、相互排斥和事件集的机制)
RT-Thread记录(七、IPC机制邮箱、消息队列)
RT-Thread记录(八、理解 RT-Thread 内存管理)
RT-Thread记录(九、RT-Thread 中断处理与阶段小结)
??
在STM32L051C8 上使用 RT-Thread 应用文系列博文连接:
RT-Thread 应用篇 — 在STM32L051上使用 RT-Thread (一)无线温湿度传感器 之 新建项目)
RT-Thread 应用篇 — 在STM32L051上使用 RT-Thread (二)无线温湿度传感器 之 CubeMX配置)
RT-Thread 应用篇 — 在STM32L051上使用 RT-Thread (三)无线温湿度传感器 之 I2C通讯)
RT-Thread 应用篇 — 在STM32L051上使用 RT-Thread (4)无线温湿度传感器 之 串口通讯)
??
RT-Thread 设备系列博文链接:
RT-Thread记录(十、全面了解 RT-Thread I/O 设备模型)
RT-Thread记录(十一)I/O 设备模型之UART设备 — 源码解析)
RT-Thread记录(十二)I/O 设备模型之UART设备 — 使用测试)
RT-Thread记录(十三)I/O 设备模型之PIN设备)
RT-Thread记录(十四)I/O 设备模型之ADC设备)
RT-Thread记录(十五)I/O 设备模型之SPI设备)
??
RT-Thread 组件与软件包系列博文链接:
RT-Thread记录(十六)SFUD组件 — SPI Flash的读写)
RT-Thread记录(十七)AT组件 — ESP8266使用 at_device 软件包网)

一、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.根据说明和原理图修改宏定义:


.

以上两步只需要,I2C 设备的使用前提已经准备好了。如果我们烧录程序开发簿,我们可以看到系统在初始化时自动注册了两个 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  #include "drv_soft_i2c.h" #include "drv_config.h"  #ifdef RT_USING_I2C  //#define DRV_DEBUG/span> #define LOG_TAG "drv.i2c" #include  #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 专栏部分的内容也差不多可以完结了,有理论,有问题,有测试,有应用。

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

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章