IIC总线是常用的串行总线,它只需要简单的两根线就可以实现数据的高速传输,同时还可以实现多机通信功能。
在单片机中用的比较多的就是通过IIC总线操作EEPROM芯片。比较常用的EEPROM芯片就是24Cxx系列的芯片,主要用来存储系统运行过程中的关键数据。
要操作这个芯片的话,必须按照一定的时序去读写。这个时序通常被称为通信协议。24Cxx系列芯片通信协议如下。
I2 C 总线协议
I 2 C 总线协议定义如下:
只有在总线空闲时才允许启动数据传送
在数据传送过程中 当时钟线为高电平时 数据线必须保持稳定状态 不允许有跳变 时钟线为高电平时 数据线的任何电平变化将被看作总线的起始或停止信号。
起始信号
时钟线保持高电平期间 数据线电平从高到低的跳变作为 I 2 C 总线的起始信号
停止信号
时钟线保持高电平期间 数据线电平从低到高的跳变作为 I 2 C 总线的停止信号
这里就使用最简单的几个通信时序起始、停止、读、写和应答时序。
为了IIC协议的通用性,将这几个协议封装为一个c文件,这样以后每个使用IIC协议的器件都能调用这个文件。
这里将最常用的几个信号封装为函数,当操作24Cxx芯片的时候,直接调用这几个函数。
- #include "24Cxx.h"
- #include "delay.h"
- void AT24Cxx_Init(void)
- {
- IIC_Init();
- }
- //在AT24CXX指定地址读出一个数据
- //ReadAddr:开始读数的地址
- //返回值 :读到的数据
- u8 AT24Cxx_ReadOneByte(u16 ReadAddr)
- {
- u8 temp = 0;
- IIC_Start();
- if(EE_TYPE > AT24C16)
- {
- IIC_Send_Byte(0xA0); //发送写命令
- IIC_Wait_Ack();
- IIC_Send_Byte(ReadAddr >> 8); //发送高地址
- IIC_Wait_Ack();
- }
- else
- IIC_Send_Byte(0xA0 + ((ReadAddr / 256) << 1)); //发送器件地址0XA0,写数据
- IIC_Wait_Ack();
- IIC_Send_Byte(ReadAddr % 256); //发送低地址
- IIC_Wait_Ack();
- IIC_Start();
- IIC_Send_Byte(0xA1); //进入接收模式
- IIC_Wait_Ack();
- temp = IIC_Read_Byte(0);
- IIC_Stop(); //产生一个停止条件
- return temp;
- }
- //在AT24CXX指定地址写入一个数据
- //WriteAddr :写入数据的目的地址
- //DataToWrite:要写入的数据
- void AT24Cxx_WriteOneByte(u16 WriteAddr, u8 DataToWrite)
- {
- IIC_Start();
- if(EE_TYPE > AT24C16)
- {
- IIC_Send_Byte(0xA0); //发送写命令
- IIC_Wait_Ack();
- IIC_Send_Byte(WriteAddr >> 8); //发送高地址
- }
- else
- IIC_Send_Byte(0xA0 + ((WriteAddr / 256) << 1)); //发送器件地址0XA0,写数据
- IIC_Wait_Ack();
- IIC_Send_Byte(WriteAddr % 256);
- IIC_Wait_Ack();
- IIC_Send_Byte(DataToWrite);
- IIC_Wait_Ack();
- IIC_Stop();
- delay_ms(10);
- }
- //在AT24CXX里面的指定地址开始写入长度为Len的数据
- //该函数用于写入16bit或者32bit的数据.
- //WriteAddr :开始写入的地址
- //DataToWrite:数据数组首地址
- //Len :要写入数据的长度2,4
- void AT24Cxx_WriteLenByte(u16 WriteAddr, u32 DataToWrite, u8 Len)
- {
- u8 t;
- for(t = 0; t < Len; t++)
- {
- AT24Cxx_WriteOneByte(WriteAddr + t, (DataToWrite >> (8 * t)) & 0xff);
- }
- }
- //在AT24CXX里面的指定地址开始读出长度为Len的数据
- //该函数用于读出16bit或者32bit的数据.
- //ReadAddr :开始读出的地址
- //返回值 :数据
- //Len :要读出数据的长度2,4
- u32 AT24Cxx_ReadLenByte(u16 ReadAddr, u8 Len)
- {
- u8 t;
- u32 temp = 0;
- for(t = 0; t < Len; t++)
- {
- temp <<= 8;
- temp += AT24Cxx_ReadOneByte(ReadAddr + Len - t - 1);
- }
- return temp;
- }
- //检查AT24CXX是否正常
- //这里用了24XX的最后一个地址(255)来存储标志字.
- //如果用其他24C系列,这个地址要修改
- //返回1:检测失败
- //返回0:检测成功
- u8 AT24Cxx_Check(void)
- {
- u8 temp;
- temp = AT24Cxx_ReadOneByte(255);
- if(temp == 0x55)
- return 0;
- else
- {
- AT24Cxx_WriteOneByte(1023, 0x55);
- temp = AT24Cxx_ReadOneByte(255);
- if(temp == 0x55)
- return 0;
- }
- return 1;
- }
- //在AT24CXX里面的指定地址开始读出指定个数的数据
- //ReadAddr :开始读出的地址 对24c02为0~255
- //pBuffer :数据数组首地址
- //NumToRead:要读出数据的个数
- void AT24Cxx_Read(u16 ReadAddr, u8 *pBuffer, u16 NumToRead)
- {
- while(NumToRead)
- {
- *pBuffer++ = AT24Cxx_ReadOneByte(ReadAddr++);
- NumToRead--;
- }
- }
- //在AT24CXX里面的指定地址开始写入指定个数的数据
- //WriteAddr :开始写入的地址 对24c02为0~255
- //pBuffer :数据数组首地址
- //NumToWrite:要写入数据的个数
- void AT24Cxx_Write(u16 WriteAddr, u8 *pBuffer, u16 NumToWrite)
- {
- while(NumToWrite--)
- {
- AT24Cxx_WriteOneByte(WriteAddr, *pBuffer);
- WriteAddr++;
- pBuffer++;
- }
- }
复制代码
这里就是对具体的芯片操作函数,在主函数中通过这几个函数就可读写EEPROM存储芯片的内容了。
- int main(void)
- {
- u8 key;
- u16 i = 0, j = 0;
- u8 datatemp[SIZE];
- delay_init();
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
- uart_init(115200);
- LED_Init();
- KEY_Init();
- AT24Cxx_Init();
- printf("IIC test!!!\r\n");
- while(AT24Cxx_Check())
- {
- printf("The chip is not detected, please check whether the hardware connection is normal!!!\r\n");
- delay_ms(300);
- LED1 = !LED1;
- }
- while(1)
- {
- key = KEY_Sacn(0);
- if(key == WKUP_PRES)
- {
- printf("\r\nStart Write 24C02....\r\n");
- AT24Cxx_Write(0, (u8 *)TEXT_Buffer, SIZE);
- printf("24C02 Write Finished!\r\n");
- }
- else if(key == KEY1_PRES)
- {
- printf("\r\nStart Read 24C02....\r\n");
- AT24Cxx_Read(0, datatemp, SIZE);
- printf("The Data Readed Is: ");
- for(j = 0; j < SIZE; j++)
- {
- printf("%c", datatemp[j]);
- }
- }
- i++;
- if(i == 20)
- {
- i = 0;
- LED0 = !LED0;
- }
- delay_ms(5);
- }
- }
复制代码
这里通过按键来测试存储芯片,一个按键按下后向芯片内写入数据,另一个按键按下后从芯片中读取刚才写入的内容。
|