I2C( Inter-Integrated Circuit)总线是由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的一种总线标准。具有接口线少,控制方式简单,器件封装形式小,通信速率较高等优点。
I2C特性:
(1)只要求两条总线线路一条串行数据线SDA,一条串行时钟线SCL;
(2)每个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机关系软件设定地址,主机可以作为主机发送器或主机接收器;
(3)它是一个真正的多主机总线,如果两个或更多主机同时初始化数据传输可以通过冲突检测和仲裁防止数据被破坏;
(4)串行的 8 位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达 3.4Mbit/s;
(5)片上的滤波器可以滤去总线数据线上的毛刺波保证数据完整;
(6)连接到相同总线的IC数量只受到总线的最大电容400pF;
IIC是属串行通讯总线,同步传输、半双工。
IIC协议格式:起始信号、停止信号、应答信号、非应答信号、发送数据、接收数据。
空闲状态:SCL和SDA均保持高电平;
时钟为高电平时,数据由高电平变为低电平。
SDA_OUT=1; SCL=1; delay_us(2); SDA_OUT=0; //方便下一次数据收发 delay_us(2); SCL=0;2.2 停止信号
时钟线为高电平时,数据线由低变高。
SDA_OUT=0; SCL=0; Delay_us(2); SCL=1; Delay_us(2); SDA_OUT=1;
数据传输时序:
时钟线为高时读取数据。应答信号本身就是一位数据。
u8 i=0; SCL=0;//告诉从机,主机需要读取数据 Delay_us(2); SCL=1;//开始读取数据 while(SDA_IN) { i++; Delay_us(1); if(i>=20)return 1;//非应答 } Delay_us(2); SCL=0;//方便下一次数据收发 return 0;//获取应答信号2.4 发送应答(非应答)信号
时钟线为低电平时发送数据。应答信号本身就是一位数据。
SCL=0; SDA_OUT=ack&0x01;//ack为应答参数,0为应答,1为非应答 Delay_us(2); SCL=1;//数据发送完成 //方便下一次数据收发 Delay_us(2); SCL=0;2.5 发送一个字节数据
for(i=0;i<8;i++) { SCL=0; if(data&0x80)SDA_OUT=1; else SDA_OUT=0; Delay_us(2); SCL=1;//数据发送完成 data<<=1; Delay_us(2); } SCL=0;//方便下一次数据收发2.6 接收一个字节数据
u8 data=0; for(i=0;i<8;i++) { SCL=0;//告诉从机,主机需要读取数据 Delay_us(2); SCL=1;//主机开始读取数据 data<<=1; if(SDA_IN)data|=0x01; Delay_us(2); } SCL=0;//方便下一次数据收发 return data;3. AT24CXX介绍
CAT24WC01/02/04/08/16是一个1K/2K/4K/8K/16K位串行CMOS
E2PROM。内部含有12/256/512/1024/2048个8位字节,CATALYST公司的先进CMOS技术实质上减少了器件的功耗,CAT24WC01有一个8字节页写缓冲器,CAT24WC02/04/08/16有一个16字节页写缓冲器,该器件通过I2C总线接口进行操作有一个专门的写保护功能。
特性
(1)与400KHz I2C总线兼容
(2)1.8到6.0伏工作电压范围
(3)低功耗CMOS 技术
(4)写保护功能当WP为高电平时进入写保护状态
(5)页写缓冲器
(6)自定时擦写周期
(7)1,000,000编程/擦除周期
(8)可保存数据100年
(9)8 脚 DIP SOIC或TSSOP封装
(10)温度范围:商业级工业级和汽车级
时钟上升沿读取数据,下降发送数据。
3.4 写操作时序
字节写
在字节写模式下,主器件发送起始命令和从器件地址信息(R/W位置零)给从器件在从器件产生应答信号后,主器件发送
CAT24WC01/02/04/08/16的字节地址,主器件在收到从器件的另一个应答信号后,再发送数据到被寻址的存储单元。AT24WC01/02/04/08/16再次应答,并在主器件产生停止信号后开始内部数据的擦写,在内部擦写过程中,CAT24WC01/02/04/08/16不再应答主器件的任何请求。
页写
用页写,
CAT24WC01可一次写入8个字节数据,CAT24WC02/04/08/16可以一次写入16个字节的数据。页写操作的启动和字节写一样不同在于传送了一字节数据后并不产生停止信号。主器件被允许发送P(AT24WC01
P=7;AT24WC02/04/08/16
P=15)个额外的字节,每发送一个字节数据后,CAT24WC01/02/04/08/16产生一个应答位并将字节地址低位加1,高位保持不变。
如果在发送停止信号之前,主器件发送超过P+1个字节,地址计数器将自动翻转,先前写入的数据被覆盖。
接收到P+1字节数据和主器件发送的停止信号后,CAT24CXXX启动内部写周期将数据写到数据区。所有接收的数据在一个写周期内写入CAT24WC01/02/04/08/16。
选择性读
选择性读操作允许主器件对寄存器的任意字节进行读操作,主器件首先通过发送起始信号、从器件地址和它想读取的字节数据的地址执行一个伪写操作。在
CAT24WC01/02/04/08/16 应答之后,主器件重新发送起始信号和从器件地址,此时R/W
位置1,CAT24WC01/02/04/08/16响应并发送应答信号,然后输出所要求的一个
8位字节数据,主器件不发送应答信号但产生一个停止信号。
连续读
连续读操作可通过立即读或选择性读操作启动。在CAT24WC01/02/04/08/16发送完一个8位字节数据后,主器件产生一个应答信号来响应,告知CAT24WC01/02/04/08/16
主器件要求更多的数据,对应每个主机产生的应答信号CAT24WC01/02/04/08/16将发送一个8位数据字节。当主器件不发送应答信号而发送停止位时结束此操作。
从CAT24WC01/02/04/08/16
输出的数据按顺序由N到N+1输出。读操作时地址计数器CAT24WC01/02/04/08/16整个地址内增加,这样整个寄存器区域在可在一个读操作内全部读出。当读取的字节超过
E(对于 24WC01,E=127;对24WC02,E=255;对24WC04,E=511;对24WC08,E=1023;对24WC16
E=2047)计数器将翻转到零并继续输出数据字节。
在本示例中采用的EEPROM芯片为AT24C08型号,该封装类型和24C02完全兼容;
AT24C08容量为8Kbit,即1KB,1024字节;24C02量为2kbit,为256字节。
引脚 | GPIO |
IIC_SCL | 时钟线PB6 |
IIC_SDA | 双向数据线PB7 |
//产生起始信号 void IIC_Start(void) { hi2c1.Instance->CR1|=1<<8; while(!(hi2c1.Instance->SR1&1<<0)){}//等待起始信号发送成功 hi2c1.Instance->CR1&=~(1<<8); } //停止信号 void IIC_Stop(void) { hi2c1.Instance->CR1|=1<<9; }6.3 IIC硬件数据收发
//发送数据 void IIC_WriteData(uint8_t data) { hi2c1.Instance->DR=data; while(!(hi2c1.Instance->SR1&1<<7)){}//等待数据发送完成 } /*发送地址*/ void IIC_WriteAddr(uint8_t adrr) { uint8_t stat; hi2c1.Instance->DR=adrr; while(!(hi2c1.Instance->SR1&1<<1)){}//等待数据发送完成 stat=hi2c1.Instance->SR2;//对SR2读取清除标志位 } uint8_t IIC_readData(void) { uint8_t data; hi2c1.Instance->CR1|=1<<10;//产生应答 while(!(hi2c1.Instance->SR1&1<<6)){}//等待数据到来 data=hi2c1.Instance->DR; hi2c1.Instance->CR1&=~(1<<10);//取消应答发送 return data; }6.4 AT24C08读写字节
#define AT24C08_ADDR_W 0xA0 //器件地址+写使能位 #define AT24C08_ADDR_R 0xA1 //器件地址+读使能位 /*写一个字节函数*/ void AT24C08_WriteOneByte(uint8_t addr,uint8_t data) { IIC_Start();//发送起始信号 IIC_WriteAddr(AT24C08_ADDR_W);//发送地址 IIC_WriteData(addr);//发送写入数据地址 IIC_WriteData(data);//写入数据 IIC_Stop();//停止信号 HAL_Delay(10);//写周期时间 } /*读一个字节函数*/ uint8_t AT24C08_ReadOneByte(uint8_t addr) { uint8_t data; IIC_Start();//发送起始信号 IIC_WriteAddr(AT24C08_ADDR_W);//器件地址+写使能 IIC_WriteData(addr);//发送写入数据地址 IIC_Start();//发送起始信号 IIC_WriteAddr(AT24C08_ADDR_R);//器件地址+读使能 data=IIC_readData();//读取一个字节数据 IIC_Stop();//停止信号 return data; }6.5 主函数
//发送数据 void IIC_WriteData(uint8_t data) { hi2c1.Instance->DR=data; while(!(hi2c1.Instance->SR1&1<<7)){}//等待数据发送完成 } /*发送地址*/ void IIC_WriteAddr(uint8_t adrr) { uint8_t stat; hi2c1.Instance->DR=adrr; while(!(hi2c1.Instance->SR1&1<<1)){}//等待数据发送完成 stat=hi2c1.Instance->SR2;//对SR2读取清除标志位 } uint8_t IIC_readData(void) { uint8_t data; hi2c1.Instance->CR1|=1<<10;//产生应答 while(!(hi2c1.Instance->SR1&1<<6)){}//等待数据到来 data=hi2c1.Instance->DR; hi2c1.Instance->CR1&=~(1<<10);//取消应答发送 return data; }
注意:STM32F10x硬件IIC和FSMC不能同时使用;
在STM32勘误手册中有说明: