51单片机eeprom读取和写
实验八 51系列单片机IIC
I2C总线上的所有器件连接在一个公共的总线上,因此,主器件在进行数据传输前选择需要通信的从器件,即进行总线寻址。 I2C总线上所有外围器件都需要有惟一的地址,由器件地址和引脚地址两部分组成,共7位。器件地址是I2C器件固有的地址编码,器件出厂时就已经给定,不可更改。引脚地址是由I2C总线外围器件的地址引脚(A2,A1,A0)决定,根据其在电路中接电源正极、接地或悬空的不同,形成不同的地址代码。引脚地址数也决定了同一种器件可接入总线的最大数目。 地址位与一个方向位共同构成I2C总线器件寻址字节。寻址字节的格式如表所示。方向位(R/)规定了总线上的主器件与外围器件(从器件)的数据传输送方向。当方向位R/=1,表示主器件读取从器件中的数据;R/=0,表示主器件向从器件发送数据。
从地址中读取一个字节的数据
INT8U read_random(INT8U RomAddress) { INT8U Read_data; I_Start(); I_Write8Bit(WriteDeviceAddress); I_TestAck(); I_Write8Bit(RomAddress); I_TestAck(); I_Start(); I_Write8Bit(ReadDeviceAddress); I_TestAck(); Read_data=I_Read8Bit(); I_NoAck(); I_Stop(); return (Read_data); }
8.4.1 串行EEPROM存储器简介
串行EEPROM存储器是一种采用串行总线的存储器,这类存储器具有体积小、功耗低、允许工作电压范围宽等特点。目前,单片机系统中使用较多的EEPROM芯片是24系列串行EEPROM。其具有型号多、容量大、支持I2C总线协议、占用单片机I/O端口少,芯片扩展方便、读写简单等优点。 目前,Atmel、MicroChip、National等公司均提供各种型号的I2C总线接口的串行EEPROM存储器。下面以Atmel公司的产品为例进行介绍。 AT24C01/02/04/08系列是Atmel公司典型的I2C串行总线的EEPROM。这里以AT24C08为例介绍。AT24C08具有1024×8位的存储容量,工作于从器件模式,可重复擦写100万次,数据可以掉电保存100年。8引脚DIP封装的AT24C08的封装结构,如图所示。
stc单片机eeprom读写程序
stc单片机eeprom读写程序以下是STC单片机使用EEPROM进行读写的示例程序:#include <reg52.h>#include <intrins.h>#define EEPROM_ADDR 0xA0 // EEPROM的I2C地址sbit SDA = P2^0; // I2C的数据线sbit SCL = P2^1; // I2C的时钟线// I2C开始信号void I2C_Start(){SDA = 1;_nop_(); // 延时一段时间SCL = 1;_nop_(); // 延时一段时间SDA = 0;_nop_(); // 延时一段时间SCL = 0;_nop_(); // 延时一段时间}// I2C停止信号void I2C_Stop(){SDA = 0;_nop_(); // 延时一段时间SCL = 1;_nop_(); // 延时一段时间SDA = 1;_nop_(); // 延时一段时间}// I2C发送一个字节的数据void I2C_SendByte(unsigned char dat){unsigned char i;for (i = 0; i < 8; i++){SDA = dat & 0x80; // 获取最高位dat <<= 1;_nop_(); // 延时一段时间SCL = 1;_nop_(); // 延时一段时间SCL = 0;_nop_(); // 延时一段时间}SDA = 1;_nop_(); // 延时一段时间SCL = 1;_nop_(); // 延时一段时间SCL = 0;_nop_(); // 延时一段时间}// I2C接收一个字节的数据unsigned char I2C_ReceiveByte(){unsigned char i, dat = 0;SDA = 1;for (i = 0; i < 8; i++){_nop_(); // 延时一段时间SCL = 1;_nop_(); // 延时一段时间dat <<= 1;dat |= SDA;SCL = 0;}return dat;}// 在EEPROM中写入一个字节的数据void EEPROM_WriteByte(unsigned char addr, unsigned char dat) {I2C_Start();I2C_SendByte(EEPROM_ADDR | 0); // 发送写入指令I2C_SendByte(addr); // 发送地址I2C_SendByte(dat); // 发送数据I2C_Stop();}// 从EEPROM中读取一个字节的数据unsigned char EEPROM_ReadByte(unsigned char addr){unsigned char dat;I2C_Start();I2C_SendByte(EEPROM_ADDR | 0); // 发送写入指令 I2C_SendByte(addr); // 发送地址I2C_Start();I2C_SendByte(EEPROM_ADDR | 1); // 发送读取指令 dat = I2C_ReceiveByte(); // 读取数据I2C_Stop();return dat;}。
基于51单片机的智能IC卡读写器设计
基于51单片机的智能IC卡读写器设计本IC卡读写器是以51单片机为核心展开设计。
该单片机是一种低功耗,高性能的8为CMOS型单片机,片内带有可读存储器,片上的PEROM允许在线对程序存储器重新编程。
它具有如下主要的能特点:1、工作电压范围4.2—5V2、256*8位内部RAM3、32条可编程IO口线4、3个可工作于4重模式的16位定时计数器5、6个中断源两个中断优先级6、具有四种工作模式的全双工串行口,可编程串行中断7、低功耗的待机工作模式和掉电工作模式。
IC卡座引脚在8个引脚中,VCC的工作电压为2.5到5V低电压供电。
SCL与SDA是IC卡上与逻辑控制有关的引出端线。
其中,SCL为串行时钟,所有的地址数据及读写控制命令等信号均从SDA端输入输出。
引脚T.P为微动开关的两个触点,此开关在无IC卡状态,处于断开状态,有卡插入时,IC卡插座上得微动开关闭合。
因此,此开关往往是用来判断是否插入IC卡的传感器件。
IC卡座引脚分布(1)单片机的信号通过小功率三极管9012控制系统的5V电源切入IC卡座,如果IC卡上电,则发光二极管被点亮,起读写指示作用。
每次对IC卡读写完成后,便及时下电,以减少插拔时带电的可能性。
(2)为了保证任意拔插IC卡时,IC卡处于断电状态,本读写器将IC卡的拔卡处理设计成由最高级中断程序来实现,且采用边沿触发方式。
同时,利用IC卡座的IC卡微动检测开关及时检测拔卡动作。
为了避免机械触点开关在动合过程中抖动而引起中断重入,甚至引起系统死机。
IC卡工作的基本原理是:射频读写器向IC卡发一组固定频率的电磁波,卡片内有一个LC串联谐振电路,其频率与读写器发射的频率相同,这样在电磁波激励下,LC谐振电路产生共振,从而使电容内有了电荷;在这个电荷的另一端,接有一个单向导通的电子泵,将电容内的电荷送到另一个电容内存储,当所积累的电荷达到2V时,此电容可作为电源为其它电路提供工作电压,将卡内数据发射出去或接受读写器的数据。
51内部eeprom读写,实现掉电存储
主函数:#include<reg52.h>#include"EEPROM.h"#include"smg.h"void main(){num=byte_read(DEBUG_Data_Memory_Begin_Sector_addr);//字节读(程序开始时读取EEPROM中数据)if(num>=60)num=0;//防止首次上电时读取出错??while(1){if(num<60){display(num);num++;delay(5);delay1(DELAY_CONST);sector_erase(DEBUG_Data_Memory_Begin_Sector_addr);//擦出扇区byte_program (DEBUG_Data_Memory_Begin_Sector_addr,num);//字节编程}if(num==60)num=0;}}EEPROM.h:/*STC89C51RC,STC89LE51RC 0x2000 共八个扇区STC89C52RC,STC89LE52RC 0x2000 共八个扇区STC89C54RD+,STC89LE54RD+ 0x8000 共五十八个扇区STC89C55RD+,STC89LE55RD+ 0x8000 共五十八个扇区STC89C58RD+,STC89LE58RD+ 0x8000 共五十八个扇区*/#include<reg52.h>#include<intrins.h>//sfr定义特殊功能寄存器sfr ISP_DATA =0xe2;//ISP/IAP 操作时的数据寄存器,从Flash 读出的数据放在此处,向Flash 写的数据也需放在此处sfr ISP_ADDRH =0xe3;//ISP/IAP 操作时的地址寄存器高八位sfr ISP_ADDRL =0xe4;//ISP/IAP 操作时的地址寄存器低八位sfr ISP_CMD =0xe5;//ISP/IAP 操作时的命令模式寄存器,须命令触发寄存器触发方可生效sfr ISP_TRIG =0xe6;//ISP/IAP 操作时的命令触发寄存器sfr ISP_CONTR =0xe7;//ISP/IAP 控制寄存器/* 定义命令*/#define uchar unsigned char /*8bit无符号整型*/#define uint unsigned int /*16bit无符号整型*/#define READ_AP_and_Data_Memory_Command 0x01 /*字节读数据存储区*/#define PROGRAM_AP_and_Data_Memory_Command 0x02 /*字节编程数据存储区*/#define SECTOR_ERASE_AP_and_Data_Memory_Command 0x03 /*扇区擦除数据存储*/#define DEBUG_Data_Memory_Begin_Sector_addr 0x2000//扇区地址#define DELAY_CONST 60000//延时#define WAIT_TIME 0x01uchar num;/* 打开ISP,IAP 功能*/void ISP_IAP_enable(void){EA=0;/* 关中断*/ISP_CONTR=ISP_CONTR & 0x18; /* 0001,1000 */ISP_CONTR=ISP_CONTR|WAIT_TIME;ISP_CONTR=ISP_CONTR|0x80; /* 1000,0000 */}/* 关闭ISP,IAP 功能*/void ISP_IAP_disable(void){ISP_CONTR=ISP_CONTR&0x7f;/* 0111,1111 */ISP_TRIG=0x00;EA=1;/* 开中断*/}/* 字节读*/uchar byte_read(uint byte_addr){ISP_ADDRH = (uchar)(byte_addr >> 8);ISP_ADDRL = (uchar)(byte_addr & 0x00ff);ISP_CMD = ISP_CMD&0xf8;/* 1111,1000 */ISP_CMD = ISP_CMD|READ_AP_and_Data_Memory_Command;/* 0000,0001 */ISP_IAP_enable();ISP_TRIG = 0x46;ISP_TRIG = 0xb9;_nop_();ISP_IAP_disable();return (ISP_DATA);}/* 扇区擦除*/void sector_erase(uint sector_addr){uint get_sector_addr=0;get_sector_addr=(sector_addr & 0xfe00); /* 1111,1110,0000,0000; 取扇区地址*/ ISP_ADDRH = (uchar)(get_sector_addr >> 8);ISP_ADDRL = 0x00;ISP_CMD = ISP_CMD&0xf8;/* 1111,1000 */ISP_CMD =ISP_CMD|SECTOR_ERASE_AP_and_Data_Memory_Command;/* 0000,0011 */ ISP_IAP_enable();ISP_TRIG = 0x46;/* 触发ISP_IAP命令*/ISP_TRIG = 0xb9;/* 触发ISP_IAP命令*/_nop_();ISP_IAP_disable();}/* 字节编程*/void byte_program(uint byte_addr, uchar original_data){ISP_ADDRH = (uchar)(byte_addr >> 8);ISP_ADDRL = (uchar)(byte_addr & 0x00ff);ISP_CMD = ISP_CMD & 0xf8; /* 1111,1000 */ISP_CMD = ISP_CMD |PROGRAM_AP_and_Data_Memory_Command; /* 0000,0010 */ISP_DATA = original_data;ISP_IAP_enable();ISP_TRIG = 0x46; /* 触发ISP_IAP命令*/ISP_TRIG = 0xb9; /* 触发ISP_IAP命令*/_nop_();ISP_IAP_disable();}void delay1(uint counter){uint temp=0;for(temp=counter;temp>0;temp--){_nop_();_nop_();_nop_();}}Smg.h:/****************************************************************************** ***** 标题: 试验数码管上显示数字( 单片机直接实现位选共阴极) ** 用573锁存器控制和单片机脚直接位选控制(非译码器控制)数码管******************************************************************************** ****/#include <reg52.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned intuchar code smg_duan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40}; //段码0-9.uchar code smg_wei[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdF,0xbF,0x7F}; //位选控制查表的方法控制void delay(uint i){uchar j;for(i;i>0;i--)for(j=200;j>0;j--);}void display(uint dat)//数码管显示函数{uint i;uint LedOut[10];LedOut[0]=smg_duan[dat%10000/1000];//(若要显示小数点,则|0x80)LedOut[1]=smg_duan[dat%1000/100];LedOut[2]=smg_duan[dat%100/10];LedOut[3]=smg_duan[dat%10];for( i=0; i<4; i++){P0=LedOut[i];P2=smg_wei[i];//使用查表法进行位选delay(10);//扫描间隔时间,数码管每位显示的时间,太长会数码管会有闪烁感}}。
51单片机读写内部EEPROM详解
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
/****************特殊功能寄存器声明****************/
_nop_();
Q0();//关闭ISP/IAP
/*
函数:写一字节
入口:addr=扇区单元地址, dat=待写入数据
此文档共包含三个程序。
第一个程序最简单易懂,看懂了基本就会读写51单片机内部EEPROMT。
第二个程序和第一个读写EEP ROM原理差不多,包含有LCD1602操作方 法,有写字符串的方法。
第三个程序在原有基础上增加了外部中断功能,细心的人会发现,操作内
部EEPROM过程会将总中断关闭,实际上程序要用到中断时只需在原有的EEP ROM操作后加上开总中断即可。
uchar V;
V =dcx(0x2002);//开机读取EEPROM区2002h数据,还原关电前LED的亮灭 状况
if(V==2){LED1=0;LED2=1;}
else if(V==6){LED1=0;LED2=0;}
while(1)
if(!K1)
while(!K1);
LED1=0;LED2=1;
sfr ISP_CMD=0xe5;
sfr ISP_TRIG=0xe6;
sfr ISP_CONTR=0xe7;
sbit LED1 = P2八0;
sbit LED2 = P 2八1;
sbit K1= P 3八2;//按钮1
STC单片机EEPROM读写程序
STC单片机EEPROM读写程序在单片机中,EEPROM(Electrically Erasable Programmable Read-Only Memory)是一种非易失性存储器,可以用于存储数据,即使在断电情况下,数据也会被保留。
因此,掌握STC单片机的EEPROM读写程序对于开发嵌入式系统非常重要。
一、EEPROM简介EEPROM是一种可重复擦写的存储器,可用于存储小量数据。
与Flash存储器相比,EEPROM具有更快的写入和擦除速度。
在STC单片机中,EEPROM的存储容量通常较小,一般在几个字节到几千字节之间。
二、EEPROM读操作在STC单片机中,进行EEPROM读操作需要按照以下步骤进行:1. 初始化I2C总线:STC单片机使用I2C总线进行EEPROM读写操作,因此需要先初始化I2C总线。
通过设置相关寄存器,设置I2C 总线的速度和地址。
2. 发送设备地址:确定要读取的EEPROM设备的地址,并发送到I2C总线。
3. 发送寄存器地址:确定要读取的EEPROM寄存器地址,并将其发送到I2C总线。
4. 发送读命令:向EEPROM发送读命令,以启动读操作。
5. 读取数据:从EEPROM中读取数据,并保存到变量中。
6. 结束读操作:完成读操作后,关闭I2C总线。
三、EEPROM写操作类似于读操作,进行EEPROM写操作也需要按照一定的步骤进行:1. 初始化I2C总线:同样地,首先需要初始化I2C总线。
2. 发送设备地址:确定要写入的EEPROM设备的地址,并发送到I2C总线。
3. 发送寄存器地址:确定要写入的EEPROM寄存器地址,并将其发送到I2C总线。
4. 发送写命令:向EEPROM发送写命令,以启动写操作。
5. 写入数据:将要写入EEPROM的数据发送到I2C总线。
6. 结束写操作:完成写操作后,关闭I2C总线。
四、注意事项在进行EEPROM读写操作时,需要注意以下几点:1. 确保正确的设备地址:要与EEPROM的地址匹配,否则无法进行有效的读写操作。
51单片机20个实验,代码详细
第一章单片机系统板说明一、概述单片机实验开发系统是一种多功能、高配置、高品质的MCS-51单片机教学与开发设备。
适用于大学本科单片机教学、课程设计和毕业设计以及电子设计比赛。
该系统采用模块化设计思想,减小了系统面积,同时增加了可靠性,使得单片机实验开发系统能满足从简单的数字电路实验到复杂的数字系统设计实验,并能一直延伸到综合电子设计等创新性实验项目。
该系统采用集成稳压电源供电,使电源系统的稳定性大大提高,同时又具备完备的保护措施。
为适应市场上多种单片机器件的应用,该系统采用“单片机板+外围扩展板”结构,通过更换不同外围扩展板,可实验不同的单片机功能,适应了各院校不同的教学需求。
二、单片机板简介本实验系统因为自带了MCS-51单片机系统,因此没有配置其他单片机板,但可以根据教学需要随时配置。
以单片机板为母板,并且有I/O接口引出,可以很方便的完成所有实验。
因此构成单片机实验系统。
1、主要技术参数(1)MSC-51单片机板板上配有ATMEL公司的STC89C51芯片。
STC89C51资源:32个I/O口;封装DIP40。
STC89C51开发软件:KEIL C51。
2、MSC-51单片机结构(1)单片机板中央放置一块可插拔的DIP封装的STC89C51芯片。
(2)单片机板左上侧有一个串口,用于下载程序。
(3)单片机板的四周是所有I/O引脚的插孔,旁边标有I/0引脚的脚引。
(4)单片机板与各个模块配合使用时,可形成—个完整的实验系统。
三、母板简介主要技术参数(1)实验系统电源实验系统内置了集成稳压电源,使整个电源具有短路保护、过流保护功能,提高了实验的稳定性。
主板的右上角为电源总开关,当把220V交流电源线插入主板后,打开电源开关,主板得电工作。
为适用多种需要,配置了+5V,+12V,—5V电压供主板和外设需要,通过右上角的插针排和插孔输出到外设。
此外,还设有螺旋保险插孔保护实验箱。
(2)RS232接口RS232接口通过MAX232芯片实现与计算机的串行通讯,通过接口引出信号。
STC51单片机 内部EEPROM操作
#include<reg52.h>#include<intrins.h>typedef unsigned char BYTE;typedef unsigned int WORD;//声明SFR IAP联系在一起的sfr IAP_DATA=0xE2; // flash data registersfr IAP_ADDRH=0xE3; //flash address highsfr IAP_ADDRL=0xe4; //falsh address lowsfr IAP_CMD=0Xe5; //FALSH COMMAND TRGGERsfr IAP_TRIG=0xE6; //flash command triggersfr IAP_CONTR=0xE7; //flash control register//定义ISP/IAP/EEPROM 命令#define CMD_IDIE 0 //stand-by#define CMD_READ 1 //BYTE - READ#define CMD_PROGRAM 2 // BYTE- PROGRAM#define CMD_ERASE 3 //SECTOR --ERASE//define ISP/IAP/EEPROM operation const for IAP_CONTR//#define ENABLE_IAP 0X80 //SYSCLK<40MHZ#define ENABLE_IAP 0X81 // SYSCLK<20MHZ//#define ENABLE_IAP 0x82 //SYSCLK<10MHZ//#define ENABLE_IAP 0X83 //SYSCLK<5MHZ//Start addtess for STC89C58 eeprom#define IAP_ADDRESS 0x08000void Delay(BYTE n);void IapIdle();BYTE IapReadByte(WORD addr);void IapProgramByte(WORD addr,BYTE dat);void IapEraseSector(WORD addr);void main(){WORD i;P1=0xfe; //1111,1110 system reset okDelay(5);IapEraseSector(IAP_ADDRESS); //ERASE CURRENT SECTOR for(i=0;i<512;i++) //check whether all sector data is ff {if(IapReadByte(IAP_ADDRESS+i)!=0xff)goto Error; //if error ,break}P1=0xfc; //1111,1100 erase successfulDelay(5);for(i=0;i<256;i++) //program 512 bytes data into data flash{IapProgramByte(IAP_ADDRESS+i,(BYTE)i);}P1=0XF8; //1111,1000 program successfulDelay(5);for(i=0;i<256;i++) //verify 512 bytes data{if(IapReadByte(IAP_ADDRESS+i)!=(BYTE)i)goto Error;}P1=0xf0; //1111,0000 verify successfulwhile(1);Error:P1&=0x7f; //oxxx,xxxx IAP operation failwhile(1);}// software delay functionvoid Delay(BYTE n){WORD x;while(n--){x=0;while(++x);}}//disable ISP/IAP/EEPROM function MAKE MCU in a safe state void IapIdle(){IAP_CONTR=0; //CLOSE IAP FUNCTIONIAP_CMD=0; //CLEAR COMMAND TO STANDBYIAP_TRIG=0; //CLEAR TRIGGER REGISTERIAP_ADDRH=0X80; //DATA PTR POINT TO NON-EEPROM AREA IAP_ADDRL=0; //CLEAR IAP ADDRESS TO PREVENT MISUSE }//Read one byte from ISP/IAP/EEPROM area//Input:addr (ISP/IAP/EEPROM address//Output: flash adataBYTE IapReadByte(WORD addr){BYTE dat;IAP_CONTR=ENABLE_IAP; //OPEN IAP FUNCTION ,AND SET WAIT TIMEIAP_CMD=CMD_READ; //SET ISP/IAP/EEPROM READ COMMANDIAP_ADDRL=addr; //SET ISP/IAP/EEPROM address lowIAP_ADDRH=addr>>8; //SET ISP//IAP//EEPROM address HIGHIAP_TRIG=0X46; //SEND TRIGGER COMMAND1 OX46IAP_TRIG=0XB9; //SEND TRIGGER COMMAND2 0XB9_nop_();dat=IAP_DATA; //read ISP/IAP/EEPROM dataIapIdle(); // close ISP/IAP/EEPROM FUNCITONreturn dat; //RETURN FLAH DATA}//Program one byte to ISP/IAP/EEPROM area//INPUT :addr (ISP/IAP/EEPROM address)//dat(ISP/IAP/EEPROM data)//Output:-void IapProgramByte(WORD addr, BYTE dat){IAP_CONTR=ENABLE_IAP; //OPEN IAP FUNTION AND SET WAIT TIMEIAP_CMD=CMD_PROGRAM; //SET ISP/IAP/EEPROM PROGRAM COMMAND IAP_ADDRL=addr; //set ISP/IAP/EEPROM ADDRESS LOWIAP_ADDRH=addr>>8; //set ISP/IAP/EEPROM address highIAP_DATA=dat; // WRITE ISP/IAP/EEPROM dataIAP_TRIG=0X46;IAP_TRIG=0XB9;_nop_();IapIdle();}void IapEraseSector(WORD addr){IAP_CONTR=ENABLE_IAP;IAP_CMD=CMD_ERASE;IAP_ADDRL=addr;IAP_ADDRH=addr>>8;IAP_TRIG=0X46;IAP_TRIG=0XB9;_nop_();IapIdle();}。
单片机课程设计-IIC总线式EEPROM存储器应用设计
目录1 设计要求 (2)2 设计目的 (2)3 器件EEPROM的介绍 (2)3.1 EEPROM简介 (2)3.2 EEPROM24XX系列功能概述 (3)4 IIC协议的介绍 (3)4.1 IIC协议总线特征 (3)4.2 IIC协议工作原理 (3)4.3 IIC协议总线基本状态 (3)4.4 寻址约定 (5)5 EEPROM读写功能实现 (5)5.1写操作 (5)5.1.1 字节写操作 (6)5.1.2 页写入操作 (6)5.2 确认查询 (7)5.3 读操作 (7)5.3.1 当前地址的读操作 (8)5.3.2 随机读操作 (8)5.3.3 连续读操作 (9)6 具体设计过程 (10)6.1 程序流程设计 (10)6.2执行结果 (13)6.3 系统组成模块结构及功能 (15)6.3.1 函数定义 (15)6.3.2 主函数设计 (17)6.3.3 源程序 (19)7 设计心得体会 (27)8 参考文献 (28)IIC总线式EEPROM存储器应用设计1 设计要求利用51单片机和IIC总线式EEPROM芯片24C02进行存储器设计。
按下KEYWRITE1键,向24C02存储器写入数据1和2;按下KEYWRITE2键,向24C02存储器写入数据3和4;按下KEYREAD键,从24C02存储器读出刚写入的数据数据;写入数据显示在左两位,读出数据显示在右两位。
如图1.1所示。
图1.1 系统仿真运行图2 设计目的通过设计,了解IIC协议的基本原理,并对EEPROM读写功能的实现有个系统的概念,对其实现过程比较清楚。
同时,在设计中,巩固我们所学的理论知识。
3 器件EEPROM的介绍3.1 EEPROM简介EEPROM (Electrically Erasable Programmable Read-Only Memory),电可擦可编程只读存储器--一种掉电后数据不丢失的存储芯片。
EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。
51单片机读写内部EEPROM详解
#define uchar unsigned char
#define uint unsigned int
特殊功能寄存器声明****************
sfr ISP_DATA=0xe2;
sfr ISP_ADDRH=0xe3;
sfr ISP_ADDRL=0xe4;
uchar dat;
ISP_CONTR=0x81;
ISP_CMD= 0x01;/用户可以对"Data Flash/EEPROM区"进行字节读ISP_ADDRL = addr;
ISP_ADDRH=addr>>8;
EA= 0;
ISP_TRIG=0x46;
ISP_TRIG=0xB9;
_nop_();
dat=ISP_DATA;
uchar dcx(uint addr);
voidQ0();
/*
*/
/*
void main(void)
uchar V;
V = dcx(0x2002);//开机读取EEPROM区2002h数据,还原关电前LED的亮灭 状况
if(V==2){LED1=0;LED2=1;}
else if(V==6){LED1=0;LED2=0;}
验证第二、第三个程序时需按程序内主程序中的操作说明进行烧录单片
机,以验证是否成功操作单片机内部EEPROM。
程序1:
/***************************************************************
作品:EEP ROM实验,开机还原关电前LED的亮灭状况
ISP_ADDRH=addr>>8;
单片机EEPROM读写数据流程解析
单片机EEPROM读写数据流程解析EEPROM 写数据流程第一步,首先是I2C 的起始信号,接着跟上首字节,也就是我们前边讲的I2C 的器件地址,并且在读写方向上选择“写”操作。
第二步,发送数据的存储地址。
24C02 一共256 个字节的存储空间,地址从0x00~0xFF,我们想把数据存储在哪个位置,此刻写的就是哪个地址。
第三步,发送要存储的数据第一个字节、第二个字节??注意在写数据的过程中,EEPROM 每个字节都会回应一个“应答位0”,来告诉我们写EEPROM 数据成功,如果没有回应答位,说明写入不成功。
在写数据的过程中,每成功写入一个字节,EEPROM 存储空间的地址就会自动加1,当加到0xFF 后,再写一个字节,地址会溢出又变成了0x00。
EEPROM 读数据流程第一步,首先是I2C 的起始信号,接着跟上首字节,也就是我们前边讲的I2C 的器件地址,并且在读写方向上选择“写”操作。
这个地方可能有同学会诧异,我们明明是读数据为何方向也要选“写”呢?刚才说过了,24C02 一共有256 个地址,我们选择写操作,是为了把所要读的数据的存储地址先写进去,告诉EEPROM 我们要读取哪个地址的数据。
这就如同我们打电话,先拨总机号码(EEPROM 器件地址),而后还要继续拨分机号码(数据地址),而拨分机号码这个动作,主机仍然是发送方,方向依然是“写”。
第二步,发送要读取的数据的地址,注意是地址而非存在EEPROM 中的数据,通知EEPROM 我要哪个分机的信息。
第三步,重新发送I2C 起始信号和器件地址,并且在方向位选择“读”操作。
这三步当中,每一个字节实际上都是在“写”,所以每一个字节EEPROM 都会回应一个“应答位0”。
第四步,读取从器件发回的数据,读一个字节,如果还想继续读下一个字节,就发送一个“应答位ACK(0)”,如果不想读了,告诉EEPROM,我不想要数据了,别再发数据了,那就发送一个“非应答位NAK(1)”。
51单片机IO口应用详解
51单片机IO口应用详解MCS-51是标准的40引脚双列直插式集成电路芯片,引脚分布请参照单片机引脚图:这4个I/O口具有不完全相同的功能,大家可得学好了,其它书本里虽然有,但写的太深,对于初学者来说很难理解的,我这里都是按我自已的表达方式来写的,相信你也能够理解的。
P0口有三个功能:1、外部扩展存储器时,当做数据总线(如图1中的D0~D7为数据总线接口)2、外部扩展存储器时,当作地址总线(如图1中的A0~A7为地址总线接口)3、不扩展时,可做一般的I/O使用,但内部无上拉电阻,作为输入或输出时应在外部接上拉电阻。
P1口只做I/O口使用:其内部有上拉电阻。
P2口有两个功能:1、扩展外部存储器时,当作地址总线使用2、做一般I/O口使用,其内部有上拉电阻;P3口有两个功能:除了作为I/O使用外(其内部有上拉电阻),还有一些特殊功能,由特殊寄存器来设置,具体功能请参考我们后面的引脚说明。
有内部EPROM的单片机芯片(例如8751),为写入程序需提供专门的编程脉冲和编程电源,这些信号也是由信号引脚的形式提供的,即:编程脉冲:30脚(ALE/PROG)编程电压(25V):31脚(EA/Vpp)在介绍这四个I/O口时提到了一个“上拉电阻”那么上拉电阻又是一个什么东东呢?他起什么作用呢?都说了是电阻那当然就是一个电阻啦,当作为输入时,上拉电阻将其电位拉高,若输入为低电平则可提供电流源;所以如果P0口如果作为输入时,处在高阻抗状态,只有外接一个上拉电阻才能有效。
ALE 地址锁存控制信号:在系统扩展时,ALE用于控制把P0口的输出低8位地址送锁存器锁存起来,以实现低位地址和数据的隔离。
参见图2(8051扩展2KB EEPROM电路,在图中ALE与4LS373锁存器的G相连接,当CPU对外部进行存取时,用以锁住地址的低位地址,即P0口输出。
由于ALE是以晶振六分之一的固定频率输出的正脉冲,当系统中未使用外部存储器时,ALE脚也会有六分之一的固定频率输出,因此可作为外部时钟或外部定时脉冲使用。
at98s51单片机存储器的结构特点和使用注意事项
at98s51单片机存储器的结构特点和使用注意事项1.引言a t98s51单片机是一种常用的存储设备,它具有独特的结构特点和使用注意事项。
本文将介绍at98s51单片机存储器的结构特点和使用注意事项,以帮助用户更好地理解和使用该设备。
2. at98s51单片机存储器结构特点a t98s51单片机的存储器结构具有以下特点:2.1存储单元a t98s51单片机的存储器由多个存储单元组成,每个存储单元能够存储一定的信息。
这些存储单元以字节为单位进行编址,可以通过地址来访问。
2.2存储器单元类型a t98s51单片机的存储器包含多种类型的存储单元,主要包括:-R AM(R an do mA cc es s Me mo ry)随机存储器:用于存储程序运行时的临时数据,具有读写功能,但断电后数据将消失。
-R OM(R ea d-On ly Me m or y)只读存储器:用于存储程序的指令和常量数据,具有只读功能,断电后数据不会丢失。
-E EP RO M(El ec tr ic a ll yE ra sa bl eP rog r am ma bl eR ea d-O n ly Me mo ry)可擦写可编程只读存储器:可重复擦写的存储器,用于存储一些需要频繁更新或修改的数据。
2.3存储器的地址范围a t98s51单片机的存储器地址范围取决于其数据总线的位数,以及具体型号的不同。
常见的a t98s51单片机的存储器地址范围为0x00至0x FF。
3. at98s51单片机存储器的使用注意事项在使用a t98s51单片机存储器时,需要注意以下事项:3.1内存管理合理地利用a t98s51单片机的存储器是提高效率的重要因素。
用户应根据具体的应用需求,合理分配存储器空间,避免出现存储器空间不足或浪费的情况。
3.2存储器读写顺序在a t98s51单片机中,读写数据的顺序对程序的正确性和性能有着重要影响。
在设计程序时,要根据具体情况选择合适的存储器读写顺序,尽量减少存储器操作次数,提高程序的执行效率。
eeprom使用方法
eeprom使用方法EEPROM(电可擦可编程只读存储器)使用起来还挺有趣的呢!EEPROM就像是一个小仓库,用来存放数据。
它的好处是数据不会因为断电就消失哦。
那怎么往这个小仓库里放东西呢?这得看你用的是什么设备或者开发板啦。
一般来说,你得先在你的编程环境里找到对应的库或者函数。
比如说,在Arduino里使用EEPROM就超级简单。
你只要包含EEPROM库,然后就可以像给小盒子贴标签放东西一样,用函数来指定地址,再把你想要存的数据放进去。
就好像你把小宝贝放进一个个小格子里,每个格子都有自己的编号,这个编号就是地址啦。
从EEPROM里取数据也不难。
还是按照那个地址,用对应的函数把数据拿出来就好啦。
不过要小心哦,如果你取数据的时候地址弄错了,那就可能拿到错误的东西,就像你本来想拿糖果,结果拿到了小石子一样。
在使用EEPROM的时候,还有个要注意的点就是它的寿命。
它虽然能擦写很多次,但也不是无限的。
所以不要没事就一直擦了写、写了擦,要像爱护小宠物一样爱护它呢。
如果你是在做一些小项目,比如自制一个小的温度记录器。
你就可以把每次测量到的温度数据存到EEPROM里。
这样,就算突然断电了,之前的数据也还在,等来电了还能接着记录或者查看历史数据呢。
还有哦,不同的EEPROM芯片可能会有一些细微的差别。
有的可能存储容量大一点,有的可能读写速度快一点。
你在选择的时候,就像挑选小鞋子一样,要根据自己的“脚”(也就是项目需求)来选合适的。
要是你只是简单存几个小参数,那就不需要特别大存储容量的EEPROM啦。
总之呢,EEPROM就像是一个贴心的小助手,只要你按照它的规则来使用,就能很好地在你的小发明、小制作里发挥大作用啦。
STC51单片机EEPROM的使用方法
STC51单片机EEPROM的使用方法STC51单片机有类似flash的功能EEPROM,可以掉电保存数据,不同型号的可以保存不同大小的数据,以12C5A60S2为例,EEPROM的大小为2K,分为两个扇区,掉电保存在很多地方需要。
首先寄存器的问题,不同系列的STC单片机的与EEPROM有关的寄存器不同,比如10/11/12系列的sfr ISP_DATA = 0xC2;sfr ISP_ADDRH = 0xC3;sfr ISP_ADDRL = 0xC4;sfr ISP_CMD = 0xC5;sfr ISP_TRIG = 0xC6;sfr ISP_CONTR = 0xC7;89/90系列的sfr ISP_DATA = 0xe2;sfr ISP_ADDRH = 0xe3;sfr ISP_ADDRL = 0xe4;sfr ISP_CMD = 0xe5;sfr ISP_TRIG = 0xe6;sfr ISP_CONTR = 0xe7;注意寄存器一定要按数据手册中的配置,ISP触发命令也不相同,详情请看下方代码其次是关于扇区问题,不同型号的MCU扇区个数不尽相同,详情请查询数据手册,在这里我以12C5A60S2为例,一共2扇区,每扇区512B,地址区间为0x0000~0x03FF,使用时请勿超出范围。
EEPROM使用时有三个功能,分别为读、写、和擦除,由ISP_CMD寄存器控制,分别对应1/2/3下面为此项内容的代码部分,分别为初始化、读、擦除和写,本程序为11.0592MHz晶振,STC12C5A60S2的MCU,以下程序测试可用EEPROM.cvoid DisableEEPROM(void){ISP_CONTR = 0;//禁止ISP/IAP操作ISP_CMD = 0;//去除ISP/IAP命令ISP_TRIG = 0;//防止ISP/IAP命令误触发ISP_ADDRH = 0xff;//指向非EEPROM区,防止误操作ISP_ADDRL = 0xff;//指向非EEPROM区,防止误操作。
stc单片机eeprom读写程序
/* STC89C54RD+的flash空间从0x4000~0xf3ff 共90个扇区,每扇区512字节*/// #define BaseAddr 0x1000 /* 51rc */// #define EndSectoraddr 0x3d00 /* 51rc */// #define EndAddr 0x3fff /* 51rc 12K eeprom */#define BaseAddr 0x4000#define EndSectoraddr 0xf200#define EndAddr 0xf3ff#define UseAddr 0x1000/* ------------- 定义扇区大小------------- */#define PerSector 512/* 用户程序需要记忆的数组, 用户实际使用了n-1个数据,数组长度规整到2 4 8 16 32 64 上*/uchar Ttotal[16] ={0x55, /* 作为判别引导头使用,用户程序请不要修改它*//* 用户保存记忆的数据*/0x01, /* 用途说明....*/0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,};uint timerForDelay, /* 专供延时用的变量*/i, /* 循环变量*/EepromPtr; /* eeprom读写指针*//* --------------- 命令定义--------------- */#define RdCommand 0x01 /* 字节读*/#define PrgCommand 0x02 /* 字节写*/#define EraseCommand 0x03 /* 扇区擦除*//* 定义常量*/#define Error 1#define Ok 0/* 定义Flash对应于20MHz晶振系统的操作等待时间*//* 时钟倍频时WaitTime用0x00*/#define WaitTime 0x01/* ================ 打开ISP,IAP 功能================= */ void ISP_IAP_enable(void){EA = 0; /* 关中断*/ISP_CONTR = ISP_CONTR & 0x18; /* 0001,1000 */ISP_CONTR = ISP_CONTR | WaitTime; /* 写入硬件延时*/ ISP_CONTR = ISP_CONTR | 0x80; /* ISPEN=1 */ }/* =============== 关闭ISP,IAP 功能================== */ void ISP_IAP_disable(void){ISP_CONTR = ISP_CONTR & 0x7f; /* ISPEN = 0 */ISP_TRIG = 0x00;EA = 1; /* 开中断*/}/* ================ 公用的触发代码==================== */ void ISPgoon(void){ISP_IAP_enable(); /* 打开ISP,IAP 功能*/ISP_TRIG = 0x46; /* 触发ISP_IAP命令字节1 */ ISP_TRIG = 0xb9; /* 触发ISP_IAP命令字节2 */ _nop_();}/* ==================== 字节读======================== */ uchar byte_read(uint byte_addr){ISP_ADDRH = (uchar)(byte_addr >> 8); /* 地址赋值*/ISP_ADDRL = (uchar)(byte_addr & 0x00ff);ISP_CMD = ISP_CMD & 0xf8; /* 清除低3位*/ ISP_CMD = ISP_CMD | RdCommand; /* 写入读命令*/ISPgoon(); /* 触发执行*/ISP_IAP_disable(); /* 关闭ISP,IAP功能*/return (ISP_DA TA); /* 返回读到的数据*/}/* ================== 扇区擦除======================== */ void SectorErase(uint sector_addr){uint iSectorAddr;iSectorAddr = (sector_addr & 0xfe00); /* 取扇区地址*/ISP_ADDRH = (uchar)(iSectorAddr >> 8);ISP_ADDRL = 0x00;ISP_CMD = ISP_CMD & 0xf8; /* 清空低3位*/ ISP_CMD = ISP_CMD | EraseCommand; /* 擦除命令3 */ISPgoon(); /* 触发执行*/ISP_IAP_disable(); /* 关闭ISP,IAP功能*/}/* ==================== 字节写======================== */ void byte_write(uint byte_addr, uchar original_data){ISP_ADDRH = (uchar)(byte_addr >> 8); /* 取地址*/ISP_ADDRL = (uchar)(byte_addr & 0x00ff);ISP_CMD = ISP_CMD & 0xf8; /* 清低3位*/ ISP_CMD = ISP_CMD | PrgCommand; /* 写命令2 */ISP_DA TA = original_data; /* 写入数据准备*/ISPgoon(); /* 触发执行*/ISP_IAP_disable(); /* 关闭IAP功能*/}/* =================== 字节写并校验=================== */ uchar byte_write_verify(uint byte_addr, uchar original_data){ISP_ADDRH = (uchar)(byte_addr >> 8); /* 取地址*/ISP_ADDRL = (uchar)(byte_addr & 0xff);ISP_CMD = ISP_CMD & 0xf8; /* 清低3位*/ISP_CMD = ISP_CMD | PrgCommand; /* 写命令2 */ISP_DA TA = original_data;ISPgoon(); /* 触发执行*//* 开始读,没有在此重复给地址,地址不会被自动改变*/ISP_DA TA = 0x00; /* 清数据传递寄存器*/ISP_CMD = ISP_CMD & 0xf8; /* 清低3位*/ISP_CMD = ISP_CMD | RdCommand; /* 读命令1 */ISP_TRIG = 0x46; /* 触发ISP_IAP命令字节1 */ ISP_TRIG = 0xb9; /* 触发ISP_IAP命令字节2 */_nop_(); /* 延时*/ISP_IAP_disable(); /* 关闭IAP功能*/if(ISP_DA TA == original_data){ /* 读写数据校验*/return Ok; /* 返回校验结果*/ }else{return Error;}}/* ===================== 数组写入===================== */ uchar ArrayWrite(uint begin_addr, uint len, uchar *array){uint i;uint in_addr;/* 判是否是有效范围,此函数不允许跨扇区操作*/if(len > PerSector){return Error;}in_addr = begin_addr & 0x01ff; /* 扇区内偏移量*/if((in_addr + len) > PerSector){return Error;}in_addr = begin_addr;/* 逐个写入并校对*/ISP_IAP_enable(); /* 打开IAP功能*/for(i = 0; i< len; i++){/* 写一个字节*/ISP_ADDRH = (uchar)(in_addr >> 8);ISP_ADDRL = (uchar)(in_addr & 0x00ff);ISP_DA TA= array[i]; /* 取数据*/ISP_CMD = ISP_CMD & 0xf8; /* 清低3位 */ISP_CMD = ISP_CMD | PrgCommand; /* 写命令2 */ISP_TRIG = 0x46; /* 触发ISP_IAP命令字节1 */ISP_TRIG = 0xb9; /* 触发ISP_IAP命令字节2 */_nop_();/* 读回来*/ISP_DA TA = 0x00;ISP_CMD = ISP_CMD & 0xf8; /* 清低3位 */ISP_CMD = ISP_CMD | RdCommand; /* 读命令1 */ISP_TRIG = 0x46; /* 触发ISP_IAP命令字节1 */ISP_TRIG = 0xb9; /* 触发ISP_IAP命令字节2 */_nop_();/* 比较对错*/if(ISP_DA TA != array[i]){ISP_IAP_disable();return Error;}in_addr++; /* 指向下一个字节*/ }ISP_IAP_disable();return Ok;}/* ========================= 扇区读出========================= */ /* 程序对地址没有作有效性判断,请调用方事先保证他在规定范围内*/void ArrayRead(uint begin_addr, uchar len){// uchar xdata data_buffer[]; /* 整个扇区读取缓存区*/ uint iSectorAddr;uint i;iSectorAddr = begin_addr; // & 0xfe00; /* 取扇区地址*/ISP_IAP_enable();for(i = 0; i < len; i++){ISP_ADDRH = (uchar)(iSectorAddr >> 8);ISP_ADDRL = (uchar)(iSectorAddr & 0x00ff);ISP_CMD = ISP_CMD & 0xf8; /* 清低3位 */ISP_CMD = ISP_CMD | RdCommand; /* 读命令1 */ISP_DA TA = 0;ISP_TRIG = 0x46; /* 触发ISP_IAP命令字节1 */ISP_TRIG = 0xb9; /* 触发ISP_IAP命令字节2 */_nop_();Ttotal[i] = ISP_DA TA;iSectorAddr++;}ISP_IAP_disable(); /* 关闭IAP功能*/}/* ==============================================================从eeprom中读取数据============================================================== */void DataRestore(){EepromPtr = BaseAddr; /* 指向eeprom的起始点*/while(EepromPtr < EndAddr) /* 在eeprom的可用区域内 */{if(byte_read(EepromPtr) == 0x55)/* 找到了上一次有效纪录*/{break; /* 寻找完成*/}EepromPtr += 0x10; /* 指向下一个小区*/ }if(EepromPtr >= EndAddr) /* 如果照遍都没有,是新片*/{EepromPtr = BaseAddr; /* 指向eeprom的起始点*/for(i=0;i<90;i++){SectorErase(EepromPtr+0x200*i); /* 全部扇区擦除*/}while(ArrayWrite(EepromPtr, 0x10, Ttotal)) /* 写默认值*/{ /* 写入失败才运行的部分*/byte_write(EepromPtr, 0); /* 该单元已经失效*/if(EepromPtr < EndAddr){EepromPtr += 0x10; /* 换一块新的小区*/}else{P1=0; /* 指示芯片内eeprom全坏 */EA= 0; /* 不再做任何事*/while(1); /* 死机*/}}}ArrayRead(EepromPtr, 16);}/* ==============================================================将需要记忆的数据保存到eeprom============================================================== */void DataSave(){uint wrPtr; /* 临时指针*/ NextArea:byte_write_verify(EepromPtr, 0); /* 将原来的标记清除*/wrPtr = EepromPtr & 0xfe00; /* 上一个扇区的起始地址*/EepromPtr += 0x10; /* 目标存入地址*//* ------------------ 判断是否启用新的扇区---------------- */if((EepromPtr & 0x1ff)==0){SectorErase(wrPtr); /* 将上一个扇区擦除,备用*/if(EepromPtr>=EndAddr) /* 已经用完了最后一个区域*/{EepromPtr = BaseAddr; /* 从头开始*/}}/* -------------------- 数据存入前的准备------------------ *//* 。
EEPROM读写访问
EEPROM写使能。当EEPROM的 地址和数据准备好后,用户必须 设置EEWE为“1”,才能将数据 写入EEPROM中。在置EEWE为 “1”前,EEMWE必须置“1”, 否则写入操作无效。
位 位名 读/写 初始值 7 6 5
EEPROM读使能。此位用于对 EEPROM的数据读取,当EEAR中 设置了EEPROM的读取地址后, EERE的置“1”操作将使单元的数 据送至EEDR寄存器中,此时EERE 位自动清“0”。
1
1
(1)休眠状态 为进入休眠状态,MCUCR中的SE位被设为1,且须执 行一条SLEEP指令。系统发生的任何一种中断和复位将使 MCU恢复到正常模式。
(2)空闲模式 SM位必须清零,SLEEP指令使MCU进入空闲状态, 当系统发生外部中断、定时器/计数器溢出中断和看门狗复 位单片机时返回正常模式。 (3)掉电模式 此模式下,只有复位和外部中断可以使单片机恢复正 常模式。 (4)节电方式库函数 void sleep_enable(void) //允许低功耗模式 void sleep_disable(void) //禁止低功耗模式 void idle(void) //闲置模式 void powerdown(void) //掉电模式 void powersave(void) //休眠模式 在调用这些库函数之前必须将头文件#include <sleep.h> 加入到源程序文件中。
STM32L051测试 (四、Flash和EEPROM的读写)
STM32L051 测试第 4 课,掉电数据保存的测试。
..修改文中以前的问题,增加后续问题说明(数据存储大小端模式)..增加后续问题2.4.3(STM32L071RBT6 EEPROM读写全字问题)..更新一下STM32L071 EEPROM读写全字问题最后解决说明•1、STM32L051内部存储模块地址范围•2、读写函数的设计▪ 2.1 读取函数▪ 2.2 EEPROM写函数▪ 2.3 Flash写函数▪ 2.4 读写EEPROM的后续问题•总结本文测试L051 flash的读写,用来处理以后应用中的掉电数据保存。
1、STM32L051内部存储模块地址范围开始找到F103的FLASH图复习了一遍,然后L051C8T6,64KB的flash,然后我惊奇的发现还有2KB的EEPROM。
发现L051系列的地址与F103完全不同,F103的flash每页的长度有1KB(小容量<=64KB)和2KB(大容量128KB起)查看各种资料,查了2个小时,还是不知道L051的flash 每页长度是128Byte 还是256Byte还是请教了一下大佬,发现直接在J-Flash中可以找到答案,先上个F103的图:然后来看个L051的图:图中64KB 的flash 和2KB的EEPROM都能都明显的看出地址,flash 512页,每页128bytes,EEPROM只有4页,每页512bytes.知道了基本的地址,就可以操作起来了。
最后还需要确定的一点事,最小擦除单元是128bytes,还是256bytes,按以前的认知,删除是按照一个Sector擦除的,也就是128bytes,但是我查看了一些网上的例子和资料,有的是说256bytes,所以后面需要自己确定一下其实在HAL库的stm32l0xx_hal_flash.h 文件中有过FLASH_PAGE_SIZE 的定义,就是128bytes :#define FLASH_SIZE (uint32_t)((*((uint32_t *)FLASHSIZE_BASE)&0xFFFF) * 1024U)#define FLASH_PAGE_SIZE ((uint32_t)128U) /*!< FLASH Page Size in bytes * /对于flash的操作,有一些基础知识补充一下:Read interface organized by word, half-word or byte in every area • Programming in the Flash memory performed by word or half-page • Programming in the Option bytes area performed by word • Programmi ng in the data EEPROM performed by word, half-word or byte • Erase operation performed by page (in Flash memory, data EEPROM and Option bytes)STM32L051写Flash必须字,读字节、半字、字都支持。