GPIO模拟IIC过程中对IIC的理解
来源:互联网 发布:软件测试工资 编辑:程序博客网 时间:2024/06/11 02:45
谈谈个人在用GPIO模拟IIC过程中对IIC的理解
前两天在配置一款数字陀螺仪的IIC时序,分别实现了使用芯片自带IIC模块配置和使用GPIO模拟,下面谈谈个人对IIC的一些理解。
概述
- IIC是一个总线协议,和spi类似的一个串行总线协议,它的特点是只用的信号线特别少,只需要两根,分别是SCL和SDA,但是与此同时也降低了通信速度。
- IIC总线信号线少就造成它的通信协议稍微复杂,理解IIC的时序是理解IIC总线的关键。
- .IIC总线通过上拉电阻接到VDD,当总线空闲时,两根信号线均为高电平。连接总线的任意一个器件输出低电平,将使总线信号变低,即各器件的信号线是“线与”关系。
- 每个IIC上连接的器件都有唯一的地址(7bit),当某个器件发出广播(地址信号)时,该器件即为主机,其它器件为从机,读写行为都由主机发起,SCL信号总由主机产生。
- .当有多个器件企图发起广播传送数据时,需要总线仲裁模块进行仲裁。
- .在SCL为高电平期间,数据线上的数据必须保持稳定(0或者1),数据接收者会在这个期间接受数据,在SCL为低电平期间可以改变数据(改变SDA的电平)。
- 读时序:主机发起通信start(7bit从器件ID+1bit读写位0)——从机收到广播并回应(ack)——主机发送地址信号(8bit)——主机重新发起通信start(7bit从器件ID+1bit读写位0)——再次发送从器件寄存器地址address(8bit)——接收数据(SCL高电平期间从器件不会改变SDA,在此期间读SDA,将SCL拉低后从器件会将下一位数据送到SDA上)——每8bit主机需要发送一个应答信号表示继续接收,否则认为结束接收——接收结束发送无应答信号通知从器件完成数据接收——发送停止信号stop——一次通信结束写时序:主机发起通信start(7bit器件ID+1bit读写位1)——从机接收到广播并回应ack——主机写从机寄存器地址(8bit)——从机应答——写数据(8bit)——从机应答——主机发送停止信号stop——一次通信结束
- 两次通信之间应该有足够的时间间隔,不同器件的时间间隔不一样,一般为us数量级
- 当SCL=1期间,SDA从1变为0表示start信号当SCL=1期间,SDA从0变为1表示stop信号应答期间输出0表示有应答,输出1表示无应答接受应答期间接收0表示有应答,接收1表示无应答
K60上使用LPLD底层库实现GPIO模拟IIC的代码如下,该代码是用于对GY_50数字陀螺仪的读写
start信号
SCL为1期间SDA从1变为0表示开始信号
//开始信号void GY_50_Start(void){ LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID,GY_50_SDA_PORT_NUM,1); LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID,GY_50_SCL_PORT_NUM,1); GY_50_Delay(1); LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID,GY_50_SDA_PORT_NUM,0); GY_50_Delay(1); LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID,GY_50_SCL_PORT_NUM,0);}
停止信号
SCL为1期间SDA从1变为0表示结束信号
//停止信号void GY_50_Stop(void){ LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM,0); LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,1); GY_50_Delay(1); LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM,1); GY_50_Delay(1);}
发送应答信号
向数据线上传送一位数据表示有应答或者无应答
//发送应答信号(0:ACK 1:NAK)void GY_50_SendAck(uint8 ack){ ack= ack?1:0; LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM,ack); LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,1); GY_50_Delay(1); LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,0); GY_50_Delay(1);}
接收应答信号
从数据线上读取一位数据查看是否应答
//接收应答信号(0:ACK 1:NAK)uint8 GY_50_ReceiveAck(void){ uint8 data_temp=0; LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,1); GY_50_Delay(1); SetGpioPortIO(GY_50_SDA_PORT_ID,GY_50_SDA_PORT_PIN,DIR_INPUT); data_temp = LPLD_GPIO_Input_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM); SetGpioPortIO(GY_50_SDA_PORT_ID,GY_50_SDA_PORT_PIN,DIR_OUTPUT); LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,0); GY_50_Delay(1); return data_temp;}
向IIC总线发送一个字节的数据
按照协议要求,在SCL为低期间改变数据,在SCL为高期间保持数据,并保持一定时间,保证对方读取完毕
//向IIC发送一个字节的数据void GY_50_SendByte(uint8 data){ static uint8 i,data_temp; for(i=0;i<8;i++) { data_temp = data&0x80;//取最高位 data <<= 1; data_temp = data_temp?1:0; LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM,data_temp); LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,1); GY_50_Delay(1); LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,0); GY_50_Delay(1); } GY_50_ReceiveAck();}
从IIC接收一个字节数据
根据协议要求,在SCL为高期间读取数据,在SCL为低期间让对方发送数据,SCL为低要保持一定时间,保证数据线上的数据稳定
//从IIC接收一个数据uint8 GY_50_ReceiveByte(void){ static uint8 i,data_temp=0; LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM,1); SetGpioPortIO(GY_50_SDA_PORT_ID,GY_50_SDA_PORT_PIN,DIR_INPUT); for(i=0;i<8;i++) { data_temp <<= 1; LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,1); GY_50_Delay(1); data_temp |= LPLD_GPIO_Input_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM); LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,0); GY_50_Delay(1); } SetGpioPortIO(GY_50_SDA_PORT_ID,GY_50_SDA_PORT_PIN,DIR_OUTPUT); //GY_50_Delay(1); return data_temp;}
写一个字节
根据协议要求,串行传送信号
//单字节写入void GY_50_WriteByte(uint8 add, uint8 data){ GY_50_Start(); GY_50_SendByte(GY_50_ADDRESS); GY_50_SendByte(add); GY_50_SendByte(data); GY_50_Stop();}
读单个字节
根据协议要求,串行传送信号和指令
//单字节读取uint8 GY_50_ReadByte(uint8 add){ uint8 data_temp; GY_50_Start(); GY_50_SendByte(GY_50_ADDRESS); GY_50_SendByte(add); GY_50_Start(); GY_50_SendByte(GY_50_ADDRESS|0x01); data_temp = GY_50_ReceiveByte(); GY_50_SendAck(1); GY_50_Stop(); return data_temp;}
延迟函数
该函数在总线周期为50M的K60芯片上大约延迟4us(k=1)
//延时函数void GY_50_Delay(uint8 k){ uint16 i,j; for(i=0;i<k;i++) { for(j=0;j<200;j++) { asm("nop"); } }}
注:
- SetGpioPortIO(GPIO_Type *portx,uint32 pins,uint8 io)为一个改变GPIO引脚数据传送方向的函数。
希望以上对大家的学习有所帮助
注:个人才疏学浅,难免有疏漏之处,还望批评指正
0 0
- GPIO模拟IIC过程中对IIC的理解
- 用s5pc100的GPIO模拟IIC
- msp430g2533之iic(gpio模拟iic)
- 关于STM32 的 硬件IIC和 模拟IIC理解学习
- GPIO模拟IIC代码模板
- GPIO模拟IIC代码模板
- GPIO口模拟IIC通信
- GPIO软件模拟IIC时序
- 关于STM32模拟IIC的理解
- 使用GPIO模拟IIC的遇到的N个问题
- STM32Cube MX 下IIC的配置与使用--GPIO模拟
- 代码增进对IIC的理解
- 对SPI、IIC、IIS、UART、CAN、SDIO、GPIO的解释
- 对SPI、IIC、IIS、UART、CAN、SDIO、GPIO的解释
- 对SPI、IIC、IIS、UART、CAN、SDIO、GPIO的解释
- 对SPI、IIC、IIS、UART、CAN、SDIO、GPIO的解释
- 00025-----GPIO模拟IIC总线程序
- 00025-----GPIO模拟IIC总线程序
- x265-1.7版本-common/slice.h注释
- 纪念PeakTools开工和申请博客
- Activity生命周期详解
- Python的机器学习库汇总与梳理
- ZOJ1016
- GPIO模拟IIC过程中对IIC的理解
- 关于Block的内存问题__上
- 线性表的链式结构实现
- x265-1.7版本-common/threading.h注释
- 基本数据结构:建立二叉树 和 二叉树的顺序遍历
- 加工中心编程技术讲座文库
- R语言学习笔记(2):数据类型和数据结构
- scrollView
- Linux---CentOS搭建环境之安装Mysql