蓝桥杯嵌入式——EEPROM避坑指南(干货)

要点1—驱动代码编写

蓝桥杯比赛时会给模拟的iic驱动代码,也就是下面这两个.c和.h文件。我们需要做的是,根据它提供的AT24C02数据手册中的时序图编写两个函数来实现对EEPROM的读写操作。
在这里插入图片描述

我建议大家能够理解这两个时序图,看着时序图来编写读写函数,轻松的多,完全不需要背过下面这两个函数。(时序图就在数据手册中)
在这里插入图片描述
在数据手册中找到这两个时序图。
在这里插入图片描述在这里插入图片描述

要点2:

(1)有符号6位数的存取

上面那两个读写函数是对 unsigned char 类型数据,也就是8位无符号数操作的。有时候我们需要存储16位无符号数的时候,可以采取这样的方法:

void write_16(unsigned char add,u16 data)
{
    
    
	unsigned char a,b;
	a=data/256;
	b=data%256;
	i2c_write(add,b);Delay_Ms(5);
	i2c_write(add+1,a);	  
}
u16 read_16(unsigned char add)
{
    
    
	u16 a;
	unsigned char c,b;
	c=i2c_read(add);Delay_Ms(5);
	b=i2c_read(add+1);
	a=c+b*256;
	return a;
}

(2)16位有符号数的存储

需要先明白一点,有符号数和无符号数在存储器里面都是由0和1组成的,有符号数只不过是把最高位用做符号位(1代表复数,0代表正数)。所以,我想说的是,存储16位有符号数时也可以用16位无符号数的存储方法。只需要在读取时加一个强制转换即可。

short  tem_up;  //定义一个16位有符号数

......//没有必要展示的代码就略过了
......
......

tem_up=(short)read_16(0x03);//加个强制转换  ,妥妥的

要点3——必须加延时

每两个读取或者写入函数之间必须加5毫秒延时,是必须加。如果不加的话,数据非常容易乱(亲身体验)。

原因是,EEPROM外设的读取速度是跟不上MCU的运行速度的,需要让MCU停下来等待一会儿。5ms咱们看着不起眼,对于CPU来说,已经是很长一段时间了。

要点4——几乎每届省赛都会遇到的问题(重要)

以第七届省赛做一个分析(只关注EEPROM部分):
在这里插入图片描述
可以看到,题目要求,设备第一次上电,从EEPROM中读取到的初始值为30、50、70,之后每次修改这三个数值,都将具体值存入EEPROM,设备再次上电,就可以从EEPROM中读取具体值。
后半句话是没问题的,可以通过程序来实现,只要在程序的最前面加一个读取EEPROM的函数就好了。
问题在前面,题目规定了读取的初值,可是,怎么才能够保证你读取到的数值是“30、50、70”呢?要知道,把程序下载到一块新板子上,EEPROM中存储的数值是不确定的。
有小伙伴可能会想,这还不简单,在程序最前面加一个写入函数不就好了,把“30、50、70”给提前写到新板子上,先写好,再读取。可是这就会导致,之后每次上电复位,读取到的都是“30、50、70”。这就与题目要求的“再次上电,读取到修改值”不符了。
针对这个问题,这里我提供一个程序上的解决方案:

  1. 代码的具体思路
    要想实现,第一次读取到的是自己设定的初值,之后读取到的是修改值。那就需要加一个判断语句,如果判断为真,就将初始值“30、50、70”写入到板子上,判断为假,就不写入初始值。而且,这个判断语句只需要执行一次。
  2. 具体代码:
int main()
{
    
    
	char string[20];
	ADC_init();
	LED_Init();
	SysTickInit();
	Buzzer_Init();
	i2c_init();	
	Usart2_init();
	key_init();
	STM3210B_LCD_Init();
	LCD_Clear(Blue);
	LCD_SetBackColor(Blue);
	LCD_SetTextColor(White);
	if(Read_AT24c02(0x06)!=2)   //判断
	{
    
    
				Write_AT24c02(0x01,30);				DelayMS(5);
				Write_AT24c02(0x02,50);				DelayMS(5);
				Write_AT24c02(0x03,70);				DelayMS(5);	
		
				Write_AT24c02(0x06,2); //加了这个语句之后,就可以让这个判断只执行一次				
				DelayMS(5);
	}	
	Level[0]=Read_AT24c02(0x01);DelayMS(5);
	Level[1]=Read_AT24c02(0x02);DelayMS(5);
	Level[2]=Read_AT24c02(0x03);DelayMS(5);	

关键是判断条件的确定,我采取的是随遍读取一个EEPROM的地址,他只有256分之一的概率等于2,就意味着这段代码,可以成功的概率是256分之255。当然,如果觉得256分之一还是太大的话,可以这样写:

	if(Read_AT24c02(0x06)!=2&&Read_AT24c02(0xaa)!=15)   //地址和数值都是瞎写的
	{
    
    
				Write_AT24c02(0x01,30);				DelayMS(5);
				Write_AT24c02(0x02,50);				DelayMS(5);
				Write_AT24c02(0x03,70);				DelayMS(5);	
		
				Write_AT24c02(0x06,2); //加了这个语句之后,就可以让这个判断只执行一次				
				DelayMS(5);
				Write_AT24c02(0xaa,15); 			
				DelayMS(5);
	}	

这样,概率就变成了256的平方分之一。(意义不大,抖个机灵而已)

这些都是我一点点总结的知识点,要是有对您有帮助的话,就给点个赞吧,球球了!

猜你喜欢

转载自blog.csdn.net/qq_43690936/article/details/109011569