nRF52832之硬件I2C
2016-03-30 23:45
337 查看
这几天一直在折腾nRF52832的硬件I2C,到了今天终于出现了成果,在此也印证了那句话:“耕耘就有收获”
52832的硬件I2C虽然官方提供了demo,但是自己对I2C通信理解的不够深入,再一个52832的代码也封装的太深了,但是对接口函数没有一个明确的解释(也可以说是我英文太渣,别人写了但是我没看懂。。。),这样对于首次接触nRF产品的人就造成了一定的难度
根据我的开发过程,还是先说明一下I2C的一些相关知识,因为我是先调硬件I2C搞了半天不对头,然后再开发模拟I2C,模拟的成功了再来调试的硬件TWI(也就是52832的硬件I2C,全称估计是two wire interface)
I2C通信需要两条线:SDA,SCL。I2C通信设备有两种角色:master和slave,一般用户开发程序都是开发master端,然后去读写作为slave的外设,比如:eeprom,flash,sensor,display device。
在通信过程中,有两组特殊控制信号:
start :scl为高电平时,sda由高电平变为低电平。
stop: scl为高电平时,sda由低电平变为高电平。
(注意在通信过程中,SCL始终由master控制,这句话在做模拟I2C的时候就显得意义非凡了)
master做写数据操作时,先是SCL和SDA都处于空闲状态(两者都是高电平),然后SDA由高变低(start信号);变低后SCL拉低,这个时候SDA就可以变成想要的电平,高电平代表bit为1,低电平代表bit为0;电平稳定后拉高时钟(拉高的目的是为了让slave读取数据,SCL为高时,SDA要保持不变,slave读取SDA的电平);数据传输完了后要结束:先拉高SCL,然后拉高SDA,然后拉低SDA,一个完整的stop信号完成了。
读数据操作时,start和stop这些时序一样,但是主机要去解析slave传来的数据(电平信号), 拉低SCL,然后释放SDA(即拉高SDA),一段延时之后拉高SCL再去读取SDA电平信号(既然是读取电平,这里必要设置为输入引脚啦),如果是高电平则记下是一个H_bit,否则是L_bit,读取到8位数据后如果还要继续读取则回复ACK,否则回复NCK。
ACK信号是SCL拉低后给SDA一个低电平,然后拉高SCL;
ANK信号是SCL拉低和给SDA一个高电平,然后拉高SCL;
下面以讲解下master 和 slave传输时总体操作:
master向slave写数据,一般slave端写数据都要一个确定的寄存器地址,即你要往这个外设的哪个位置传数据
以eeprom为例,先发送器件地址0xAE(8位数据,高7位是地址,LSB是数据传输方向:0;0代表写,1代表读,可以当做out,in来理解这样容易记住);
然后发送寄存器地址,然后发送数据;
时序上面可以是
start–slave_address_write–register_address–N*Send_data–stop
Send_data每发一个字节,slave会回应一个“CK信号”,如果是ACK则发送数据成功了,否则失败
因为是连续的写数据,因此中间可以没有stop,start
读数据操作,要先写进一个寄存器地址,再传递一个读命令
start–slave_address_write–register_address–start–slave_address_Read–N*Receive_data–stop
发送slave_address_Read前要先re_start,跟start信号一样
Receive_data 是接收数据,这时要去识别SDA电平并且解析数据,作出ACK回应,最后一个字节接收完毕回复NCK信号;然后stop。
下面说明nRF52832的硬件I2C代码问题
nRF留出的API接口是
这个函数调用了app_twi_schedule函数,以此来导入到队列
想要调用app_twi_perform函数那么得准备好参数
1、p_app_twi,这是在TWI传输队列里申请一个位置
英文原话是creating an instance of the TWI transaction manager.
2、p_transfers,这是包含了要传输的数组块的一个数组
3、number_of_transfers,这个是你传输数据块的个数
4、user_function,一个用户的回调函数的函数指针,数据块传输完了API内部会调用这个user_function
解释:上面说的数据块的意思就是一个完整的I2C操作需要用到的信息:包含了slave地址,数据传递方向(读或者写),传输的数据data_buffer,数据长度length,有无结束标志(意思就是这团数据传输完了后是否结束通信了)
在官方SDK里面目录
examples\peripheral\twi_master_using_app_twi里打开工程
首先初始化TWI
![](https://img-blog.csdn.net/20160330231910182)
数据传输
![](https://img-blog.csdn.net/20160330232136371)
传输的内容
![](https://img-blog.csdn.net/20160330232508700)
注意AT24C02_init_transfers是一个全局变量数组
也就是它的地址是在堆里面的,不会自动释放;这么做的原因是这个数组的地址可能会被多次调用,而放在某个函数里面会造成地址不同造成错误
demo里面有解释
注意这里的AT_WRITE_NUMBER数组可以理解为一个数据缓冲区,可以通过改变这个数组的内容然后调用app_twi_perform来发数据出去(把const去掉)
读数据类似,demo用的自定义传输函数
仿写一个
![](https://img-blog.csdn.net/20160330233850705)
![](https://img-blog.csdn.net/20160330234141972)
没想到这篇博客会有这么多人看,写的挺乱的,但是也不想再做修改了~~~写博客真的耗费时间啊~
建议大家去看twi_sensor这个工程
路径:NORDIC官方SDK\nRF52_SDK_11.0.0\examples\peripheral\twi_sensor
52832的硬件I2C虽然官方提供了demo,但是自己对I2C通信理解的不够深入,再一个52832的代码也封装的太深了,但是对接口函数没有一个明确的解释(也可以说是我英文太渣,别人写了但是我没看懂。。。),这样对于首次接触nRF产品的人就造成了一定的难度
根据我的开发过程,还是先说明一下I2C的一些相关知识,因为我是先调硬件I2C搞了半天不对头,然后再开发模拟I2C,模拟的成功了再来调试的硬件TWI(也就是52832的硬件I2C,全称估计是two wire interface)
I2C通信需要两条线:SDA,SCL。I2C通信设备有两种角色:master和slave,一般用户开发程序都是开发master端,然后去读写作为slave的外设,比如:eeprom,flash,sensor,display device。
在通信过程中,有两组特殊控制信号:
start :scl为高电平时,sda由高电平变为低电平。
stop: scl为高电平时,sda由低电平变为高电平。
(注意在通信过程中,SCL始终由master控制,这句话在做模拟I2C的时候就显得意义非凡了)
master做写数据操作时,先是SCL和SDA都处于空闲状态(两者都是高电平),然后SDA由高变低(start信号);变低后SCL拉低,这个时候SDA就可以变成想要的电平,高电平代表bit为1,低电平代表bit为0;电平稳定后拉高时钟(拉高的目的是为了让slave读取数据,SCL为高时,SDA要保持不变,slave读取SDA的电平);数据传输完了后要结束:先拉高SCL,然后拉高SDA,然后拉低SDA,一个完整的stop信号完成了。
读数据操作时,start和stop这些时序一样,但是主机要去解析slave传来的数据(电平信号), 拉低SCL,然后释放SDA(即拉高SDA),一段延时之后拉高SCL再去读取SDA电平信号(既然是读取电平,这里必要设置为输入引脚啦),如果是高电平则记下是一个H_bit,否则是L_bit,读取到8位数据后如果还要继续读取则回复ACK,否则回复NCK。
ACK信号是SCL拉低后给SDA一个低电平,然后拉高SCL;
ANK信号是SCL拉低和给SDA一个高电平,然后拉高SCL;
下面以讲解下master 和 slave传输时总体操作:
master向slave写数据,一般slave端写数据都要一个确定的寄存器地址,即你要往这个外设的哪个位置传数据
以eeprom为例,先发送器件地址0xAE(8位数据,高7位是地址,LSB是数据传输方向:0;0代表写,1代表读,可以当做out,in来理解这样容易记住);
然后发送寄存器地址,然后发送数据;
时序上面可以是
start–slave_address_write–register_address–N*Send_data–stop
Send_data每发一个字节,slave会回应一个“CK信号”,如果是ACK则发送数据成功了,否则失败
因为是连续的写数据,因此中间可以没有stop,start
读数据操作,要先写进一个寄存器地址,再传递一个读命令
start–slave_address_write–register_address–start–slave_address_Read–N*Receive_data–stop
发送slave_address_Read前要先re_start,跟start信号一样
Receive_data 是接收数据,这时要去识别SDA电平并且解析数据,作出ACK回应,最后一个字节接收完毕回复NCK信号;然后stop。
下面说明nRF52832的硬件I2C代码问题
nRF留出的API接口是
ret_code_t app_twi_perform(app_twi_t * \ p_app_twi,app_twi_transfer_t const * p_transfers,\ uint8_t number_of_transfers,\ void (* user_function)(void)\ )
这个函数调用了app_twi_schedule函数,以此来导入到队列
ret_code_t app_twi_schedule(app_twi_t * p_app_twi, app_twi_transaction_t const * p_transaction)
想要调用app_twi_perform函数那么得准备好参数
1、p_app_twi,这是在TWI传输队列里申请一个位置
英文原话是creating an instance of the TWI transaction manager.
2、p_transfers,这是包含了要传输的数组块的一个数组
3、number_of_transfers,这个是你传输数据块的个数
4、user_function,一个用户的回调函数的函数指针,数据块传输完了API内部会调用这个user_function
解释:上面说的数据块的意思就是一个完整的I2C操作需要用到的信息:包含了slave地址,数据传递方向(读或者写),传输的数据data_buffer,数据长度length,有无结束标志(意思就是这团数据传输完了后是否结束通信了)
在官方SDK里面目录
examples\peripheral\twi_master_using_app_twi里打开工程
首先初始化TWI
数据传输
传输的内容
注意AT24C02_init_transfers是一个全局变量数组
也就是它的地址是在堆里面的,不会自动释放;这么做的原因是这个数组的地址可能会被多次调用,而放在某个函数里面会造成地址不同造成错误
demo里面有解释
// [these structures have to be "static" - they cannot be placed on stack // since the transaction is scheduled and these structures most likely // will be referred after this function returns] static app_twi_transfer_t const transfers[] = { AT24C02_READ(&AT24C02_first_page_addr,AT_buffer,5) };
注意这里的AT_WRITE_NUMBER数组可以理解为一个数据缓冲区,可以通过改变这个数组的内容然后调用app_twi_perform来发数据出去(把const去掉)
读数据类似,demo用的自定义传输函数
仿写一个
没想到这篇博客会有这么多人看,写的挺乱的,但是也不想再做修改了~~~写博客真的耗费时间啊~
建议大家去看twi_sensor这个工程
路径:NORDIC官方SDK\nRF52_SDK_11.0.0\examples\peripheral\twi_sensor
相关文章推荐
- JavaScript语言精粹——数组
- c语言学习路程 冒泡排序算法void bubble(int i )函数
- BestCoder Round #75
- 【1】JAVA---地址App小软件(AddressApp.class)(初步接触项目开发的分层思想)(表现层)
- Linux 上的常用文件传输方式介绍与比较
- 【1】JAVA---地址App小软件(AddressApp.class)(初步接触项目开发的分层思想)(表现层)
- 实用的 Python 之 feedparser
- 我的2016年决心书(老男孩教育在线课程班第一期)
- VBA基础
- 2016.3.30 OneZero站立会议
- c++判断一个字符串是否是数字
- Python itertools模块详解
- leetcode017 Letter Combinations of a Phone Number
- Azure上Linux虚拟机Mac地址的持久化
- 使用requestAnimationFrame和Canvas给按钮添加绕边动画
- POJ1275 Cashier Employment
- 求出data为首地址的100D字数组中的最小偶数,并把它存放在AX中,目前只能做出无符号数,有待修改
- Katana Op for visualization of OpenVDB
- 【心血之作】linux虚拟机下安装配置Hadoop(完全分布式)生态环境(hadoop2.2.0,HBase0.98,Hive0.13(连接oracle),sqoop1.4.4(连接oracle)
- 89978