IIC总线
一、与IIC有关的知识
(1)IIC属于半双工通信方式
(2)IIC的协议
1.空闲状态:IIC的SCL和SDA两条线均处于高电平状态,此时即释放总线
2.起始信号(Start):SCL为高电平期间,SDA产生一个下降沿信号
3.停止信号(End):SCL为高电平期间,SDA产生一个上升沿信号
4.应答信号ACK: 发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
5.数据有效性:I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。即:数据在SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。
6.数据传输:在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。
(3)24C02
1.写数据流程
第一步,首先是 I2C 的起始信号,接着跟上首字节,也就是我们前边讲的 I2C 的器件地址,并且在读写方向上选择“写”操作。第二步,发送数据的存储地址。24C02 一共256 个字节的存储空间,地址从0x00~0xFF,我们想把数据存储在哪个位置,此刻写的就是哪个地址。第三步,发送要存储的数据第一个字节、第二个字节„„注意在写数据的过程中,EEPROM 每个字节都会回应一个“应答位 0”,来告诉我们写 EEPROM 数据成功,如果没有回应答位,说明写入不成功。字
2.读数据流程:
第一步,首先是 I2C 的起始信号,接着跟上首字节,也就是我们前边讲的 I2C 的器件地址,并且在读写方向上选择“写”操作。这个地方可能有同学会诧异,我们明明是读数据为何方向也要选“写”呢?刚才说过了, 24C02 一共有 256 个地址,我们选择写操作,是为了把所要读的数据的存储地址先写进去,告诉 EEPROM 我们要读取哪个地址的数据。这就如同我们打电话,先拨总机号码( EEPROM 器件地址),而后还要继续拨分机号码(数据地址),而拨分机号码这个动作,主机仍然是发送方,方向依然是“写”。第二步,发送要读取的数据的地址,注意是地址而非存在 EEPROM 中的数据,通知EEPROM 我要哪个分机的信息。第三步,重新发送 I2C 起始信号和器件地址,并且在方向位选择“读”操作。这三步当中,每一个字节实际上都是在“写”,所以每一个字节EEPROM 都会回应一个“应答位0”。第四步,读取从器件发回的数据,读一个字节,如果还想继续读下一个字节,就发送一个“应答位 ACK(0)”,如果不想读了,告诉EEPROM,我不想要数据了,别再发数据了,那就发送一个“非应答位 NAK(1)”
3.24C02地址
24C02的 7 位地址中,其中高 4 位是固定的 0b1010,而低 3 位的地址取决于具体电路的设计,由芯片上的 A2、 A1、 A0 这 3 个引脚的实际电平决定,高为1,低为0.最低位是数据方向位(R/W)0表示接下来要发送数据(写),1表示接下来是请求数据(读)。
二、用到的知识
1. GPIO、串口
2. IIC、24C02
三、功能
先在24c02的一个地址中写入一个字符,然后在读取该位置的字符并通过串口显示出来。
#include "iic.h"#define iicsda PBout(7)#define iicscl PBout(6)#define iicsdain PBin(7)void SDAOUT(void)//sda×÷ΪÍÆÍìÊä³ö{ GPIO_InitTypeDef GPIO_InitTypeStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_7; GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitTypeStruct);}void SDAIN(void)//SDA×÷Ϊ¸¡¿ÕÊäÈë{ GPIO_InitTypeDef GPIO_InitTypeStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_7; GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitTypeStruct);}void Myiic_INIT()//IIC³õʼ»¯{ GPIO_InitTypeDef GPIO_InitTypeStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7; GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitTypeStruct); GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);}void Myiic_Start(void)//ÆðʼÐźÅ{ SDAOUT(); iicsda=1; iicscl=1; delay_us(4); iicsda=0; delay_us(4); iicscl=0;}void Myiic_Stop(void)//Í£Ö¹ÐźÅ{ SDAOUT(); iicscl=0; iicsda=0; delay_us(4); iicscl=1; iicsda=1; delay_us(4);}u8 Myiic_Wait_Ack(void)//µÈ´ýACK{ u8 time=0; SDAIN(); iicsda=1; delay_us(1); iicscl=1; delay_us(1); while(iicsdain) { time++; if(time>250) { Myiic_Stop(); return 1; } } iicscl=0; return 0;}void Myiic_ACK(void)//²úÉúACKÓ¦´ð{ iicscl=0; SDAOUT(); iicsda=0; delay_us(2); iicscl=1; delay_us(2); iicscl=0;}void Myiic_NACK(void)//²»²úÉúÓ¦´ðλ{ iicscl=0; SDAOUT(); iicsda=1; delay_us(2); iicscl=1; delay_us(2); iicscl=0;}void Myiic_Sendbyte(u8 w)//·¢ËÍÒ»¸ö×Ö½Ú{ u8 i; SDAOUT(); iicscl=0; for(i=0;i<8;i++) { iicsda=(w&0x80)>>7; w<<=1; delay_us(2); iicscl=1; delay_us(2); iicscl=0; delay_us(2); }}u8 Myiic_Readbyte(unsigned char ack)//¶ÁÈ¡Ò»¸ö×Ö½Ú{ unsigned char i=0,r=0; SDAIN(); for(i=0;i<8;i++) { iicscl=0; delay_us(2); iicscl=1; r<<=1; if(iicsdain) r++; delay_us(1); } if(!ack) Myiic_NACK(); else Myiic_ACK(); return r;}
新闻热点
疑难解答