当前位置: 首页 > news >正文

基于RT-Thread的STM32F4开发第五讲——软件模拟I2C

文章目录

  • 前言
  • 一、RT-Thread工程创建
  • 二、AT24C02
  • 三、函数编写
    • 1.I2C_soft.c
    • 2.I2C_soft.h
    • 3.main.h
  • 四、效果展示
  • 五、资源分享
  • 总结


前言


本章是基于RT-Thread studio实现软件模拟I2C,开发板是正点原子的STM32F4探索者,使用的RT-Thread驱动是5.1.0,使用的I2C通讯芯片是存储芯片AT24C02,本章和前面文章不同在于I2C是软件模拟,与设备无关,所以驱动文件不会有问题,但是对于代码开发官方文档有些重要内容没有提到,本文将进行补充。

一、RT-Thread工程创建

这里只需要按前文得到一个不报错的基础工程,因为是软件模拟I2C,所以不需要去cubemx进行硬件配置。
然后去board.h找到I2C的定义区间,使能一个I2C型号,将SCL和SDA按你的使用的开发板引脚定义。我这里使能了I2C1,SCL接入的引脚是PB8,SDA接入的引脚是PB9,如下。
在这里插入图片描述
然后去设置中打开软件模拟I2C开关,Use GPIO to soft simulate I2C感觉重复了,开不开对工程没有影响,对于debug message开启的话可以看到I2C通讯的工作流程。
在这里插入图片描述
到此,I2C工程配置完成

二、AT24C02

AT24C02是接下来用到的I2C通讯芯片,我简单说明一下。
AT24C02 是一款由 低功耗串行电可擦除只读存储器(EEPROM),通过 I²C 总线进行通信。支持标准模式(100kHz)和快速模式(400kHz)。
2K 位(256 字节)存储空间,分为 32 页,每页 8 字节。地址范围:0x00~0xFF(地址低3位为页内地址,高5位为页面地址)。一个页面
只能写入8字节,超过的数据将写入下一个页面。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、函数编写

1.I2C_soft.c

先看代码,再看讲解

#include "I2C_soft.h"
#define DBG_TAG "I2C_soft"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>#define     I2C1_NAME   "i2c1"
#define     SLAVE_ADDR  0xa0>>1//data[0]为数据地址,后面开始是写入数据
int write_i2c1reg(rt_uint8_t *data,rt_uint8_t data_byte)
{rt_uint8_t i2c1_flag = 0;struct rt_i2c_bus_device *i2c1_bus;i2c1_bus = (struct rt_i2c_bus_device *)rt_device_find(I2C1_NAME);if(i2c1_bus == RT_NULL){LOG_D("failed to i2c1 bus find");return -1;}i2c1_flag = (rt_uint8_t)rt_i2c_master_send(i2c1_bus, SLAVE_ADDR, RT_NULL, data, data_byte);if(i2c1_flag != data_byte){LOG_D("failed to i2c1 send");return -1;}return 0;
}
//data_add为读数据地址
int read_i2c1reg(rt_uint8_t data_add,rt_uint8_t *data,rt_uint8_t data_byte)
{rt_uint8_t i2c1_flag = 0;struct rt_i2c_bus_device *i2c1_bus;i2c1_bus = (struct rt_i2c_bus_device *)rt_device_find(I2C1_NAME);if(i2c1_bus == RT_NULL){LOG_D("failed to i2c1 bus find");return -1;}rt_i2c_master_send(i2c1_bus, SLAVE_ADDR, RT_NULL, &data_add, 1);i2c1_flag = (rt_uint8_t)rt_i2c_master_recv(i2c1_bus, SLAVE_ADDR, RT_NULL, data, data_byte);if(i2c1_flag != data_byte){LOG_D("failed to i2c1 recv");return -1;}return 0;
}

按照图1,器件地址应该是0xa0(W)或0xa1®,最后一位为读写位,但是官方手册明确说明了不包含读写位。如下
在这里插入图片描述
所以,后面的函数默认传入的地址是不带最后一位的7位地址,然后根据flags标志形成8位地址作为器件地址,具体操作是将输入的地址左移1位,然后或上读写位成为最终地址,那么为了保证最终地址不出错,所以我们传入的地址就要先右移一位。
我这里使用rt_i2c_master_sendrt_i2c_master_recv写入和读出数据,代码上更简介,这两个函数就是把rt_i2c_transfer和传输的消息数组指针封装了一下。
在这里插入图片描述
另外对于rt_i2c_transfer函数第三个参数我觉得官网解释有误,num只能是1,否则就会出错。要符合官方文档的定义,你每次用rt_i2c_transfer只能写入一个字节,那就效率太低了。所以最好不要用这个函数,用上面两个函数,如果实在要用,那就记住num只能是1,和你数组元素个数无关。
在这里插入图片描述
当我们使用rt_i2c_master_send传输数据时,如果标志位flag不写入RT_I2C_NO_START /* 无开始条件 */,那么自动一开始发送一个起始位和一个器件地址字节和应答,后面就是一个数据字节一个应答,达到发送的数据个数后一个停止位,刚好符合图2中AT24C02的写入格式,所以我的写入函数没有问题。就是注意数组第一位是数据字节地址,后面才是写入的数据内容。

