上次已经完成了IIC读写AT24C02的协议层,现在开始编写读写AT24C02的驱动函数。先从单字节的读写开始。
字节写要求在接收器件地址和ACK应答后,接收位的字地址。接收到这个地址后AT24C02应答“0”,然后是一个8位数据。在接收8位数据后,AT24C02应答“0”,接着必须由主器件发送停止条件来终止写序列。
此时AT24C02进入内部写周期tWR,数据写入非易失性存储器中,在此期间所有输入都无效。直到写周期完成,AT24C02才会有应答。
void AT24C02_ByteWrite(u8 wordAdd,u8 dat,s8 *err)
{
u8 ack = 0;
IIC_Start();
IIC_SendByte(AT24C02_ADD< < 1);
ack = IIC_CheckAck();
if(ack != 0) //发器件地址
{
IIC_Stop(); //不应答
err = -1;
return;
}
IIC_SendByte(wordAdd); //发字地址
ack = IIC_CheckAck();
if(ack != 0) //不应答
{
IIC_Stop();
*err = -2;
return;
}
IIC_SendByte(dat); //发数据
ack = IIC_CheckAck();
if(ack != 0) //不应答
{
IIC_Stop();
*err = -3;
return;
}
IIC_Stop();
*err = 0;
}
其中传入了一个错误检测err,是在测试程序时为了快速发现错误位置而设置的。如果出现错误,就发送停止信号并用return退出该次写操作,由于该函数为void类型,所以直接return就可以了,不用带返回值。
和字节写相对应的是随机读,读取任意一个地址的数据。
随机读需先写一个目标字地址,一旦AT24C02接收器件地址和字地址并应答了ACK,主器件就产生一个重复的起始条件。
然后,主器件发送器件地址,AT24C02应答ACK,并随时钟送出数据。主器件无需应答“0”,但需发送停止条件。
u8 AT24C02_RandomRead(u8 wordAdd,s8 *err)
{
u8 ack = 0;
u8 temp = 0;
IIC_Start();
IIC_SendByte(AT24C02_ADD< < 1);//发器件地址
ack = IIC_CheckAck();
if(ack != 0) //不应答
{
IIC_Stop();
*err = -4;
goto loop;
}
IIC_SendByte(wordAdd); //发字地址
ack = IIC_CheckAck();
if(ack != 0) //不应答
{
IIC_Stop();
*err = -5;
goto loop;
}
IIC_Start();
IIC_SendByte(AT24C02_ADD< < 1 | 1);//发器件地址(读)
ack = IIC_CheckAck();
if(ack != 0) //不应答
{
IIC_Stop();
*err = -6;
goto loop;
}
temp = IIC_ReadByte();
IIC_NoAcktoSlave();
IIC_Stop();
*err = 0;
loop:
return temp;
}
跟写字节一样,这里也引入了err判断错误,出现错误发送停止信号并退出该次读操作。因为该函数需要返回值,所以这里不能像上面那样直接return,但是出现错误,也不能让return带着一个未知的数返回。这里退出该次读操作用到了C语言中很忌讳的goto,直接让程序跳到想要的位置。这种方式来做处理在嵌入式中是比较常见的,虽然C语言中goto是不被推荐使用的,但是只要能把它用的好,就可以大胆的用。
字节读写函数封装完成后,直接在主函数中调用。AT24C02擦写次数只有100万次左右,所以写函数不可以放入while循环中,否则器件可能很快就坏了。
主文件
#include "stm32f4xx.h"
#include "led.h"
#include "usart.h"
#include "delay.h"
#include "stdio.h"
#include "AT24C02.h"
int main()
{
s8 err = 0;
u8 temp = 0;
Usart1_Init(115200);
LED_Init(); //初始化LED灯
AT24C02_Init();
AT24C02_ByteWrite(0x05,125,&err);
temp = AT24C02_RandomRead(0x05,&err);
printf("temp = %drn",temp);
while(1)
{
}
}
将程序烧入开发板中,打开串口助手,可以看到读到的数正好是写入的数,AT24C02单字节读写成功。