今天在这里贴一个今天写的IIC读AT24C02的帖子
- #include "stm32f10x_i2c.h"
- #include "iic.h"
- #include "stdio.h"
- #define I2C_Speed 400000
- #define I2C1_SLAVE_ADDRESS7 0XA0
- #define I2C_PageSize 8
- u16 EEPROM_ADDRESS;
- void GPIO_Configuration(void)//GPIO_Pin_6,GPIO_Pin_7复用开漏输出
- {
- GPIO_InitTypeDef GPIO_InitStructure;
-
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//IIC1 和 IIC2 都是在APB1上的
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//SCL 和 SDA
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;// GPIO_Pin_6(SCL) GPIO_Pin_7;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//IIC 的 SDA和SCL都是复用开漏输出模式
- GPIO_Init(GPIOB,&GPIO_InitStructure);
- }
- void I2C_Configuration(void)
- {
- I2C_InitTypeDef I2C_InitStructure;
-
- I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//设置IIC是IIC模式;
- //IIC 的 工作模式有两种的,一种是IIC 一种是SMBus模式
- I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;//
- /*本成员设置的是I2C的SCL线时钟的占空比。SCL线的时钟信号的高电平时间
- 与低电平时间是没必要相同的,由于SDA线是在SCL线维持在高电平时读取或写入数据的,而在SCL的
- 低电平期间SDA的数据发生变化,所以高电平时间较长就不容易出现数据错误。根据I2C协议,在快速
- 模式和高速模式下SCL的高低电平时间可以不同。在STM32的I2C占空比配置中有两个选择,分别为高
- 电平时间比低电平时间为16:9 (I2C_DutyCycle_16_9)和2:1 ( I2C_DutyCycle_2)。 本实验中使用
- 的是I2C_DutyCycle_2*/
- I2C_InitStructure.I2C_OwnAddress1 = 0;//这个是STM32 本身的地址,可以随便设置,它是作为主设备的,但是如果作为从设备的话,设定的地址,就必须
- //作为主设备进行寻地址的地址了
- I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;//
- /*
- 本成员是关于I2C应答设置,设置为使能则每接收到一个字节就返回一个应
- 答信号。 本实验配置为允许应答(I2C_Ack_Enable),这是绝大多数遵循I2C标准的设备通讯的要求,
- 改为禁止应答(I2C_Ack_Disable)往往会导致通讯错误
- ***************/
- I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
- //本成员选择I2C的寻址模式是7位还是10位地址
- I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
- /*
- 本成员设置的是I2C的传输速率,在调用初始化函数时,函数会根据我们输
- 入的数值经过运算后把分频值写入到I2C的时钟控制寄存器。而我们写入的这个参数值不得高于
- 400KHz。**************/
-
- I2C_Init(I2C1,&I2C_InitStructure);//初始化
-
- I2C_Cmd(I2C1,ENABLE);//使能I2C1;
- printf("\n\r I2C_Configuration----\r\n");
-
- }
- void I2C_EE_Init(void)
- {
- GPIO_Configuration();
-
- I2C_Configuration();
-
- #ifdef EEPROM_Block0_ADDRESS
- EEPROM_ADDRESS = EEPROM_Block0_ADDRESS;
- //0xA0
- #endif
- #ifdef EEPROM_Block1_ADDRESS
- EEPROM_ADDRESS = EEPROM_Block1_AFFRESS;
- //0XA2
- #endif
- #ifdef EEPROM_Block2_ADDRESS
- EEPROM_ADDRESS = EEPROM_Block2_ADDRESS;
- //0XA4
- #endif
- #ifdef EEPROM_Block3_ADDRESS
- EEPROM_ADDRESS = EEPROM_Block3_ADDRESS;
- //0XA6
- #endif
- }
- /*********************
- 1:这个的思想就是先看看你的字节数是不是够你的1page的大小;
- 2:然后再去看看你设置的需要写的字节的位置
- 3:看看你需要写的这一页的还需要多少字节才能写完
- 4:最后就是去分析了;
- ******************/
- //NumOfPage 是指你需要写的字节一共需要占用的的页数
- //NumOfSingle 是指你需要写的字节写完完整的页数以后还剩下多少字节数
- //Addr 是你要写的第一个字节的位置
- //count 是你要写完一页page 的个数;
- //注意你写完一page的时候,他的地址会自动变成0的,没写完一页page 的时候,他的地址会自动累加这是一个很重要的特性
- void I2C_EE_BufferWrite(u8* pBuffer,u8 WriteAddr,u16 NumByteToWrite)
- {
- u8 NumOfPage = 0,NumOfSingle = 0,Addr = 0,count = 0;
- Addr = WriteAddr % I2C_PageSize;//把首个字节的位置找出来
- count = I2C_PageSize - Addr;//把写完该页page的个数找出来
- NumOfPage = NumByteToWrite / I2C_PageSize;//找出你要写的数据能占几页page
- NumOfSingle = NumByteToWrite % I2C_PageSize;//找出写完page以后还剩多少个字节
-
- if(Addr == 0)//如果上来要写的位置是某一个page 的 第一个位置
- {
- if(NumOfPage == 0)//如果要写的字数小于一页page 所需要的大小
- {
- I2C_EE_PageWrite(pBuffer,WriteAddr,NumOfSingle);//直接开始从page 写
- I2C_EE_WaitEepromStandbyState();//等待发送成功;
- }
- else
- {
- while(NumOfPage--)//如果page >0 那就写完page
- {
- I2C_EE_PageWrite(pBuffer,WriteAddr,I2C_PageSize);//写一页page
- I2C_EE_WaitEepromStandbyState();//等待这一页的数据发送完成
- WriteAddr += I2C_PageSize;//把地址进行累加
- pBuffer += I2C_PageSize;//字符往后加
- }
- if(NumOfSingle!=0)//写完你要写的page 以后如果还有写的数据
- {
- I2C_EE_PageWrite(pBuffer,WriteAddr,NumOfSingle);//将剩下的字符写进去
- I2C_EE_WaitEepromStandbyState();//等待数据发送完成
- }
- }
- }
- else
- {
- if(NumOfPage == 0)//要写的字符数小于一page
- {
- if(NumOfSingle < count)//如果写的数还不够写完1page的数的话
- {
- I2C_EE_PageWrite(pBuffer,WriteAddr,NumOfSingle);//直接写进去
- I2C_EE_WaitEepromStandbyState();//等待这一页的数据发送完成
- }
- else//如果要写的数据大于写完这一页的字数
- {
- I2C_EE_PageWrite(pBuffer,WriteAddr,count);//先把这一页写完
- I2C_EE_WaitEepromStandbyState();//等待数据发送完成
- WriteAddr += count;//将地址累加
- pBuffer += count;//
- I2C_EE_PageWrite(pBuffer,WriteAddr,NumOfSingle-count);//再去写完剩下的字节数
- I2C_EE_WaitEepromStandbyState();//等待数据完成
- }
- }
- else//如果要写的数据大于一page
- {
- NumByteToWrite -= count;//这个是写完本页剩下的字节数
- NumOfPage = NumByteToWrite / I2C_PageSize;//这个是还剩下的数据所占有的页数
- NumOfSingle = NumByteToWrite % I2C_PageSize;//剩下的数据写完页数以后还剩下的字节数
- if(count != 0)//如果要写完一页需要的字节数不是0;
- {
- I2C_EE_PageWrite(pBuffer,WriteAddr,count);//先把这一页写完
- I2C_EE_WaitEepromStandbyState();
- WriteAddr += count;
- pBuffer += count;
- }
- while(NumOfPage--)//写完剩下的page
- {
- I2C_EE_PageWrite(pBuffer,WriteAddr,I2C_PageSize);
- I2C_EE_WaitEepromStandbyState();
- WriteAddr += I2C_PageSize;
- pBuffer += I2C_PageSize;
- }
- if(NumOfSingle != 0)//将最后的字节写进去
- {
- I2C_EE_PageWrite(pBuffer,WriteAddr,NumOfSingle);
- I2C_EE_WaitEepromStandbyState();
- }
- }
- }
- }
- /*
- IIC通信的步骤;
- 1:首先要等待总线BUSY = 0;
- 2:产生一个开始的信号;然后等待EV5;
- 3:发送一个地址;然后等待EV6;
- 4:发送数据;等待EV8;
- 5:发送STOP;
- 这是通信一次的步骤;
- ******/
- void I2C_EE_ByteWrite(u8* pBuffer,u8 WriteAddr)//给EPPROM写一个字节
- {
- while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));//等待IIC忙结束
-
- I2C_GenerateSTART(I2C1,ENABLE);//产生开始信号
- // I2C_ CheckEvent() 检查最近一次 I2C 事件是否是输入的事件
- while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//等待EV5;
-
- I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Transmitter);//配置成发送方向和发送的外设地址
-
- while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//等待EV6
-
- I2C_SendData(I2C1,WriteAddr);//发送第一个数据(这里其实第一个数据是给EPPROM写地址)
-
- while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));//等待EV8
-
- I2C_SendData(I2C1,*pBuffer);//发送你要写的数据
-
- while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));//等待EV8
-
- I2C_GenerateSTOP(I2C1,ENABLE);//产生停止信号
- }
- void I2C_EE_PageWrite(u8* pBuffer,u8 WriteAddr,u8 NumByteToWrite)//写一个EPPROM 的 Page
- {
- while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));//等待IIC忙结束
-
- I2C_GenerateSTART(I2C1,ENABLE);//这个是产生开始信号
-
- while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//等待EV5
-
- I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Transmitter);//设置发送方向以及发送的地址
-
- while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//等待EV6(这里的EV6和EV8一块了,主要是因为这里的速度确实快)
-
- I2C_SendData(I2C1,WriteAddr);//发送第一个数据(这个其实就是给EPPROM写地址)
-
- while(! I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));//等待EV8
-
- while(NumByteToWrite--)//写数据
- {
- I2C_SendData(I2C1,*pBuffer);
-
- pBuffer++;
-
- while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));//等待EV8
- }
-
- I2C_GenerateSTOP(I2C1,ENABLE);//产生停止信号
- }
- void I2C_EE_BufferRead(u8* pBuffer,u8 ReadAddr,u16 NumByteToRead)//读NumByteToRead个EPPROM的字节
- {
- while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));//等待BUSY = 0;
-
- I2C_GenerateSTART(I2C1,ENABLE);//产生一个开始信号
-
- while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//等待EV5
-
- I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Transmitter);//发送一个外设地址
-
- while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//等待VE6;
-
- I2C_Cmd(I2C1,ENABLE);//使能外设
-
- I2C_SendData(I2C1,ReadAddr);//发送一个数据(这个就是你要读的数据的地址)
-
- while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));//EV8
-
- I2C_GenerateSTART(I2C1,ENABLE);//发送一个开始信号
-
- while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//EV5
-
- I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Receiver);//发送一个数据,加一个方向(这个就是读的方向)
-
- while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//EV6
-
- while(NumByteToRead)//剩下的就是读数据了
- {
- if(NumByteToRead == 1)//只有当最后一个数据的时候,才不会去应答,其他读的数据的时候需要去应答
- {
- I2C_AcknowledgeConfig(I2C1,DISABLE);//最后一个传输的数据不需要响应
- I2C_GenerateSTOP(I2C1,ENABLE);
- }
- if(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED))//EV7
- {
- *pBuffer = I2C_ReceiveData(I2C1);
- pBuffer++;
- NumByteToRead--;
- }
- }
- I2C_AcknowledgeConfig(I2C1,ENABLE);//把硬件自动应答打开
- }
- void I2C_EE_WaitEepromStandbyState(void)
- {
- vu16 SR1_Tmp = 0;
- do
- {
- I2C_GenerateSTART(I2C1,ENABLE);//产生一个开始的信号;
-
- SR1_Tmp = I2C_ReadRegister(I2C1,I2C_Register_SR1);//
-
- I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Transmitter);
- }
- while(!(I2C_ReadRegister(I2C1,I2C_Register_SR1) & 0x0002));//这个是判断你发送的数据成功没成功
-
-
- I2C_ClearFlag(I2C1,I2C_FLAG_AF);//清除应答错误标志位
-
- I2C_GenerateSTOP(I2C1,ENABLE);
- }
- void I2C_Test(void)
- {
- u16 i;
- u8 I2c_Buf_Write[256];
- u8 I2c_Buf_Read[256];
-
- printf("写入数据\n\r");
-
- for(i=0;i<=255;i++)
- {
- I2c_Buf_Write[i] = i;
- printf("0x%02X ",I2c_Buf_Write[i]);
- if(i%16 == 15)
- {
- printf("\n\r");
- }
- }
- I2C_EE_BufferWrite(I2c_Buf_Write,EEP_Firstpage,256);
-
- printf("\n\r读出的数据\r\n");
- I2C_EE_BufferRead(I2c_Buf_Read,EEP_Firstpage,256);
-
- for(i=0;i<256;i++)
- {
- if(I2c_Buf_Read[i] != I2c_Buf_Write[i])
- {
- printf("0x%02X ",I2c_Buf_Read[i]);
- printf("错误:I2C EEPROM写入与读出数据不一样\r\n");
- return;
- }
- printf("0x%02X ",I2c_Buf_Read[i]);
- if(i%16 == 15)
- {
- printf("\r\n");
- }
- }
- printf("读写测试通过PASSED\r\n");
- }
复制代码 这里主要用的东西在这里我给大家贴上(不知道为什么,今天想偷点懒)
IICçå¼è
IICçæ¶éæ
GPIO模å¼
è¿ä¸ªå¯¹åºä¸è¾¹çåå读çEV5ä¹ç±»çä¸è¥¿
先这样吧,确实有点懒了,但是基本上都全了,代码在附件上,大家可以看看,有什么错误之处还请指出,毕竟不是很熟悉。大家将就着看吧。
IIC.rar
(5.29 MB, 下载次数: 1341)
|
谢谢分享啦