首先说下编写这个程序的目的和思路:把AT24C02的驱动代码放一个模块里,只对外提供3个API函数-初始化,指定地址写一个字节,指定地址读一个字节。页写页读什么的都不用,这样方便外部调用. 参考官方的库和神舟的源代码编写了个简单的读写AT24C02一个字节的程序,调试发现了几个问题: 1. 程序第一次调试没问题,第二次修改写入的数据再调试就陷入了死循环,再也跳不出来了 2. 换成神舟1号(目标板是神舟1号开发板)的源代码,重新编译写入调试,还是同样的问题 3. 把仿真器,目标板全部断电,放一段时间再调试,有时候能够正常跑,有时死锁 4. 打开寄存器查看,发现通常I2C模块一旦初始化,SR1的BUSY位自动置位,等多久都没有 上网搜索,发现碰得这问题的人很多,绝大多数意见都认为是这个BUSY问题,有人说是bug官方推荐模拟I2C,有人说是官方例程有问题,其中一位指出是初始话顺序的问题,应该先配置I2C,再配置GPIO的复用功能,这话很有道理,照做,修改自己写的程序调试,第 一次是没问题,reset再运行,还是死锁,问题依旧。 后来隐约想到,官方文档好像说引脚的初始话应该先置高。修改,在初始化的配置GPIO的复用功能之前,先将GPIO配置为输出,且置 高,而且在每次读操作之后执行初始化一次防止BUSY(写操作实测不需要)。测试再也没有发现令人崩溃的BUSY了。 下面是AT24C02.C的代码, #include"stm32f10x.h" static AT24C02_Delay(){ //延时2ms, 确保写入成功 ;对外隐藏 uint32_t i; i=72*200*2; //72对应系统时钟多少兆,2对应要延时多少毫秒 while(i--); } void AT24CO2_Init(uint32_t I2C_speed,uint8_t I2C_selfAddr ){ //I2C_speed : I2C的SCL的频率,通常配置为100000 //I2C_selfAddr : 自身地址,这里可以为任意 GPIO_InitTypeDef GPIO_InitStructure; I2C_InitTypeDef I2C_InitStructure; //第一步: RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); I2C_DeInit(I2C1); I2C_InitStructure.I2C_ClockSpeed = I2C_speed; I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = I2C_selfAddr; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit; I2C_DeInit(I2C1); I2C_Init(I2C1,&I2C_InitStructure); //第二步:先将Pins配置为通用输出且置高 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_6|GPIO_Pin_7); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); //第三步:配置为I2C功能 GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_6|GPIO_Pin_7); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD ; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); } void AT24C02_WriteByte(uint8_t AT24C02_MemAddr, uint8_t data){ //向指定地址写一个数据,1个字节 //AT24C02_MemAddr: 存储地址,范围为0x00~0xFF // data : 8位数据,范围为0x00~0xFF I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, 0xA0,I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, AT24C02_MemAddr); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_SendData(I2C1,data); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTOP(I2C1, ENABLE); AT24C02_Delay(); //延时2毫秒,确保写入成功 } uint8_t AT24C02_ReadByte(uint8_t AT24C02_MemAddr){ //随机读取一个字节的数据 //从指定地址读出一个字节 //AT24C02_MemAddr: 存储地址,范围为0x00~0xFF uint8_t I2cReceiveData; I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, 0xA0,I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, AT24C02_MemAddr ); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Receiver); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)); I2cReceiveData=I2C_ReceiveData(I2C1); I2C_AcknowledgeConfig(I2C1, DISABLE); I2C_GenerateSTOP(I2C1, ENABLE); I2C_AcknowledgeConfig(I2C1, ENABLE); AT24CO2_Init( 100000, 0xDD ); //这里跟main函数中的初始设置保持一致 return I2cReceiveData ; } |
回复:解决stm32f10x I2C读写EEPROM芯片死锁问题
RE:解决stm32f10x I2C读写EEPROM芯片死锁问题
I2C_DeInit(I2C1);
回复:解决stm32f10x I2C读写EEPROM芯片死锁问题
RCC_APB1PeriphClockCmd(?????
, ENABLE );
RCC_APB2PeriphClockCmd( ????| RCC_APB2Periph_GPIOA |RCC_APB2Periph_AFIO
, ENABLE );
如有该设的时脉未设到,及不该出现同时启动了的,皆无法正常运行
回复:解决stm32f10x I2C读写EEPROM芯片死锁问题
回复第 3 楼 于2012-12-03 17:37:57发表:
I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
I2C_DeInit(I2C1);