Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
I2C_IIC
nuc980
NK-980IOT I2C测试:读取BMP180
发布于 2022-03-29 18:24:01 浏览:851
订阅该版
[tocm] ## 开发环境 * 软件:RT-Thread Studio * 硬件:NK-980IOT开发板 ## I2C介绍 I2C是一种双线、双向串行总线,为设备之间的数据交换提供了一种简单有效的方法。I2C标准是一种真正的多主总线,包括冲突检测和仲裁,当两个或多个主总线试图同时控制总线时,可防止数据损坏。 共有四套I2C控制器,支持断电唤醒功能。 ### 特性 I2C总线使用两根导线(SDA和SCL)在连接到总线的设备之间传输信息。I2C总线的主要功能包括: * 最多支持三个I2C端口 * 主/从模式 * 主设备和从设备之间的双向数据传输 * 多主机模式(无中心主机) * 支持标准模式(100kbps)、快速模式(400kbps)和快速模式plus(1Mbps) * 在不损坏总线上串行数据的情况下,同时传输主机之间的仲裁 * 内置14位超时计数器,在I2C总线挂起且定时器超时计数器溢出时请求I2C中断 * 可编程时钟允许多种速率控制 * 支持7位寻址和10位寻址模式 * 支持多地址识别(带掩码选项的四个从地址) * 支持断电唤醒功能 * 支持设置/保持时间可编程 ### 功能框图 ![h9Eu9Ahwg1-pPqL60k0yK8krG3uzHoA9li7p6UfQrj4.png](https://oss-club.rt-thread.org/uploads/20220329/3faf08b9b2afdd56eba7c2cea200b42b.png) ### 基本配置 在测试用使用的I2C2,下面主要介绍I2C2的配置。 时钟源配置:在I2CKEN中启用I2C2外设时钟(CLK\_APBCLK1\[2\]) 复位配置:在I2C2RST中重置I2C2控制器(SYS\_APBIPRST1\[2\]) 管脚配置: ![be0sgar0jsCGnBrKwMmBWT6uDqL36ArFGzZWSdOdBG8.png](https://oss-club.rt-thread.org/uploads/20220329/70373cecfb3f2b70ee99d2f11a339b93.png) 测试中使用的是PB5/PB7: ![e0uUvCZENhosHCddy2M2CHsUGVaJJcHa1wbJuDs8fyU.png](https://oss-club.rt-thread.org/uploads/20220329/f1f28a5c356e725c55a2cd136c053d87.png) ### 功能描述 在I2C总线上,数据在主设备和从设备之间传输。SCL和SDA线路上的数据位以字节为单位同步传输。每个数据字节的长度为8位。每个数据位有一个SCL时钟脉冲,MSB先传输,每个传输的字节后有一个确认位。在SCL的高位期间对每个位进行采样;因此,SDA线可能仅在SCL的低期发生变化,并且在SCL的高期必须保持稳定。当SCL处于高位时,SDA线上的转换被解释为命令(启动或停止)。有关I2C总线定时的更多详细信息,请参考图6.16-2。 #### I2C时序图 ![K03cuIiHCPU25pUYteu0Gw3X48Fk_KRN8bq4Gjncyo0.png](https://oss-club.rt-thread.org/uploads/20220329/2f30b207e65743c1f76074802ee960b1.png) 以上内容均来自芯片的数据手册,数据手册里内容非常全,建议大家在需要时一定要去翻阅。新唐是国产IC里少有的能把手册做那么全的,很给力。 ## 外部电路 测试使用了GY-68模块,模块原理图: ![bQAQ6ShEISC2ZyrWJ8iCeIdxvuYvZLQh67_jSw6uf54.jpg](https://oss-club.rt-thread.org/uploads/20220329/942ecc91b030e06db41977dc086cb135.jpg) 与开发板的连接 ![DmOgflbAA0mLPZIUJbuzOO64RJynzaRSqfL4SoYno7Q.jpg](https://oss-club.rt-thread.org/uploads/20220329/a6965bf0aa828833907bd471b8d5b16e.jpg.webp) ## 工程代码部分 ### 工程配置 先使能I2C2 ![ZiscGJI6dj9xO5b9eairg5Uc1LXtV4a1GsigdMWh2VA.png](https://oss-club.rt-thread.org/uploads/20220329/eae53f5e7741f57e52f5187583da80ef.png) 在软件包里有传感器驱动库可以使用 ![lqvholZFZZ5_OQDajmuIWIKYnFrXj5DCcFqhpHl4F3g.png](https://oss-club.rt-thread.org/uploads/20220329/9613ec57a9c148cd8a62049d6d252512.png) 这个库写的不错,里面有对设备抽象、添加自己的设备等代码,对提高编程能力很有启发和学习价值。 ### 初始化 ```Plain Text int rt_hw_bmp180_init(const char *name, struct rt_sensor_config *cfg) { rt_err_t ret = RT_EOK; rt_sensor_t sensor_baro = RT_NULL, sensor_temp = RT_NULL; struct rt_sensor_module *module = RT_NULL; struct bmp180_dev *bmp180 = RT_NULL; uint8_t bmbuf[22] = {0}; bmp180 = rt_calloc(1, sizeof(struct bmp180_dev)); if(bmp180 == RT_NULL) { LOG_E("malloc memory failed\r\n"); ret = -RT_ERROR; goto __exit; } bmp180->i2c_bus = rt_i2c_bus_device_find(cfg->intf.dev_name); if(bmp180->i2c_bus == RT_NULL) { LOG_E("i2c bus device %s not found!\r\n", cfg->intf.dev_name); ret = -RT_ERROR; goto __exit; } module = rt_calloc(1, sizeof(struct rt_sensor_device)); if(module == RT_NULL) { LOG_E("malloc memory failed\r\n"); ret = -RT_ERROR; goto __exit; } module->sen[0] = sensor_baro; module->sen[1] = sensor_temp; module->sen_num = 2; /* barometric pressure sensor register */ { sensor_baro = rt_calloc(1, sizeof(struct rt_sensor_device)); if (sensor_baro == RT_NULL) { goto __exit; } rt_memset(sensor_baro, 0x0, sizeof(struct rt_sensor_device)); sensor_baro->info.type = RT_SENSOR_CLASS_BARO; sensor_baro->info.vendor = RT_SENSOR_VENDOR_BOSCH; sensor_baro->info.model = "bmp180_baro"; sensor_baro->info.unit = RT_SENSOR_UNIT_PA; sensor_baro->info.intf_type = RT_SENSOR_INTF_I2C; sensor_baro->info.range_max = 110000; /* 1Pa */ sensor_baro->info.range_min = 30000; sensor_baro->info.period_min = 100; /* read ten times in 1 second */ rt_memcpy(&sensor_baro->config, cfg, sizeof(struct rt_sensor_config)); sensor_baro->ops = &bmp180_ops; sensor_baro->module = module; ret = rt_hw_sensor_register(sensor_baro, name, RT_DEVICE_FLAG_RDWR, (void*)bmp180); if (ret != RT_EOK) { LOG_E("device register err code: %d", ret); goto __exit; } } /* temperature sensor register */ { sensor_temp = rt_calloc(1, sizeof(struct rt_sensor_device)); if (sensor_temp == RT_NULL) { goto __exit; } rt_memset(sensor_temp, 0x0, sizeof(struct rt_sensor_device)); sensor_temp->info.type = RT_SENSOR_CLASS_TEMP; sensor_temp->info.vendor = RT_SENSOR_VENDOR_BOSCH; sensor_temp->info.model = "bmp180_temp"; sensor_temp->info.unit = RT_SENSOR_UNIT_DCELSIUS; sensor_temp->info.intf_type = RT_SENSOR_INTF_I2C; sensor_baro->info.range_max = 850; /* 0.1C */ sensor_baro->info.range_min = -400; sensor_temp->info.period_min = 100; /* read ten times in 1 second */ rt_memcpy(&sensor_temp->config, cfg, sizeof(struct rt_sensor_config)); sensor_temp->ops = &bmp180_ops; sensor_temp->module = module; ret = rt_hw_sensor_register(sensor_temp, name, RT_DEVICE_FLAG_RDWR, (void*)bmp180); if (ret != RT_EOK) { LOG_E("device register err code: %d", ret); goto __exit; } } /* bmp180 read calc param */ ret = bmp180_read_regs(sensor_baro, BMS_CAL_AC1, bmbuf, 22); if(ret == RT_EOK) { bmp180->calc_param.ac1 = (bmbuf[0]<<8)|bmbuf[1]; bmp180->calc_param.ac2 = (bmbuf[2]<<8)|bmbuf[3]; bmp180->calc_param.ac3 = (bmbuf[4]<<8)|bmbuf[5]; bmp180->calc_param.ac4 = (bmbuf[6]<<8)|bmbuf[7]; bmp180->calc_param.ac5 = (bmbuf[8]<<8)|bmbuf[9]; bmp180->calc_param.ac6 = (bmbuf[10]<<8)|bmbuf[11]; bmp180->calc_param.b1 = (bmbuf[12]<<8)|bmbuf[13]; bmp180->calc_param.b2 = (bmbuf[14]<<8)|bmbuf[15]; bmp180->calc_param.mb = (bmbuf[16]<<8)|bmbuf[17]; bmp180->calc_param.mc = (bmbuf[18]<<8)|bmbuf[19]; bmp180->calc_param.md = (bmbuf[20]<<8)|bmbuf[21]; } else { LOG_E("bmp180 read calc param failed\r\n"); goto __exit; } return RT_EOK; __exit: if(sensor_baro) { rt_free(sensor_baro); } if(sensor_temp) { rt_free(sensor_temp); } if(module) { rt_free(module); } if (bmp180) { rt_free(bmp180); } return ret; } ``` ### 功能实现 ```Plain Text static void read_baro_entry(void *parameter) { rt_device_t baro_dev = RT_NULL, temp_dev = RT_NULL; struct rt_sensor_data baro_data,temp_data; rt_size_t res0 = 0, res1 = 1; rt_uint8_t chip_id; baro_dev = rt_device_find("baro_bmp180"); if (baro_dev == RT_NULL) { rt_kprintf("not found baro_bmp180 device\r\n"); return; } if (rt_device_open(baro_dev, RT_DEVICE_FLAG_RDONLY) != RT_EOK) { rt_kprintf("open baro_180 failed\r\n"); return; } temp_dev = rt_device_find("temp_bmp180"); if (temp_dev == RT_NULL) { rt_kprintf("not found temp_bmp180 device\r\n"); return; } if (rt_device_open(temp_dev, RT_DEVICE_FLAG_RDONLY) != RT_EOK) { rt_kprintf("open temp_bmp180 failed\r\n"); return; } rt_device_control(baro_dev, RT_SENSOR_CTRL_SET_ODR, (void *)(1));/* 1Hz read */ rt_device_control(temp_dev, RT_SENSOR_CTRL_SET_ODR, (void *)(1));/* 1Hz read */ rt_device_control(temp_dev, RT_SENSOR_CTRL_GET_ID, (void*)&chip_id); rt_kprintf("bmp180 chip ID [0x%X]\n", chip_id); while (1) { res0 = rt_device_read(baro_dev, 0, &baro_data, 1); res0 = rt_device_read(temp_dev, 0, &temp_data, 1); if (res0==0 || res1==0) { rt_kprintf("read data failed! result is %d,%d\n", res0, res1); rt_device_close(baro_dev); rt_device_close(temp_dev); return; } else { rt_kprintf("baro[%dPa],temp[%d.%dC],timestamp[%d]\r\n", baro_data.data.baro, temp_data.data.temp/10, temp_data.data.temp%10, temp_data.timestamp); } rt_thread_delay(500); } } ``` ### 工程代码连接 https://gitee.com/sunxh_rk/nk-980-iot-i2c ## 测试结果 ![chRZDonZ-_s8qmsLSta8ZwsOJIGiIeSkPKqCr9TZeFo.jpg](https://oss-club.rt-thread.org/uploads/20220329/6d7af78d4964dba950733ec2d6208aaa.jpg.webp) //视频 [演示视频.mp4](https://oss-club.rt-thread.org/uploads/20220329/7f1f533f5cba8559e08b5fa32e70b85b.mp4) ## 总结 RT-THREAD现在支持的开发板和传感器越来越全了,点一点就能完成工程搭建和测试。非常适合快速出产品的项目开发。 新唐的NK-980IOT开发板除了开始上手时不熟悉烧写过程,其他都很容易使用,提供的手册资料非常全,堪比ti、adi等大厂,遇到问题建议大家多翻翻手册。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
sunxh_rk
这家伙很懒,什么也没写!
文章
1
回答
0
被采纳
0
关注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组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
10
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
YZRD
2
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部