提示
如果分开操作,把数据地址独立出来应该如下操作。

//data_add为数据地址,data为写入数据数组
rt_i2c_master_send(i2c1_bus, SLAVE_ADDR, RT_I2C_NO_STOP, &data_add, 1);
rt_i2c_master_send(i2c1_bus, SLAVE_ADDR, RT_I2C_NO_START, data, data_byte);

可见RT_I2C_NO_STOP会去除停止位,RT_I2C_NO_START会去除起始位和器件地址字节

对于接收函数,按照图3的数据格式,先采用rt_i2c_master_send(i2c1_bus, SLAVE_ADDR, RT_NULL, &data_add, 1);发送一个读数据地址,然后使用rt_i2c_master_recv(i2c1_bus, SLAVE_ADDR, RT_NULL, data, data_byte);将读到的数据存入数组data中,data_byte是读取数据字节数,rt_i2c_master_recv的flag同理。

弄清了以上这些,遇见了其他的I2C通讯芯片,只要按照它的读写格式,就能利用rt_i2c_master_sendrt_i2c_master_recv配置出需要的格式。

2.I2C_soft.h

#ifndef APP_I2C_SOFT_H_
#define APP_I2C_SOFT_H_#include <board.h>
//data[0]为数据地址,后面开始是写入数据
int write_i2c1reg(rt_uint8_t *data,rt_uint8_t data_byte);
int read_i2c1reg(rt_uint8_t data_add,rt_uint8_t *data,rt_uint8_t data_byte);#endif /* APP_I2C_SOFT_H_ */

3.main.h

#include <rtthread.h>#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include "I2C_soft.h"int main(void)
{rt_uint8_t i2c1_wd[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10};rt_uint8_t i2c1_rd[8] = {0};write_i2c1reg(i2c1_wd, 10);rt_thread_mdelay(100);read_i2c1reg(0x00,i2c1_rd, 9);rt_thread_mdelay(100);for(int i = 0;i<9;i++){rt_kprintf("i2c1 read data id 0x%x\n",i2c1_rd[i]);}read_i2c1reg(0x08,i2c1_rd, 9);rt_thread_mdelay(100);for(int i = 0;i<9;i++){rt_kprintf("i2c1 read data id 0x%x\n",i2c1_rd[i]);}while (1){rt_thread_mdelay(1000);}return RT_EOK;
}

四、效果展示

在这里插入图片描述
为什么是这样效果我就不解释了,如果你看懂了这篇文章你就知道为什么是这样了(AT24C02默认无数据写入空间值为0xff)

五、资源分享

通过网盘分享的文件:I2C_soft.zip
链接: https://pan.baidu.com/s/1k1P0mUaXDR7jJ6dwgJJ7QQ?pwd=iims 提取码: iims


总结

对于软件模拟的I2C好处是兼容性好,移植容易,对硬件设计要求不高,缺点就是传输速率很低,效率不高,占用系统资源过大。我看了一下,好像RT-Thread并没有设计硬件I2C驱动。另外RT-Thread可以安装AT24C02的软件包,可以尝试使用一下。

相关文章:

  • spring boot 注解 @bean
  • 解决 uv run 时 ModuleNotFoundError: No module named ‘anthropic‘ 的完整指南
  • HTTPS、SSL证书是啥?网站“安全小锁”的入门科普
  • megatron——EP并行
  • 【idea 报错:java: 非法字符: ‘\ufeff‘】
  • Node.js 实战八:服务部署方案对比与实践
  • [IMX] 05.串口 - UART
  • 数据可视化热图工具:Python实现CSV/XLS导入与EXE打包
  • Python在自动驾驶数据清洗中的应用
  • 路由器实战操作
  • Vue百日学习计划Day36-42天详细计划-Gemini版
  • mysql的安装方式
  • Lambda大数据架构
  • Linux基础开发工具三(git,gdb/cgdb)
  • 为什么wifi有信号却连接不上?
  • password,密码加密解释
  • UE RPG游戏开发练手 第二十九课 重攻技能2
  • Flink 快速入门
  • 从基础到高级:网站反爬技术全景解析与第三方工具对比
  • 2025年- H33-Lc141 --148. 排序链表(快慢指针,快指针先出发一步)--Java版
  • 甘肃白银煤矿透水事故最新进展:3名被困矿工已无生命体征
  • 自然资源部:适应存量时代城市更新发展,严控增量盘活存量
  • 一日双赛“莎头组合”赢得强势,但国乒已开始品尝输球滋味
  • 特朗普与普京通话前夕,英美法德意领导人通话讨论俄乌问题
  • 上海发文加强直播经济技能人才培养:三年新培养持证直播技能人才5万名
  • 全总联合六部门印发工作指引,共保劳动者合法权益