友情提示:380元/半年,儿童学编程,就上码丁实验室。
我是潘,曾经是个工程师。这是 “Arduino 公开课” 系列的入门教程。本课将介绍EEPROM读写与获取串口数据流。有任何疑问请在评论区提出,我会逐一回答。
EEPROM (Electrically Erasable Programmable Read-Only Memory),电可擦可编程只读存储器 — 一种掉电后数据不丢失的存储器。最初的ROM 是不能编程的,出厂什么内容就永远什么内容。后来出现了PROM,可以写入一次,但要是写错了,只能换一片,自认倒霉。
人类文明不断进步,终于出现了可多次擦除写入的EPROM。不过,每次擦除要把芯片拿到紫外线上照一下。试想一下,你往单片机上写入一个程序后,发现有个小地方要改,为此你要把单片机放紫外灯下照半小时,然后才能再下一次,这么折腾一天也改不了几次。
最终,可以随意修改的 EEPROM 出现了,拯救了一大批程序员。很多人将它与FLASH闪存相比较,实际上 FLASH 也是 EEPROM 一种。为了区分,我们指EEPROM 都是狭义的 EEPROM,与 FLASH 的区别如下:
1、 FLASH 按扇区操作,EEPROM则按字节操作
2、 FLASH 写入时间长,EEPROM写入时间短
3、 FLASH 擦写次数少(TLC 200次 ~ SLC 10000次),EEPROM次数多(1000000次)
4、 FLASH 电路结构简单,成本低,EEPROM工艺复杂,成本高
5、运行时,EEPROM 可以修改,FLASH则不行。因此EEPROM可以存储一些参数,FLASH 存储程序代码和不需修改的数据。
Arduino 上既有FLASH,也有EEPROM。存放程序的区域就是FLASH,Uno 的空间大小为32KB,而存储一些需要随时修改,但又能掉电保存的数据,比如:数字收音机的频率、智能家居各模块的开关状态等,则放在EEPROM,空间大小为1KB。
EEPROM 的操作,官方已经提供了8个示例,我们先看看最基本的三个 Write、Read、Clear示例。
程序略微修改了一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/*
作者:Ardui.co
效果:EEPROM 写入数据
版本:1.0
更新时间:2017年3月20日
*/
#include <EEPROM.h>
intaddr=0;//初始化地址变量
voidsetup(){
pinMode(13,OUTPUT);
}
voidloop(){
intval=analogRead(0)/4;//从A0读取结果0~1023,转换为0~255,空载输入为随机数
EEPROM.write(addr,val);//按照 EEPROM 地址,写入数值
if(addr<=EEPROM.length()){// 如果地址达到末尾,从头开始
addr=addr+1;//前一个地址写入数据后,进入下一个地址
}
else{
digitalWrite(13,HIGH);// 全部写入完毕,点亮板载LED
}
delay(10);//延时100ms,注意每次写入需要3.3ms,因此不能少于4ms;
}
|
EEPROM.write(addr, val) 是根据地址来写入数据的:
addr:写入字节的地址,整数变量;
val:写入的字节,范围0 ~ 255。
现在要把这些数据从EEPROM读出来:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
/*
作者:Ardui.co
效果:EEPROM 读取数据
版本:1.0
更新时间:2017年3月20日
*/
#include <EEPROM.h>
intaddress=0;
bytevalue;
voidsetup(){
Serial.begin(9600);
}
voidloop(){
value=EEPROM.read(address);
Serial.print(address);
Serial.print(“\t”);
Serial.print(value,DEC);
Serial.println();
address=address+1;
if(address==EEPROM.length()){
address=0;
}
delay(500);
}
|
打开串口监视器,可以看到刚才写进入的随机数据:
EEPROM一般用于存储设置参数等数据,如果我们想把设备RESET,很简单设置一个Clear程序即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/*
作者:Ardui.co
效果:EEPROM 清零
版本:1.0
更新时间:2017年3月20日
*/
#include <EEPROM.h>
voidsetup(){
pinMode(13,OUTPUT);
for(inti=0;i<EEPROM.length();i++){
EEPROM.write(i,0);
}
digitalWrite(13,HIGH);
}
voidloop(){
}
|
现在,我们是让Arduino不停地从0号地址位开始的读取EEPROM,把读取到的数值输出到串口监视器上。如果,向串口监视器输入数字,更新从0号地址位开始的EEPROM信息。并间接的更新了输出到监视器上的数值。
由于官方EEPROM 每次只能写入或读取一个地址位,因此我们设置了两个函数 EEPROM_write 与 EEPROM_read,形参跟官方一样,但可以连续读取或写入:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/*
作者:Ardui.co
参考:部分使用了极客工坊弘毅老师的代码 http://www.geek-workshop.com/thread-4413-1-1.html
效果:读取串口数据流,写入EEPROM
版本:1.0
更新时间:2017年3月20日
*/
#include <EEPROM.h>
#define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp);}
#define EEPROM_read(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp=EEPROM.read(address+i);}
unsignedlongincomingByte=0; // 定义无符号长整数型变量incomingByte初始值为0
unsignedlongincomingByteTemp=0;
voidsetup(){
Serial.begin(9600); // 打开串口,设置数据传输速率9600
}
voidloop(){
if(Serial.available()>0){
incomingByte=Serial.parseInt(); //读取串口传入的下一个有效整数,把该整数赋值给incomingByte变量
EEPROM_write(0,incomingByte) //把incomingByte变量从0地址位开始写入EEPROM
}
if(incomingByte!=incomingByteTemp){
EEPROM_read(0,incomingByte)//从0地址位开始读取EEPROM,把值写入变量incomingByte
Serial.println(incomingByte);//通过串口输出
incomingByteTemp=incomingByte;
delay(1000);
}
}
|
串口命令 Serial.parseInt() 的作用是查找传入的串行数据流中的下一个有效整数。Serial.read()只能每次读取一个字节,Serial.parseInt() 一次能读取一个数据流。
byte *pp=(byte*)&p 的意思是:定义了一个字节型数组指针pp,将它指向了变量 p 。(byte*) 是为了将&p 强制转换为字节型指针,以便赋值给*pp 。