Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
I2C_IIC
使用IIC驱动框架来读取LM75的信号
发布于 2019-01-28 20:44:35 浏览:6132
订阅该版
* 本帖最后由 whj467467222 于 2019-4-11 08:32 编辑 * 该测试是在RT_Thread下测试,硬件正常情况下的测试。自己写的一个测试使用IIC来读取LM75的测试程序,顺便总结一下自己对IIC驱动框架的理解。 该测试基于[STM32F107 μC/Eval 开发板](https://github.com/RT-Thread/rt-thread/tree/master/bsp/stm32/stm32f107-uc-eval#%E7%AE%80%E4%BB%8B),使用模拟IIC,使用引脚为PB6 PB7。 所有内容参考[I2C总线设备](https://www.rt-thread.org/document/site/programming-manual/device/i2c/i2c/)[https://www.rt-thread.org/document/site/programming-manual/device/i2c/i2c/]([hide][/hide])
查看更多
43
个回答
默认排序
按发布时间排序
whj467467222
认证专家
2019-01-28
开源,分享,交流,共同进步
1,在ENV开启IIC驱动框架 RT_THREAD Components--Device Drivers 这里要记得选择模拟IIC
whj467467222
认证专家
2019-01-28
开源,分享,交流,共同进步
2,在rtconfig.h里面就有了如下的宏定义 ``` #define RT_USING_I2C #define RT_USING_I2C_BITOPS ``` 这里就表示开启了IIC,并且使用的是模拟IIC 3,因为本BSP包目前还没有添加支持IIC,目前无法通过ENV来进行设置,所以这里的模拟IIC的 SDA SCL定义到哪个引脚还需要自己设置 我在这里设置为 ``` #define BSP_I2C1_SCL_PIN 22 #define BSP_I2C1_SDA_PIN 23 ``` 上面的22 23是在drv_gpio.c里面查表所得,这里有一点需要值得注意的是,早先的RTT是使用的STM32的引脚编码来进行编号,但是现在这个地方做了更改。 早前的版本使用引脚编码来进行编号,方便查找,但是不同引脚的MCU就需要定义不同的顺序,代码量很大,而且要使用很多判断语句,显得很臃肿。 新版采用的方法是查表法,每个端口的几号引脚可以通过drv_gpio.c来进行查找方便了很多,而且代码很精简。
whj467467222
认证专家
2019-01-28
开源,分享,交流,共同进步
4,上面配置好了,接下来就是IIC总线的初始化。 ``` 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]); } return RT_EOK; } INIT_BOARD_EXPORT(rt_hw_i2c_init); ``` 这个函数完成了IIC的初始化。 INIT_BOARD_EXPORT(rt_hw_i2c_init)完成了板级自动初始化。 obj_num = sizeof(i2c_obj) / sizeof(struct stm32_i2c);计算定义了几个IIC总线 soft_i2c_config这个结构体通过宏定义来获取定义了几个IIC总线的名字:目前支持I2C1 I2C2 I2C3 i2c_obj[i].ops = stm32_bit_ops_default;默认的参数,这里不需要自己修改 ``` 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 }; ``` stm32_i2c_gpio_init(&i2c_obj[i]);完成对模拟IIC SDA SCL引脚的初始化,这里初始化的模式是PIN_MODE_OUTPUT_OD rt_i2c_bit_add_bus(&i2c_obj[i].i2c2_bus, soft_i2c_config[i].bus_name);完成对IIC总线的注册 stm32_i2c_bus_unlock(&soft_i2c_config[i]);刚刚完成对IIC总线的注册,这个时候还不需要发送数据,这个时候把互斥锁打开。
whj467467222
认证专家
2019-01-28
开源,分享,交流,共同进步
5,IIC总线注册到系统中之后可以通过list_device来进行查看
whj467467222
认证专家
2019-01-28
开源,分享,交流,共同进步
6,总线注册成功之后就是对设备的操作 ``` static void i2c_stlm75_sample(int argc, char *argv[]) { float temperature; temperature = 0.0; if (!initialized) { stlm75_init(name); } while(1) { if (initialized) { read_temp(&temperature); rt_kprintf("read stlm10 sensor temperature: %d.%d \n", (int)temperature, (int)(temperature * 10) % 10); } else { rt_kprintf("initialize sensor failed!\n"); } rt_thread_delay(1000); } } MSH_CMD_EXPORT(i2c_stlm75_sample, i2c stlm75 sample); ``` 首先导出命令行 上面的初始化函数完成了传感器的初始化,然后1S的循环来定时读取温度传感器的数据
whj467467222
认证专家
2019-01-28
开源,分享,交流,共同进步
7,传感器初始化函数 static void stlm75_init(const char *name) { i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name); if (i2c_bus == RT_NULL) { rt_kprintf("can't find %s device!\n", name); } else { initialized = RT_TRUE; } } 使用rt_device_find来查找在前面注册的IIC总线
whj467467222
认证专家
2019-01-28
开源,分享,交流,共同进步
[i=s] 本帖最后由 whj467467222 于 2019-1-28 21:49 编辑 [/i] 8,读取温度传感器信号函数 ``` static void read_temp(float *cur_temp) { rt_uint8_t temp[2]; rt_uint16_t abc; rt_uint8_t write[1]= {0x00}; write_regs(i2c_bus,1,write); read_regs(i2c_bus,2, temp); abc = ((rt_uint16_t)temp[0]<<8 | temp[1])>>5; *cur_temp = abc*0.125; } ``` 这个地方的函数按照IC的要求进行操作就可以了。
whj467467222
认证专家
2019-01-28
开源,分享,交流,共同进步
9,写操作命令 ``` static rt_err_t write_regs(struct rt_i2c_bus_device *bus, rt_uint8_t len, rt_uint8_t *buf) { struct rt_i2c_msg msgs; msgs.addr = STLM75_ADDR; msgs.flags = RT_I2C_WR; msgs.buf = buf; msgs.len = len; if (rt_i2c_transfer(bus, &msgs, 1) == 1) { return RT_EOK; } else { return -RT_ERROR; } } ``` 按照IC要求进行操作
whj467467222
认证专家
2019-01-28
开源,分享,交流,共同进步
10,IIC总线框架读写操作的函数rt_i2c_transfer ``` rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num) { rt_mutex_take(&bus->lock, RT_WAITING_FOREVER); ret = bus->ops->master_xfer(bus, msgs, num); rt_mutex_release(&bus->lock); return ret; } ``` struct rt_i2c_bus_device *bus, 总线 struct rt_i2c_msg msgs[] 消息结构体 rt_uint32_t num 数据数量 然后获取互斥锁,获取到了之后执行 ``` ret = bus->ops->master_xfer(bus, msgs, num); ``` 实际执行的函数是 ``` static rt_size_t i2c_bit_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num) { struct rt_i2c_msg *msg; struct rt_i2c_bit_ops *ops = bus->priv; rt_int32_t i, ret; rt_uint16_t ignore_nack; bit_dbg("send start condition\n"); i2c_start(ops); for (i = 0; i < num; i++) { msg = &msgs[i]; ignore_nack = msg->flags & RT_I2C_IGNORE_NACK; if (!(msg->flags & RT_I2C_NO_START)) { if (i) { i2c_restart(ops); } ret = i2c_bit_send_address(bus, msg); if ((ret != RT_EOK) && !ignore_nack) { bit_dbg("receive NACK from device addr 0x%02x msg %d\n", msgs[i].addr, i); goto out; } } if (msg->flags & RT_I2C_RD) { ret = i2c_recv_bytes(bus, msg); if (ret >= 1) bit_dbg("read %d byte%s\n", ret, ret == 1 ? "" : "s"); if (ret < msg->len) { if (ret >= 0) ret = -RT_EIO; goto out; } } else { ret = i2c_send_bytes(bus, msg); if (ret >= 1) bit_dbg("write %d byte%s\n", ret, ret == 1 ? "" : "s"); if (ret < msg->len) { if (ret >= 0) ret = -RT_ERROR; goto out; } } } ret = i; out: bit_dbg("send stop condition\n"); i2c_stop(ops); return ret; } ``` 该函数进入之后就发送了i2c_start(ops);IIC启动信号, 然后进入了for循环,我这个就发送一个数据进行说明 ignore_nack = msg->flags & RT_I2C_IGNORE_NACK; 这里需要回复ACK所以这里的ignore_nack=0 所以i2c_restart(ops);不会被执行 接下来执行ret = i2c_bit_send_address(bus, msg); ``` static rt_err_t i2c_bit_send_address(struct rt_i2c_bus_device *bus, struct rt_i2c_msg *msg) { rt_uint16_t flags = msg->flags; rt_uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK; struct rt_i2c_bit_ops *ops = bus->priv; rt_uint8_t addr1, addr2; rt_int32_t retries; rt_err_t ret; retries = ignore_nack ? 0 : bus->retries; if (flags & RT_I2C_ADDR_10BIT) { } else { /* 7-bit addr */ addr1 = msg->addr << 1; if (flags & RT_I2C_RD) addr1 |= 1; ret = i2c_send_address(bus, addr1, retries); if ((ret != 1) && !ignore_nack) return -RT_EIO; } return RT_EOK; } ``` 这里删掉了10bit模式,因为我用的7bi't'模式,10bit还没看 rt_uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;因为第一次是写数据,所以这里的结果是0 addr1 = msg->addr << 1;这个地方要重点注意一下,地址左移了一位 然后执行ret = i2c_send_address(bus, addr1, retries); ``` for (i = 0; i <= retries; i++) { ret = i2c_writeb(bus, addr); if (ret == 1 || i == retries) break; bit_dbg("send stop condition\n"); i2c_stop(ops); i2c_delay2(ops); bit_dbg("send start condition\n"); i2c_start(ops); } ``` 前面做了这么多的准备工作,终于要执行写数据的函数了 ``` static rt_int32_t i2c_writeb(struct rt_i2c_bus_device *bus, rt_uint8_t data) { rt_int32_t i; rt_uint8_t bit; struct rt_i2c_bit_ops *ops = bus->priv; for (i = 7; i >= 0; i--) { SCL_L(ops); bit = (data >> i) & 1; SET_SDA(ops, bit); i2c_delay(ops); if (SCL_H(ops) < 0) { bit_dbg("i2c_writeb: 0x%02x, " "wait scl pin high timeout at bit %d\n", data, i); return -RT_ETIMEOUT; } } SCL_L(ops); i2c_delay(ops); return i2c_waitack(ops); } ```
whj467467222
认证专家
2019-01-28
开源,分享,交流,共同进步
这个是我今天在空调房间板子在电脑旁边测得温度,吐槽一下这个片子精度是有0.5℃。
撰写答案
登录
注册新账号
关注者
0
被浏览
6.1k
关于作者
whj467467222
开源,分享,交流,共同进步
提问
29
回答
1222
被采纳
149
关注TA
发私信
相关问题
1
NXP的I2C应该比ST的好用吧
2
Use of I2C device driver
3
关于I2C 驱动问题请教
4
我如何知道这个iic的io配置和我电路设计的是一致的?
5
I2C模拟读操作失败,不知道问什么进不去读函数
6
RTT的I2C有官方文档资料没有
7
求 STM32F103 IIC 自定义IO初始化 代码
8
报一个LPC4008代码中I2C的bug
9
RTOS IIC总线使用
10
关于在RTT中使用STM32 I2C的疑问
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
RT-Thread CI编译产物artifacts自动上传功能介绍
2
STM32G030移植RT-Thread
3
CubeMX & RT-Thread Studio 联合开发说明
4
RT-Thread项目助手v0.3 | Ubuntu与MacOS平台的RT-Thread Env
5
【FRA156测评DM-MCX】- 环境配置篇
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
rt-smart
FAL
I2C_IIC
ESP8266
UART
cubemx
WIZnet_W5500
ota在线升级
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
GD32
定时器
ADC
flashDB
编译报错
socket
中断
rt_mq_消息队列_msg_queue
keil_MDK
Debug
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
lchnu
3
个答案
2
次被采纳
张世争
1
个答案
2
次被采纳
a1012112796
10
个答案
1
次被采纳
三世执戟
8
个答案
1
次被采纳
聚散无由
5
个答案
1
次被采纳
本月文章贡献
jinchanchan
12
篇文章
14
次点赞
ssdd45555
3
篇文章
2
次点赞
聚散无由
1
篇文章
4
次点赞
RTT_逍遥
1
篇文章
2
次点赞
hywing
1
篇文章
2
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部