在线时间1 小时
UID334437
ST金币0
蝴蝶豆0
注册时间2011-12-16
新手上路
- 最后登录
- 1970-1-1
|
a0a.1 0b0c
首先说下编写这个程序的目的和思路:把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 ;
}
|
|