文章目录
前言
本文是基于嵌入式开发板CT117E,stm32f103RBT6。"空手套白狼"就是直接利用官方给的库(v3.5),进行拷贝修改形成可以正常运行的代码。
一、原理图
二、由原理图得到的信息
- 获取8位地址: 前四位是固定的1010, 最后一位为0表示写,为1表示读,中间三位对应上面的电路图,E0,E1,E2, 都是接的GND,所以为E0=0,E1=0,E2=0;可以知道M24C02MN6的从设备写地址为10100000(0xa0),读设备地址为10100001(0xa1)。
三、iic对e2prom的读写函数
-
给的资源包里面有i2c的驱动源码,所以只需要写e2prom的读和写的函数就可以了。
-
我们要了解e2prom的读写时序和他的地址,地址是8位的,最后一位是读写标志,0–写,1–读,其他需要参考原理图进行地址的判断,蓝桥杯的开发板看原理图可以看出,写的时候应该是0xa0,读的时候是0xa1,接下来就是时序的编程,这个需要记住,不能错任何一步;EEPROM一个地址,存入一个字节的数据,所以针对不同类型的数据,需要分离成单个字节的数据;所以地址和数据的变量都是定为u8。
-
写的函数较为容易: 开始—发送e2prom的地址(0xa0)—等待回应—发送我们要写的地址—等待回应–发送我们要写入的一个字节数据—等待回应----发出结束信号。
void i2c_write(u8 addr,u8 data)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CSendByte(data);
I2CWaitAck();
I2CStop();
}
- 读函数: 开始信号—发送e2prom的地址( 0xa0先是写我们要读的地址给它)–等待回应—发送我们要读的地址----等待回应—再次发送开始信号----发送 0xa1(表示要读)—等待回应—接收数据—发送应答信号–结束信号。
u8 i2c_read(u8 addr)
{
u8 t;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
t=I2CReceiveByte();
I2CWaitAck();
I2CStop();
return t;
}
四、存取数据应用
①存取32位的数据
void u32_write(u8 addr,u32 data)
{
i2c_write(addr,data&0xff);
Delay_Ms(5);
i2c_write(addr+1,data>>8&0xff);
Delay_Ms(5);
i2c_write(addr+2,data>>16&0xff);
Delay_Ms(5);
i2c_write(addr+3,data>>24&0xff);
Delay_Ms(5);
}
u32 u32_read(u8 addr)
{
u32 t;
t+=i2c_read(addr);
Delay_Ms(5);
t+=(i2c_read(addr+1))<<8;
Delay_Ms(5);
t+=(i2c_read(addr+2))<<16;
Delay_Ms(5);
t+=(i2c_read(addr+3))<<24;
Delay_Ms(5);
return t;
}
u32_write(0x55,14253675);
read_32=u32_read(0x55);
②存取2位小数的浮点型数据
void float_2_write(u8 addr,float data) //2位小数的写入
{
u32 t;
t=100*data;
i2c_write(addr,t&0xff);
Delay_Ms(5);
i2c_write(addr+1,t>>8&0xff);
Delay_Ms(5);
}
float float_2_read(u8 addr) //2位小数的读出
{
float t;
t+=i2c_read(addr);
Delay_Ms(5);
t+=(i2c_read(addr+1))<<8;
Delay_Ms(5);
return t/100;
}
float_2_write(0x55,100.85);
float_2=float_2_read(0x55);
③存取字符串字符以ASCII码存储
for(i=0;i<sizeof(str_write);i++) //存
{
i2c_write(0x10+i,str_write[i]);
Delay_Ms(5);
}
for(i=0;i<sizeof(str_write);i++) //取
{
str_read[i]=i2c_read(0x10+i);
}
④存取负数
- 负数: 存的时候判断一下是否为符数,是的话,腾出一个地址存放一个标识,例如"-",第二个地址直接存他的相反数,在读的时候进行判断标志,读出后的结果用0减去就行了,达到人为的负数存取效果。
if(minus_write<0)
{
i2c_write(0x06,'-');
Delay_Ms(5);
i2c_write(0x07,-minus_write); //存正数
Delay_Ms(5);
}
if(i2c_read(0x06)=='-')
{
minus_read = 0 - i2c_read(0x07);
}
五、在主函数的应用方法
- 主函数应用:
if(i2c_read(0x14)!=5) //这里按道理说程序只会执行一次;
{
LCD_DisplayStringLine(Line0,"123456");
i2c_write(0x14,5);
Delay_Ms(2); //这里一定要加延时,cpu的速度太快了,需要等待一下e2PROM
i2c_write(0x21,0); //初始化我们要写的地址
Delay_Ms(2);
}
i2c_num=i2c_read(0x21);
i2c_num++;
i2c_write(0x21,i2c_num);
sprintf((char *)i2c_buff,"i2c_num: %d ",i2c_num);
LCD_DisplayStringLine(Line0,i2c_buff);
- 这里有1/256的概率可能会翻车,因为我们一般都需要初始化我们在内存的值为0,这个初始化如果和平时一样,每次掉电重启都会初始化一次,达不到我们要掉电后值不变的效果,而会变成每次都初始化为0,所以这里巧妙地使用读内存的值,如果不是这个值,我们就给内存赋值为这个值,然后顺便在这里初始化我们本来要存的地址的值,这个只会执行一次,但这样设计不太靠谱…