IIC协议解析
IIC协议解析
IIC 即Inter-Integrated Circuit(集成电路总线),这种总线类型是由飞利浦半导体公司在八十年代初设计出来的,主要是用来连接整体电路(ICS) ,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。这种方式简化了信号传输总线接口。
IIC的主要构成
两个双向的信号线
- 数据线SDA: Serial Data
- 时钟线SCL: Serial clock
IIC主要特点:
- 具有多机功能,该模块既可以做主设备也可以做为从设备
- IIC主设备功能:主要产生时钟,产生起始信号和停止信号
- IIC从设备功能:可编程的IIC地址检测,停止位检测
- 支持不同速率的通讯速度,标准速度(最高速度100kHZ),快速(最高400kHZ)
IIC通信过程:
- 主模式时,IIC的接口启动数据传输并且产生时钟信号。串行数据传输总是以起始条件开始并以停止条件结束。起始条件和停止条件都是在主模式下由软件产生控制的。
- 从模式时,IIC接口能识别它自己的地址(7位或者10位)和在数据总线广播的地址(好比每个人都有不同的身份ID,叫到哪个哪个就发生应答),同时软件能够控制开启或者禁止广播呼叫地址的识别。
- 数据和地址按照8位每个字节来传输,高位在前。跟在起始条件后的1或者2个字节是地址(7位模式为1个自己,10位模式为2个字节)。地址只能主模式发送。在一个字节传输的8个时钟后的第九个时钟期间,从模式接收后必须回一个ACK给发送器,这样才进行数据传输。
IIC几种信号:
- 空闲状态:在IIC空闲时候,SDA ,SCL 都是保持高电平。
- 起始信号:在时钟SCL保持高电平,然后SDA数据线是从高电平变为低电平表示起始信号;
/*SDA下降沿*/ void IIC_Start(void) { SDA = 1; SCL = 1; IIC_Delay(DELAY_TIME); SDA = 0; IIC_Delay(DELAY_TIME); SCL = 0; }
- 停止信号:在时钟SCL保持高电平,然后SDA数据线是从低电平变为高电平表示停止信号;
void IIC_Stop(void) { SDA = 0; SCL = 1; IIC_Delay(DELAY_TIME); SDA = 1; IIC_Delay(DELAY_TIME); }
- 应答信号:主机发送完一个8位数据后,会从从机接收一个应答(acknowledge)信号,SDA将会拉低,这是接收应答;主机在接收完一个8位信号后,会向从机发送一个应答信号,这是发送应答。
简单的理解就是:收到别人的信息要回复;你给别人信息别人也要回复你
//发送应答 void IIC_SendAck(bit ackbit) { SCL = 0; //SCL=0时 SDA数据才能变 SDA = ackbit; // 0表示应答,1表示非应答 IIC_Delay(DELAY_TIME); SCL = 1; IIC_Delay(DELAY_TIME); SCL = 0; SDA = 1; IIC_Delay(DELAY_TIME); } //接受应答 bit IIC_WaitAck(void) { bit ackbit; SCL = 1; IIC_Delay(DELAY_TIME); ackbit = SDA; SCL = 0; IIC_Delay(DELAY_TIME); return ackbit; }
最后列出所有的代码(十二届蓝桥杯资料包代码)
//iic.h #ifndef _IIC_H #define _IIC_H void IIC_Start(void); void IIC_Stop(void); bit IIC_WaitAck(void); void IIC_SendAck(bit ackbit); void IIC_SendByte(unsigned char byt); unsigned char IIC_RecByte(void); #endif
//iic.c /* 程序说明: IIC总线驱动程序 软件环境: Keil uVision 4.10 硬件环境: CT107单片机综合实训平台 8051,12MHz 日 期: 2011-8-9 */ #include "reg52.h" #include "intrins.h" #define DELAY_TIME 5 #define SlaveAddrW 0xA0 #define SlaveAddrR 0xA1 //总线引脚定义 sbit SDA = P2^1; /* 数据线 */ sbit SCL = P2^0; /* 时钟线 */ void IIC_Delay(unsigned char i) { do{_nop_();} while(i--); } //总线启动条件 void IIC_Start(void) { SDA = 1; SCL = 1; IIC_Delay(DELAY_TIME); SDA = 0; IIC_Delay(DELAY_TIME); SCL = 0; } //总线停止条件 void IIC_Stop(void) { SDA = 0; SCL = 1; IIC_Delay(DELAY_TIME); SDA = 1; IIC_Delay(DELAY_TIME); } //发送应答 void IIC_SendAck(bit ackbit) { SCL = 0; SDA = ackbit; // 0:应答,1:非应答 IIC_Delay(DELAY_TIME); SCL = 1; IIC_Delay(DELAY_TIME); SCL = 0; SDA = 1; IIC_Delay(DELAY_TIME); } //等待应答 bit IIC_WaitAck(void) { bit ackbit; SCL = 1; IIC_Delay(DELAY_TIME); ackbit = SDA; SCL = 0; IIC_Delay(DELAY_TIME); return ackbit; } //通过I2C总线发送数据 void IIC_SendByte(unsigned char byt) { unsigned char i; for(i=0; i<8; i++) { SCL = 0; //发送数据时,只有SCL为0时,才可以改变SDA值 IIC_Delay(DELAY_TIME); if(byt & 0x80) SDA = 1; //SDA 获取 byt的最高位,通过与1000 0000 相与获得 else SDA = 0; // 结果为1,if成立,SDA获取1 //需要注意的是,if(*)内只要大于0就成立, //而不一定非要为true或者1 IIC_Delay(DELAY_TIME); SCL = 1; byt <<= 1; // byt 左移一位,右侧补0,比如 1011 0001变为 0110 0010 IIC_Delay(DELAY_TIME); } SCL = 0; } //从I2C总线上接收数据 unsigned char IIC_RecByte(void) { unsigned char i, da; for(i=0; i<8; i++) { SCL = 1; IIC_Delay(DELAY_TIME); da <<= 1; if(SDA) da |= 1; SCL = 0; IIC_Delay(DELAY_TIME); } return da; }============================找指导老师布置任务吧==============================