当前位置:文档之家› 51单片机读写内部EEPROM详解

51单片机读写内部EEPROM详解

51单片机读写内部EEPROM详解
51单片机读写内部EEPROM详解

此文档共包含三个程序。

第一个程序最简单易懂,看懂了基本就会读写51单片机内部EEPROM了。

第二个程序和第一个读写EEPROM原理差不多,包含有LCD1602操作方法,有写字符串的方法。

第三个程序在原有基础上增加了外部中断功能,细心的人会发现,操作内部EEPROM过程会将总中断关闭,实际上程序要用到中断时只需在原有的EEPROM操作后加上开总中断即可。

验证第二、第三个程序时需按程序内主程序中的操作说明进行烧录单片机,以验证是否成功操作单片机内部EEPROM。

程序1:

/*************************************************************** 作品:EEPROM实验,开机还原关电前LED的亮灭状况

单片机:STC89C52RC

晶振:12M

编译环境:Keil uVision4 V9.00

***************************************************************/

//#include

#include

#include

#define uchar unsigned char

#define uint unsigned int

/****************特殊功能寄存器声明****************/

sfr ISP_DATA = 0xe2;

sfr ISP_ADDRH = 0xe3;

sfr ISP_ADDRL = 0xe4;

sfr ISP_CMD = 0xe5;

sfr ISP_TRIG = 0xe6;

sfr ISP_CONTR = 0xe7;

sbit LED1 = P2^0;

sbit LED2 = P2^1;

sbit K1 = P3^2; //按钮1

sbit K2 = P3^3; //按钮2

void cc(uint addr);

void xcx(uint addr,uchar dat);

uchar dcx(uint addr);

void Q0();

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:主程序

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

/*

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;}

while(1)

{

if(!K1)

{

while(!K1);

LED1=0;LED2=1;

cc(0x2000); // 擦除第1个扇区(2000h~21FFh)

xcx(0x2002,2); // 对EEPROM区2002h写入2

}

if(!K2)

{

while(!K2);

LED1=0;LED2=0;

cc(0x2000); // 擦除第1个扇区(2000h~21FFh)

xcx(0x2002,6); // 对EEPROM区2002h写入6

}

}

}

*/

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:擦除某一扇区(每个扇区512字节)

入口:addr = 某一扇区首地址

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

void cc(uint addr)

{

// 打开IAP 功能(ISP_CONTR.7)=1:允许编程改变Flash, 设置Flash操作等待时间

// 0x83(晶振<5M) 0x82(晶振<10M) 0x81(晶振<20M) 0x80(晶振<40M) ISP_CONTR = 0x81;

ISP_CMD = 0x03; // 用户可以对"Data Flash/EEPROM区"进行扇区擦除ISP_ADDRL = addr; // ISP/IAP操作时的地址寄存器低八位,

ISP_ADDRH = addr>>8; // ISP/IAP操作时的地址寄存器高八位。

EA =0;

ISP_TRIG = 0x46; // 在ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG先写入46h,ISP_TRIG = 0xB9; // 再写入B9h,ISP/IAP命令才会生效。

_nop_();

Q0(); // 关闭ISP/IAP

}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:写一字节

入口:addr = 扇区单元地址, dat = 待写入数据

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

void xcx(uint addr,uchar dat)

{

ISP_CONTR = 0x81;

ISP_CMD = 0x02; // 用户可以对"Data Flash/EEPROM区"进行字节编程ISP_ADDRL = addr;

ISP_ADDRH = addr>>8;

ISP_DATA = dat; // 数据进ISP_DATA

EA = 0;

ISP_TRIG = 0x46;

ISP_TRIG = 0xB9;

_nop_();

Q0(); // 关闭ISP/IAP

}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:读一字节

入口:addr = 扇区单元地址

出口:dat = 读出的数据

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

uchar dcx(uint addr)

{

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; // 取出数据

Q0(); // 关闭ISP/IAP

return dat;

}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:关闭ISP/IAP操作

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

void Q0()

{

ISP_CONTR = 0; // 关闭IAP功能

ISP_CMD = 0; // 待机模式,无ISP操作

ISP_TRIG = 0; // 关闭IAP功能, 清与ISP有关的特殊功能寄存器

}

/*

STC89C52RC内部EEPROM详细地址表:

第一扇区第二扇区第三扇区第四扇区

起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址

2000h 21FFh 2200h 23FFh 2400h 25FFh 2600h 27FFH

第五扇区第六扇区第七扇区第八扇区

起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址

2800h 29FFh 2A00h 2BFFh 2C00h 2DFFh 2E00h 2FFFh

*/

程序2:

/*************************************************************** 作品:EEPROM实验,开机还原关电前LED的亮灭状况

单片机:STC89C52RC

晶振:12M

编译环境:Keil uVision4 V9.00

***************************************************************/ //#include

#include

#include

#define uchar unsigned char

#define uint unsigned int

/****************特殊功能寄存器声明****************/

sfr ISP_DATA = 0xe2;

sfr ISP_ADDRH = 0xe3;

sfr ISP_ADDRL = 0xe4;

sfr ISP_CMD = 0xe5;

sfr ISP_TRIG = 0xe6;

sfr ISP_CONTR = 0xe7;

sbit LED1 = P2^0;

sbit LED2 = P2^1;

sbit K1 = P3^2; //按钮1

sbit K2 = P3^3; //按钮2

void cc(uint addr);

void xcx(uint addr,uchar dat);

uchar dcx(uint addr);

void Q0();

#ifndef uchar

#define uchar unsigned char

#endif

#ifndef uint

#define uint unsigned int

#endif

/**********************************

PIN口定义

**********************************/

#define LCD1602_DATAPINS P0

sbit LCD1602_E=P2^7;

sbit LCD1602_RW=P2^5;

sbit LCD1602_RS=P2^6;

/**********************************

函数声明

**********************************/

/*在51单片机12MHZ时钟下的延时函数*/

void Lcd1602_Delay1ms(uint c); //误差0us

/*LCD1602写入8位命令子函数*/

void LcdWriteCom(uchar com);

/*LCD1602写入8位数据子函数*/

void LcdWriteData(uchar dat) ;

/*LCD1602初始化子程序*/

void LcdInit();

/*LCD1602写入字符串*/

void LCDWrite_String(uchar x, uchar y,uchar z, uchar *s);

/*设置LCD1602写入字符串的位置*/

void LCD_set_xy(uchar x, uchar y, uchar z);

uchar ON_Hour=0x07; //初始开灯时间07:00 1

uchar Warning_TempH=32; //高温报警温度

5

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:主程序

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

/*

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;}

while(1)

{

if(!K1)

{

while(!K1);

LED1=0;LED2=1;

cc(0x2000); // 擦除第1个扇区(2000h~21FFh)

xcx(0x2002,2); // 对EEPROM区2002h写入2

}

if(!K2)

{

while(!K2);

LED1=0;LED2=0;

cc(0x2000); // 擦除第1个扇区(2000h~21FFh)

xcx(0x2002,6); // 对EEPROM区2002h写入6

}

}

}

*/

void main(void)

{

LcdInit();

//不注销下面三句,烧录一次

//注销小面三句,再烧录一次

//若两次烧录后现象一致,则操作内部EEPROM成功

/////////////////////////////////////////////////////////////////

cc(0x2000); // 擦除第1个扇区(2000h~21FFh)

xcx(0x2000,ON_Hour); // 对EEPROM区2002h写入2

xcx(0x2001,Warning_TempH); // 对EEPROM区2002h写入2

/////////////////////////////////////////////////////////////////

ON_Hour = dcx(0x2000);

Warning_TempH = dcx(0x2001);

if((ON_Hour==0x07)||(Warning_TempH==32))

{

LcdWriteCom(0x80);

LCDWrite_String(0, 1, 7, "SUCCESS");

}

else

LCDWrite_String(0, 1, 5, "ERROR");

while(1);

}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:擦除某一扇区(每个扇区512字节)

入口:addr = 某一扇区首地址

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

void cc(uint addr)

{

// 打开IAP 功能(ISP_CONTR.7)=1:允许编程改变Flash, 设置Flash操作等待时间

// 0x83(晶振<5M) 0x82(晶振<10M) 0x81(晶振<20M) 0x80(晶振<40M) ISP_CONTR = 0x81;

ISP_CMD = 0x03; // 用户可以对"Data Flash/EEPROM区"进行扇区擦除ISP_ADDRL = addr; // ISP/IAP操作时的地址寄存器低八位,

ISP_ADDRH = addr>>8; // ISP/IAP操作时的地址寄存器高八位。

EA =0;

ISP_TRIG = 0x46; // 在ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG先写入46h,ISP_TRIG = 0xB9; // 再写入B9h,ISP/IAP命令才会生效。

_nop_();

Q0(); // 关闭ISP/IAP

}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:写一字节

入口:addr = 扇区单元地址, dat = 待写入数据

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

void xcx(uint addr,uchar dat)

{

ISP_CONTR = 0x81;

ISP_CMD = 0x02; // 用户可以对"Data Flash/EEPROM区"进行字节编程ISP_ADDRL = addr;

ISP_ADDRH = addr>>8;

ISP_DATA = dat; // 数据进ISP_DATA

EA = 0;

ISP_TRIG = 0x46;

ISP_TRIG = 0xB9;

_nop_();

Q0(); // 关闭ISP/IAP

}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:读一字节

入口:addr = 扇区单元地址

出口:dat = 读出的数据

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

uchar dcx(uint addr)

{

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; // 取出数据

Q0(); // 关闭ISP/IAP

return dat;

}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:关闭ISP/IAP操作

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

void Q0()

{

ISP_CONTR = 0; // 关闭IAP功能

ISP_CMD = 0; // 待机模式,无ISP操作

ISP_TRIG = 0; // 关闭IAP功能, 清与ISP有关的特殊功能寄存器

}

/*

STC89C52RC内部EEPROM详细地址表:

第一扇区第二扇区第三扇区第四扇区

起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址

2000h 21FFh 2200h 23FFh 2400h 25FFh 2600h 27FFH

第五扇区第六扇区第七扇区第八扇区

起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址

2800h 29FFh 2A00h 2BFFh 2C00h 2DFFh 2E00h 2FFFh

*/

/****************************************************************************** *

* 函数名: Lcd1602_Delay1ms

* 函数功能: 延时函数,延时1ms

* 输入: c

* 输出: 无

* 说名: 该函数是在12MHZ晶振下,12分频单片机的延时。

******************************************************************************* /

void Lcd1602_Delay1ms(uint c) //误差0us

{

uchar a,b;

for (; c>0; c--)

{

for (b=199;b>0;b--)

{

for(a=1;a>0;a--);

}

}

}

/****************************************************************************** *

* 函数名: void LCDWrite_String(uchar x, uchar y, uchar *s)

* 函数功能: 向LCD写入一个字符串

* 输入: x,y,*s

* 输出: 无

******************************************************************************* /

void LCDWrite_String(uchar x, uchar y, uchar z, uchar *s) //x 0~15 , y 0,1,2,3

{

LCD_set_xy(x,y,z);

while(*s)

{

LcdWriteData(*s);

s++;

}

}

/****************************************************************************** *

* 函数名: void LCD_set_xy(uchar x, uchar y,uchar z)

* 函数功能: 指定向LCD写入字符串的位置

* 输入: x,y,z //x:横坐标y:纵坐标z:字符串长度

* 输出: 无

******************************************************************************* /

void LCD_set_xy(uchar x,uchar y,uchar z)

{

uchar i;

if(y==0)

{

LcdWriteCom(0x80+x);

for(i=0;i

{

LcdWriteData(' ');

}

LcdWriteCom(0x80+x);

}

if(y==1)

{

LcdWriteCom(0xc0+x);

for(i=0;i

{

LcdWriteData(' ');

}

LcdWriteCom(0xc0+x);

}

if(y==2)

{

LcdWriteCom(0x94+x);

for(i=0;i

{

LcdWriteData(' ');

}

LcdWriteCom(0x94+x);

}

if(y==3)

{

LcdWriteCom(0xd4+x);

for(i=0;i

{

LcdWriteData(' ');

}

LcdWriteCom(0xd4+x);

}

}

/****************************************************************************** *

* 函数名: LcdWriteCom

* 函数功能: 向LCD写入一个字节的命令

* 输入: com

* 输出: 无

******************************************************************************* /

#ifndef LCD1602_4PINS //当没有定义这个LCD1602_4PINS时

void LcdWriteCom(uchar com) //写入命令

{

LCD1602_E = 0; //使能

LCD1602_RS = 0; //选择发送命令

LCD1602_RW = 0; //选择写入

LCD1602_DATAPINS = com; //放入命令

Lcd1602_Delay1ms(1); //等待数据稳定

LCD1602_E = 1; //写入时序

Lcd1602_Delay1ms(5); //保持时间

LCD1602_E = 0;

}

#else

void LcdWriteCom(uchar com) //写入命令

{

LCD1602_E = 0; //使能清零

LCD1602_RS = 0; //选择写入命令

LCD1602_RW = 0; //选择写入

LCD1602_DATAPINS = com; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改

Lcd1602_Delay1ms(1);

LCD1602_E = 1; //写入时序

Lcd1602_Delay1ms(5);

LCD1602_E = 0;

// Lcd1602_Delay1ms(1);

LCD1602_DATAPINS = com << 4; //发送低四位

Lcd1602_Delay1ms(1);

LCD1602_E = 1; //写入时序

Lcd1602_Delay1ms(5);

LCD1602_E = 0;

}

#endif

/****************************************************************************** *

* 函数名: LcdWriteData

* 函数功能: 向LCD写入一个字节的数据

* 输入: dat

* 输出: 无

******************************************************************************* /

#ifndef LCD1602_4PINS

void LcdWriteData(uchar dat) //写入数据

{

LCD1602_E = 0; //使能清零

LCD1602_RS = 1; //选择输入数据

LCD1602_RW = 0; //选择写入

LCD1602_DATAPINS = dat; //写入数据

Lcd1602_Delay1ms(1);

LCD1602_E = 1; //写入时序

Lcd1602_Delay1ms(5); //保持时间

LCD1602_E = 0;

}

#else

void LcdWriteData(uchar dat) //写入数据

{

LCD1602_E = 0; //使能清零

LCD1602_RS = 1; //选择写入数据

LCD1602_RW = 0; //选择写入

LCD1602_DATAPINS = dat; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改

Lcd1602_Delay1ms(1);

LCD1602_E = 1; //写入时序

Lcd1602_Delay1ms(5);

LCD1602_E = 0;

LCD1602_DATAPINS = dat << 4; //写入低四位

Lcd1602_Delay1ms(1);

LCD1602_E = 1; //写入时序

Lcd1602_Delay1ms(5);

LCD1602_E = 0;

}

#endif

/****************************************************************************** *

* 函数名: LcdInit()

* 函数功能: 初始化LCD屏

* 输入: 无

* 输出: 无

******************************************************************************* /

#ifndef LCD1602_4PINS

void LcdInit() //LCD初始化子程序

{

LcdWriteCom(0x38); //开显示

LcdWriteCom(0x0c); //开显示不显示光标

LcdWriteCom(0x06); //写一个指针加1

LcdWriteCom(0x01); //清屏

LcdWriteCom(0x80); //设置数据指针起点

}

#else

void LcdInit() //LCD初始化子程序

{

LcdWriteCom(0x32); //将8位总线转为4位总线

LcdWriteCom(0x28); //在四位线下的初始化

LcdWriteCom(0x0c); //开显示不显示光标

LcdWriteCom(0x06); //写一个指针加1

LcdWriteCom(0x01); //清屏

LcdWriteCom(0x80); //设置数据指针起点

}

#endif

程序3:

/*************************************************************** 作品:EEPROM实验,开机还原关电前LED的亮灭状况

单片机:STC89C52RC

晶振:12M

编译环境:Keil uVision4 V9.00

***************************************************************/ //#include

#include

#include

#define uchar unsigned char

#define uint unsigned int

/****************特殊功能寄存器声明****************/

sfr ISP_DATA = 0xe2;

sfr ISP_ADDRH = 0xe3;

sfr ISP_ADDRL = 0xe4;

sfr ISP_CMD = 0xe5;

sfr ISP_TRIG = 0xe6;

sfr ISP_CONTR = 0xe7;

sbit LED1 = P2^0;

sbit LED2 = P2^1;

sbit K1 = P3^2; //按钮1

sbit K2 = P3^3; //按钮2

void cc(uint addr);

void xcx(uint addr,uchar dat);

uchar dcx(uint addr);

void Q0();

#ifndef uchar

#define uchar unsigned char

#endif

#ifndef uint

#define uint unsigned int

#endif

/**********************************

PIN口定义

**********************************/

#define LCD1602_DATAPINS P0

sbit LCD1602_E=P2^7;

sbit LCD1602_RW=P2^5;

sbit LCD1602_RS=P2^6;

/**********************************

函数声明

**********************************/

/*在51单片机12MHZ时钟下的延时函数*/

void Lcd1602_Delay1ms(uint c); //误差0us

/*LCD1602写入8位命令子函数*/

void LcdWriteCom(uchar com);

/*LCD1602写入8位数据子函数*/

void LcdWriteData(uchar dat) ;

/*LCD1602初始化子程序*/

void LcdInit();

/*LCD1602写入字符串*/

void LCDWrite_String(uchar x, uchar y,uchar z, uchar *s);

/*设置LCD1602写入字符串的位置*/

void LCD_set_xy(uchar x, uchar y, uchar z);

void IntConfiguration();

/*

uchar ON_Hour=0x07; //初始开灯时间07:00 1

uchar Warning_TempH=32; //高温报警温度

5

*/

uchar ON_Hour; //初始开灯时间07:00 1 uchar Warning_TempH; //高温报警温度

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:主程序

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

void main(void)

{

LcdInit();

IntConfiguration();

/////////////////////////////////////////////////////////////////

/*

cc(0x2000); // 擦除第1个扇区(2000h~21FFh)

xcx(0x2000,ON_Hour); // 对EEPROM区2002h写入2

xcx(0x2001,Warning_TempH); // 对EEPROM区2002h写入2

*/

/////////////////////////////////////////////////////////////////

while(1)

{

ON_Hour = dcx(0x2000);

Warning_TempH = dcx(0x2001);

if((ON_Hour==0x07)||(Warning_TempH==32))

{

LcdWriteCom(0x80);

LCDWrite_String(0, 1, 7, "SUCCESS");

}

else

LcdWriteCom(0x80);

LCDWrite_String(0, 1, 5, "ERROR");

}

/*

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;

cc(0x2000); // 擦除第1个扇区(2000h~21FFh)

xcx(0x2002,2); // 对EEPROM区2002h写入2

}

if(!K2)

{

while(!K2);

LED1=0;LED2=0;

cc(0x2000); // 擦除第1个扇区(2000h~21FFh)

xcx(0x2002,6); // 对EEPROM区2002h写入6

}

}

*/

}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:擦除某一扇区(每个扇区512字节)

入口:addr = 某一扇区首地址

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

void cc(uint addr)

{

// 打开IAP 功能(ISP_CONTR.7)=1:允许编程改变Flash, 设置Flash操作等待时间

// 0x83(晶振<5M) 0x82(晶振<10M) 0x81(晶振<20M) 0x80(晶振<40M) ISP_CONTR = 0x81;

ISP_CMD = 0x03; // 用户可以对"Data Flash/EEPROM区"进行扇区擦除ISP_ADDRL = addr; // ISP/IAP操作时的地址寄存器低八位,

ISP_ADDRH = addr>>8; // ISP/IAP操作时的地址寄存器高八位。

EA =0;

ISP_TRIG = 0x46; // 在ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG先写入46h,ISP_TRIG = 0xB9; // 再写入B9h,ISP/IAP命令才会生效。

_nop_();

Q0(); // 关闭ISP/IAP

}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:写一字节

入口:addr = 扇区单元地址, dat = 待写入数据

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

void xcx(uint addr,uchar dat)

ISP_CONTR = 0x81;

ISP_CMD = 0x02; // 用户可以对"Data Flash/EEPROM区"进行字节编程ISP_ADDRL = addr;

ISP_ADDRH = addr>>8;

ISP_DATA = dat; // 数据进ISP_DATA

EA = 0;

ISP_TRIG = 0x46;

ISP_TRIG = 0xB9;

_nop_();

Q0(); // 关闭ISP/IAP

}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:读一字节

入口:addr = 扇区单元地址

出口:dat = 读出的数据

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

uchar dcx(uint addr)

{

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; // 取出数据

Q0(); // 关闭ISP/IAP

return dat;

}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

函数:关闭ISP/IAP操作

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

void Q0()

{

ISP_CONTR = 0; // 关闭IAP功能

ISP_CMD = 0; // 待机模式,无ISP操作

ISP_TRIG = 0; // 关闭IAP功能, 清与ISP有关的特殊功能寄存器EA=1;

}

/*

STC89C52RC内部EEPROM详细地址表:

第一扇区第二扇区第三扇区第四扇区

起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址

2000h 21FFh 2200h 23FFh 2400h 25FFh 2600h 27FFH

第五扇区第六扇区第七扇区第八扇区

起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址

2800h 29FFh 2A00h 2BFFh 2C00h 2DFFh 2E00h 2FFFh

*/

/****************************************************************************** *

* 函数名: Lcd1602_Delay1ms

* 函数功能: 延时函数,延时1ms

* 输入: c

* 输出: 无

* 说名: 该函数是在12MHZ晶振下,12分频单片机的延时。

******************************************************************************* /

void Lcd1602_Delay1ms(uint c) //误差0us

{

uchar a,b;

for (; c>0; c--)

{

for (b=199;b>0;b--)

{

单片机EEPROM的使用函数

/******************************************************************** 这是EEROM.h文件 ********************************************************************/ #ifndef _EEPROMus_h //对EEROM进行操作 #define _EEPROMus_h #include #include extern void EEw(unsigned int m,unsigned int,unsigned char w); //将第m扇区的第n个存储空间数据改成w extern void EEr(unsigned int m,unsigned int n,unsigned char *r); //将第m扇区的第n个存储空间数据读到r extern void EEe(unsigned int m); //删除第m扇区内的内容 extern void EEwa(unsigned int m,unsigned int n,unsigned char w[]); //在m扇区,从0x00写到第n个,写数组w里的数 extern void EEra(unsigned int m,unsigned int n,unsigned char r[]); //在m扇区,从0x00读到第n个,读到数组r里 #endif /******************************************************************** 这是EEPROM.c文件 ********************************************************************/ /******************************************************************** IAP_CONTR: B7: 0:禁止IAP 1:允许IAP B6和B5配合让程序从AP区和ISP监控区复位及程序的开始 B4:当IAP_TRIG触发的5a/a5失败,则为1,且由软件清零 B3:/ B2B1B0:设置CPU等待时间 IAP_TRIG: 每次发送命令后要用此寄存器发送5a,然后a5后,命令生效 IAP_CMD: 对IAP进行命令输入: 0x00:无操作 0x01:读 0x02:写

51单片机实例程100讲全集

目录 目录 (1) 函数的使用和熟悉 (4) 实例3:用单片机控制第一个灯亮 (4) 实例4:用单片机控制一个灯闪烁:认识单片机的工作频率 (4) 实例5:将P1口状态分别送入P0、P2、P3口:认识I/O口的引脚功能 (5) 实例6:使用P3口流水点亮8位LED (5) 实例7:通过对P3口地址的操作流水点亮8位LED (6) 实例8:用不同数据类型控制灯闪烁时间 (7) 实例9:用P0口、P1 口分别显示加法和减法运算结果 (8) 实例10:用P0、P1口显示乘法运算结果 (9) 实例11:用P1、P0口显示除法运算结果 (9) 实例12:用自增运算控制P0口8位LED流水花样 (10) 实例13:用P0口显示逻辑"与"运算结果 (10) 实例14:用P0口显示条件运算结果 (11) 实例15:用P0口显示按位"异或"运算结果 (11) 实例16:用P0显示左移运算结果 (11) 实例17:"万能逻辑电路"实验 (11) 实例18:用右移运算流水点亮P1口8位LED (12) 实例19:用if语句控制P0口8位LED的流水方向 (13) 实例20:用swtich语句的控制P0口8位LED的点亮状态 (13) 实例21:用for语句控制蜂鸣器鸣笛次数 (14) 实例22:用while语句控制LED (15) 实例23:用do-while语句控制P0口8位LED流水点亮 (16) 实例24:用字符型数组控制P0口8位LED流水点亮 (17) 实例25:用P0口显示字符串常量 (18) 实例26:用P0 口显示指针运算结果 (19) 实例27:用指针数组控制P0口8位LED流水点亮 (19) 实例28:用数组的指针控制P0 口8 位LED流水点亮 (20) 实例29:用P0 、P1口显示整型函数返回值 (21) 实例30:用有参函数控制P0口8位LED流水速度 (22) 实例31:用数组作函数参数控制流水花样 (22) 实例32:用指针作函数参数控制P0口8位LED流水点亮 (23) 实例33:用函数型指针控制P1口灯花样 (25) 实例34:用指针数组作为函数的参数显示多个字符串 (26) 实例35:字符函数ctype.h应用举例 (27) 实例36:内部函数intrins.h应用举例 (27) 实例37:标准函数stdlib.h应用举例 (28) 实例38:字符串函数string.h应用举例 (29) 实例39:宏定义应用举例2 (29) 实例40:宏定义应用举例2 (29) 实例41:宏定义应用举例3 (30)

51单片机基础知识及期末复习

51单片机简答题部分(经典) 1、什么叫堆栈? 答:堆栈是在片内RAM中专门开辟出来的一个区域,数据的存取是以"后进先出"的结构方式处理的。实质上,堆栈就是一个按照"后进先出"原则组织的一段内存区域。 2、进位和溢出? 答:两数运算的结果若没有超出字长的表示范围,则由此产生的进位是自然进位;若两数的运算结果超出了字长的表示范围(即结果不合理),则称为溢出。 3、在单片机中,片内ROM的配置有几种形式?各有什么特点? 答:单片机片内程序存储器的配置形式主要有以下几种形式:(1)掩膜(Msak)ROM型单片机:内部具有工厂掩膜编程的ROM,ROM中的程序只能由单片机制造厂家用掩膜工艺固 化,用户不能修改ROM中的程序。掩膜ROM单片机适合于 大批量生产的产品。用户可委托芯片生产厂家采用掩膜方法 将程序制作在芯片的ROM。 (2)EPROM型单片机:内部具有紫外线可擦除电可编程的只读存储器,用户可以自行将程序写入到芯片内部的EPROM 中,也可以将EPROM中的信息全部擦除。擦去信息的芯片 还可以再次写入新的程序,允许反复改写。 (3)无ROM型单片机:内部没有程序存储器,它必须连接程序存储器才能组成完整的应用系统。 无ROM型单片机价格低廉,用户可根据程序的大小来选择外接 程序存储器的容量。这种单片机扩展灵活,但系统结构较复 杂。 (4)E2ROM型单片机:内部具有电可擦除叫可编程的程序存储器,使用更为方便。该类型目前比较常用 (5)OTP(One Time Programmable)ROM单片机:内部具有一次可编程的程序存储器,用户可以在编程器上将程序写入片内程 序存储器中,程序写入后不能再改写。这种芯片的价格也较 低。 4、什么是单片机的机器周期、状态周期、振荡周期和指令周期?它们之间是什么关系? 答:某条指令的执行周期由若干个机器周期(简称M周期)构成,一个机器周期包含6个状态周期(又称时钟周期,简称S周期),而一个状态周期又包含两个振荡周期(P1和P2,简称P周期)。也就是说,指令执行周期有长有短,但一个机器周期恒等于6个状态周期或12个振荡周

51单片机实用汇编程序库(word)

51 单片机实用程序库 4.1 流水灯 程序介绍:利用P1 口通过一定延时轮流产生低电平 输出,以达到发光二极管轮流亮的效果。实际应用中例如:广告灯箱彩灯、霓虹灯闪烁。 程序实例(LAMP.ASM) ORG 0000H AJMP MAIN ORG 0030H MAIN: 9 MOV A,#00H MOV P1,A ;灭所有的灯 MOV A,#11111110B MAIN1: MOV P1,A ;开最左边的灯 ACALL DELAY ;延时 RL A ;将开的灯向右边移 AJMP MAIN ;循环 DELAY: MOV 30H,#0FFH D1: MOV 31H,#0FFH D2: DJNZ 31H,D2 DJNZ 30H,D1 RET END 4.2 方波输出 程序介绍:P1.0 口输出高电平,延时后再输出低电 平,循环输出产生方波。实际应用中例如:波形发生器。 程序实例(FAN.ASM): ORG 0000H MAIN: ;直接利用P1.0 口产生高低电平地形成方波////////////// ACALL DELAY SETB P1.0 ACALL DELAY 10 CLR P1.0 AJMP MAIN ;////////////////////////////////////////////////// DELAY: MOV R1,#0FFH DJNZ R1,$ RET

五、定时器功能实例 5.1 定时1 秒报警 程序介绍:定时器1 每隔1 秒钟将p1.o 的输出状态改变1 次,以达到定时报警的目的。实际应用例如:定时报警器。程序实例(DIN1.ASM): ORG 0000H AJMP MAIN ORG 000BH AJMP DIN0 ;定时器0 入口 MAIN: TFLA G EQU 34H ;时间秒标志,判是否到50 个 0.2 秒,即50*0.2=1 秒 MOV TMOD,#00000001B;定时器0 工作于方式 1 MOV TL0,#0AFH MOV TH0,#3CH ;设定时时间为0.05 秒,定时 20 次则一秒 11 SETB EA ;开总中断 SETB ET0 ;开定时器0 中断允许 SETB TR0 ;开定时0 运行 SETB P1.0 LOOP: AJMP LOOP DIN0: ;是否到一秒//////////////////////////////////////// INCC: INC TFLAG MOV A,TFLAG CJNE A,#20,RE MOV TFLAG,#00H CPL P1.0 ;////////////////////////////////////////////////// RE: MOV TL0,#0AFH MOV TH0,#3CH ;设定时时间为0.05 秒,定时 20 次则一秒 RETI END 5.2 频率输出公式 介绍:f=1/t s51 使用12M 晶振,一个周期是1 微秒使用定时器1 工作于方式0,最大值为65535,以产生200HZ 的频率为例: 200=1/t:推出t=0.005 秒,即5000 微秒,即一个高电

51单片机基础知识 (问答题)

1、单片机的机器周期、状态周期、振荡周期和指令周期之间是什么关系? 答:一个机器周期恒等于6个状态周期或12个振荡周期,即1M=6S=12P。 2、存储器中有几个保留特殊功能的单元用做入口地址?作用是什么? 答:MCS-51系列单片机的存储器中有6个保留特殊功能单元; 作用:0000H为复位入口、0003H为外部中断0入口、000BH为T0溢出中断入口、0013H为外部中断1入口、001BH为T1溢出中断入口、0023H为串行接口中断入口。 3、开机复位后,CPU使用是的哪组工作寄存器?它们的地址是什么?CPU如何确定和改变当前工 作寄存器组? 答:开机复位后,CPU使用的是第0组工作寄存器。 它们的地址是00H~07H。CPU通过对程序状态字PSW中RS1、RS0的设置来确定和改变当前工作寄存器组。如:RS1、RS0为00则指向第0组;为01则指向第1组;为10则指向第2组;为11则指向第3组。 4、MCS-51的时钟周期、机器周期、指令周期的如何分配的?当振荡频率为8MHz时,一个单片 机时钟周期为多少微秒? 答:MCS-51的时钟周期是最小的定时单位,也称为振荡周期或节拍。一个机器周期包含12个时钟周期或节拍。不同的指令其指令周期一般是不同的,可包含有1~4个机器周期。 当振荡频率为8MHz时,一个单片机时钟周期为0.125μs 。 5、EA/V 引脚有何功用?8031的引脚应如何处理?为什么? PP 答:EA/V PP是双功能引脚: (1)EA接高电平时,在低4KB程序地址空间(0000H~0FFFH),CPU执行片内程序存储器的指令,当程序地址超出低4KB空间(1000H~FFFFH)时,CPU将自动执行片外程序存储器的指令。 (2)EA接低电平时,CPU只能执行外部程序存储器的指令。 8031单片机内部无ROM,必须外接程序存储器。因此,8031的EA引脚必须接低电平。 在对8751单片机内部的EPROM编程时,此引脚V PP外接+12V电压,用于固化EPROM程序。 6、单片机对中断优先级的处理原则是什么? 答:⑴低级不能打断高级,高级能够打断低级; ⑵一个中断以被响应,同级的被禁止; ⑶同级,按查询顺序,INT0→T0→INT1→T1→串行接口。 7、MCS-51的外部中断的触发方式有哪两种?他们对触发脉冲或电平有什么要求? 答:有电平触发和脉冲触发。

51单片机实例(含详细代码说明)

1.闪烁灯 1.实验任务 如图4.1.1所示:在P1.0端口上接一个发光二极管L1,使L1在不停地一亮一灭,一亮一灭的时间间隔为0.2秒。 2.电路原理图 图4.1.1 3.系统板上硬件连线 把“单片机系统”区域中的P1.0端口用导线连接到“八路发光二极管指示模块”区域中的L1端口上。 4.程序设计内容 (1).延时程序的设计方法 作为单片机的指令的执行的时间是很短,数量大微秒级,因此,我们要 求的闪烁时间间隔为0.2秒,相对于微秒来说,相差太大,所以我们在 执行某一指令时,插入延时程序,来达到我们的要求,但这样的延时程 序是如何设计呢?下面具体介绍其原理:

如图4.1.1所示的石英晶体为12MHz,因此,1个机器周期为1微秒机器周期微秒 MOV R6,#20 2个 2 D1: MOV R7,#248 2个 2 2+2×248=498 20× DJNZ R7,$ 2个2×248 (498 DJNZ R6,D1 2个2×20=40 10002 因此,上面的延时程序时间为10.002ms。 由以上可知,当R6=10、R7=248时,延时5ms,R6=20、R7=248时, 延时10ms,以此为基本的计时单位。如本实验要求0.2秒=200ms, 10ms×R5=200ms,则R5=20,延时子程序如下: DELAY: MOV R5,#20 D1: MOV R6,#20 D2: MOV R7,#248 DJNZ R7,$ DJNZ R6,D2 DJNZ R5,D1 RET (2).输出控制 如图1所示,当P1.0端口输出高电平,即P1.0=1时,根据发光二极管 的单向导电性可知,这时发光二极管L1熄灭;当P1.0端口输出低电平, 即P1.0=0时,发光二极管L1亮;我们可以使用SETB P1.0指令使P1.0 端口输出高电平,使用CLR P1.0指令使P1.0端口输出低电平。 5.程序框图 如图4.1.2所示

51单片机基础知识试题题库(含答案)

第二章习题参考答案 一、填空题: 1、当MCS-51引脚ALE有效时,表示从P0口稳定地送出了低8位地址。 2、MCS-51的堆栈是软件填写堆栈指针临时在片内数据存储器内开辟的区域。 3、当使用8751且EA=1,程序存储器地址小于1000H 时,访问的是片内ROM。 4、MCS-51系统中,当PSEN信号有效时,表示CPU要从外部程序存储器读取信息。 5、MCS-51有4组工作寄存器,它们的地址范围是 00H~1FH 。 6、MCS-51片内20H~2FH范围内的数据存储器,既可以字节寻址又可以位寻址。 7、PSW中RS1 RS0=10时,R2的地址为 12H 。 8、PSW中RS1 RS0=11时,R2的地址为 1AH 。 9、单片机系统复位后,(PSW)=00H,因此片内RAM寄存区的当前寄存器是第 0 组,8个寄存器的单元地址为 00H ~ 07H 。 10、PC复位后为 0000H 。 11、一个机器周期= 12 个振荡周期= 6 个时钟周期。 12、PC的内容为将要执行的的指令地址。 13、在MCS-51单片机中,如果采用6MHz晶振,1个机器周期为 2us 。 14、内部RAM中,位地址为30H的位,该位所在字节的字节地址为 26H 。 15、若A中的内容为63H,那么,P标志位的值为 0 。 16、8051单片机复位后,R4所对应的存储单元的地址为 04H ,因上电时PSW= 00H 。这时当前的工作寄存器区是第 0 工作寄存器区。 17、使用8031芯片时,需将/EA引脚接低电平,因为其片内无程序存储器。 18、片内RAM低128个单元划分为哪3个主要部分:工作寄存器区、位寻址区 和用户RAM区。 19、通过堆栈操作实现子程序调用,首先就要把 PC 的内容入栈,以进行断点保护。调用返回时,再进行出栈保护,把保护的断点送回到 PC 。 20、MCS-51单片机程序存储器的寻址范围是由程序计数器PC的位数所决定的,因为MCS -51的PC是16位的,因此其寻址的范围为 64 KB。 21、MCS-51单片机片内RAM的寄存器共有 32 个单元,分为 4 组寄存器,每组 8 个单元,以R0~R7作为寄存器名称。 22、但单片机的型号为8031/8032时,其芯片引线EA一定要接低电平。 二、选择题: 1、当MCS-51复位时,下面说法正确的是( A )。 A、 PC=0000H B、 SP=00H C、 SBUF=00H D、 P0=00H 2、PSW=18H时,则当前工作寄存器是( D )。 A、 0组 B、 1组 C、 2组 D、 3组 3、MCS-51上电复位后,SP的内容应是( B )。 A、 00H B、 07H C、 60H D、 70H 4、当ALE信号有效时,表示( B )。 A、从ROM中读取数据 B、从P0口可靠地送出低8位地址 C、从P0口送出数据 D、从RAM中读取数据 5、MCS—51单片机的CPU主要的组成部分为( A )。 A、运算器、控制器 B、加法器、寄存器 C、运算器、加法器 D、运算器、译码器

单片机内的Flash与EEPROM作用及区别(精)

单片机内的 Flash 与 EEPROM 作用及区别 单片机运行时的数据都存在于 RAM (随机存储器中, 在掉电后 RAM 中的数据是无 法保留的,那么怎样使数据在掉电后不丢失呢?这就需要使用 EEPROM 或FLASHROM 等 存储器来实现。在传统的单片机系统中, 一般是在片外扩展存储器, 单片机与存储器之间通 过 IIC 或 SPI 等接口来进行数据通信。这样不光会增加开发成本,同时在程序开发上也要花 更多的心思。在 STC 单片机中内置了 EEPROM (其实是采用 IAP 技术读写内部 FLASH 来 实现 EEPROM ,这样就节省了片外资源,使用起来也更加方便。下面就详细介绍 STC 单 片机内置 EEPROM 及其使用方法。 flash 是用来放程序的,可以称之为程序存储器,可以擦出写入但是基本都是整个扇区进行的 . 一般来说单片机里的 flash 都用于存放运行代码,在运行过程中不能改; EEPROM 是用来保存用户数据,运行过程中可以改变,比如一个时钟的闹铃时 间初始化设定为 12:00,后来在运行中改为 6:00,这是保存在 EEPROM 里, 不怕掉电,就算重新上电也不需要重新调整到 6:00 下面是网上详细的说法,感觉不错:

FLASH 和 EEPROM 的最大区别是 FLASH 按扇区操作, EEPROM 则按字节操作, 二者寻址方法不同,存储单元的结构也不同, FLASH 的电路结构较简单,同样容量占芯片面积较小,成本自然比 EEPROM 低,因而适合用作程序存储器, EEPROM 则更多的用作非易失的数据存储器。当然用 FLASH 做数据存储器也行, 但操作比EEPROM 麻烦的多,所以更“人性化”的 MCU 设计会集成 FLASH 和 EEPROM 两种非易失性存储器,而廉价型设计往往只有 FLASH ,早期可电擦写型 MCU 则都是EEPRM 结构,现在已基本上停产了。 在芯片的内电路中, FLASH 和 EEPROM 不仅电路不同,地址空间也不同,操作方法和指令自然也不同, 不论冯诺伊曼结构还是哈佛结构都是这样。技术上, 程序存储器和非易失数据存储器都可以只用 FALSH 结构或 EEPROM 结构, 甚至可以用“变通”的技术手段在程序存储区模拟“数据存储区” ,但就算如此,概念上二者依然不同,这是基本常识问题。 EEPROM :电可擦除可编程只读存储器, Flash 的操作特性完全符合 EEPROM 的定义,属 EEPROM 无疑,首款 Flash 推出时其数据手册上也清楚的标明是EEPROM ,现在的多数 Flash 手册上也是这么标明的,二者的关系是“白马”和 “马” 。至于为什么业界要区分二者, 主要的原因是 Flash EEPROM 的操作方法和传统 EEPROM 截然不同,次要的原因是为了语言的简练,非正式文件和口语中Flash EEPROM 就简称为 Flash , 这里要强调的是白马的“白” 属性而非其“马” 属性以区别 Flash 和传统 EEPROM 。 Flash 的特点是结构简单, 同样工艺和同样晶元面积下可以得到更高容量且大数据量 下的操作速度更快,但缺点是操作过程麻烦,特别是在小数据量反复重写时, 所以在 MCU 中 Flash 结构适于不需频繁改写的程序存储器。 很多应用中,需要频繁的改写某些小量数据且需掉电非易失,传统结构的EEPROM 在此非常适合, 所以很多 MCU 内部设计了两种 EEPROM 结构, FLASH

Eeprom的读写

所看过的对24系列I2C读写时序描述最准确最容易理解的资料,尤其是关于主从器件的应答描述和页写描述,看完后明白了很多。关于页写的描述,网络上绝大部分范程都没提到页写时的数据地址必须是每页的首地址才能准确写入,而且如果写入超过一页的数据会循环覆盖当前页的数据。 关于IIC总线 I2C总线:i2c总线是Philips 公司首先推出的一种两线制串行传输总线。它由一根数据线(SDA)和一根时钟线(SDL)组成。i2c总线的数据传输过程如图3所示,基本过程为: 1、主机发出开始信号。 2、主机接着送出1字节的从机地址信息,其中最低位为读写控制码(1为读、0为写),高7位为从机器件地址代码。 3、从机发出认可信号。 4、主机开始发送信息,每发完一字节后,从机发出认可信号给主机。 5、主机发出停止信号。 I2C总线上各信号的具体说明: 开始信号:在时钟线(SCL)为高电平其间,数据线(SDA)由高变低,将产生一个开始信号。 停止信号:在时钟线(SCL)为高电平其间,数据线(SDA)由低变高,将产生一个停止信号。 应答信号:既认可信号,主机写从机时每写完一字节,如果正确从机将在下一个时钟周期将数据线(SDA)拉低,以告诉主机操作有效。在主机读从机时正确读完一字节后,主机在下一个时钟周期同样也要将数据线(SDA)拉低,发出认可信号,告诉从机所发数据已经收妥。(注:读从机时主机在最后1字节数据接收完以后不发应答,直接发停止信号)。 注意:在I2C通信过程中,所有的数据改变都必须在时钟线SCL为低电平时改变,在时钟线SCL为高电平时必须保持数据SDA信号的稳定,任何在时钟线为高电平时数据线上的电平改变都被认为是起始或停止信号。 作为一种非易失性存储器(NVM),24系列EEPROM使用的很普遍,一般作为数据量不太大的数据存储器。下面总结一下其应用的一些要点。从命名上看,24CXX中XX的单位是kbit,如24C08,其存储容量为8k bit,即1k Byte=1024 Byte。 一、工作条件 1.工作电压(VCC) 24CXX:4.5V-5.5V 24CXX-W:2.5V-5.5V 24CXX-R:1.8V-5.5V 2.输入电平定义(VIH,VIL) VIH:0.7VCC-VCC+1 VIL:-0.45V-0.3VCC 二、硬件连接 1.上拉电阻RP的取值 由于I2C总线电容要满足小于400pf的条件。从以下波形可以看出,上拉电阻越大,总线的电容越小,可以实现的数据传输率就越大,可达400khz。 [点击图片可在新窗口打开] 2.写保护脚 芯片写保护脚是高电平有效,即WP接高电平时禁止写入

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 /* 字节写*/

51单片机内部EEPROM的应用

用51hei-5板子学习单片机内部EEPROM的应用 STC89C51、52内部都自带有2K字节的EEPROM,54、55和58都自带有16K字节的EEPRO M,STC单片机是利用IAP技术实现的EEPROM,内部Flash擦写次数可达100,000 次以上,先来介绍下ISP与IAP的区别和特点。 ISP:In System Programable 是指在系统编程,通俗的讲,就是片子已经焊板子上,不用取下,就可以简单而方便地对其进行编程。比如我们通过电脑给STC单片机下载程序,或给AT89S51单片机下载程序,这就是利用了ISP技术。 IAP:In Application Programable 是指在应用编程,就是片子提供一系列的机制(硬件/软件上的)当片子在运行程序的时候可以提供一种改变flash数据的方法。通俗点讲,也就是说程序自己可以往程序存储器里写数据或修改程序。这种方式的典型应用就是用一小段代码来实现程序的下载,实际上单片机的ISP功能就是通过IAP技术来实现的,即片子在出厂前就已经有一段小的boot程序在里面,片子上电后,开始运行这段程序,当检测到上位机有下载要求时,便和上位机通信,然后下载数据到存储区。大家要注意千万不要尝试去擦除这段ISP引导程序,否则恐怕以后再也下载不了程序了。STC单片机内部有几个专门的特殊功能寄存器负责管理ISP/IAP 功能的,见表1。 表1 ISP/IAP相关寄存器列表 名称地址功能描述D7D6D5D4D3D2D1D0复位值ISP_DATA E2h Flash数据寄存器1111 1111 ISP_ADDRH E3h Flash高字节地址寄 存器0000 0000 ISP_ADDRL E4h Flash低字节地址寄 存器0000 0000 ISP_CMD E5h Flash命令模式寄存 器 ----------MS2MS1MS0xxxx x000 ISP_TRIG E6h Flash命令触发寄存 器 xxxx xxxx ISP_CONTR E7h ISP/IAP 控制寄存器ISPEN SWBS SWRST----WT2WT1WT0000x x000 ISP_DATA:ISP/IAP操作时的数据寄存器。

STC单片机EEPROM的应用和程序

STC单片机EEPROM的应用和程序 (2009-04-22 21:58:34) 转载▼ 标签: 杂谈 分类:Program 最近,由于工作的需要,用STC89C52来开发新产品,要用天STC的Eeprom的功能,上网也找了一点资料,得到很大帮助,真的非常感谢。程序是我在网上摘录的,调试通过了,不过我产品在用动态扫描显示的,由于在Eeprom擦除时要用几十毫秒,会有一闪烁的。不过这是正常的。 单片机运行时的数据都存在于RAM(随机存储器)中,在掉电后RAM 中的数据是无 法保留的,那么怎样使数据在掉电后不丢失呢?这就需要使用EEPROM 或FLASHROM 等存储器来实现。在传统的单片机系统中,一般是在片外扩展存储器,单片机与存储器之间通过IIC 或SPI 等接口来进行数据通信。这样不光会增加开发成本,同时在程序开发上也要花更多的心思。在STC 单片机中内置了EEPROM(其实是采用IAP 技术读写内部FLASH 来 实现EEPROM),这样就节省了片外资源,使用起来也更加方便。下面就详细介绍STC 单片机内置EEPROM 及其使用方法。 STC 各型号单片机内置的EEPROM 的容量各有不同,见下表: (内部EEPROM 可以擦写100000 次以上) 上面提到了IAP,它的意思是"在应用编程",即在程序运行时程序存储器可由程序自 身进行擦写。正是是因为有了IAP,从而可以使单片机可以将数据写入到程序存储器中,使得数据如同烧入的程序一样,掉电不丢失。当然写入数据的区域与程序存储区要分开来,以使程序不会遭到破坏。 要使用IAP 功能,与以下几个特殊功能寄存器相关: ISP_DATA:ISP/IAP 操作时的数据寄存器。 ISP/IAP 从Flash 读出的数据放在此处,向Flash 写的数据也需放在此处 ISP_ADDRH:ISP/IAP 操作时的地址寄存器高八位。 ISP_ADDRL:ISP/IAP 操作时的地址寄存器低八位。 ISP_CMD:ISP/IAP 操作时的命令模式寄存器,须命令触发寄存器触发方可生效。 ISP_TRIG:ISP/IAP 操作时的命令触发寄存器。 当ISPEN(ISP_CONTR.7)=1 时,对ISP_TRIG 先写入0x46,再写入0xb9,ISP/IAP 命令才会生效。 单片机芯片型号起始地址内置EEPROM 容量(每扇区512 字节) STC89C51RC,STC89LE51RC 0x2000 共八个扇区 STC89C52RC,STC89LE52RC 0x2000 共八个扇区 STC89C54RD+,STC89LE54RD+ 0x8000 共五十八个扇区 STC89C55RD+,STC89LE55RD+ 0x8000 共五十八个扇区 STC89C58RD+,STC89LE58RD+ 0x8000 共五十八个扇区 寄存器标识地址名称7 6 5 4 3 2 1 0 初始值 ISP_DATA 0xE2 ISP/IAP闪存数据寄存器11111111 ISP_ADDRH 0xE3 ISP/IAP 闪存地址高位00000000

52单片机内部EEPROM

#include #include #define uchar unsigned char #define uint unsigned int sbit en=P2^7; sbit rs=P2^6; sbit rw=P2^5; void delay(unsigned char z) { unsigned char j,i; for (i=0;i> 8); //送地址高字节

51内部eeprom读写,实现掉电存储

主函数: #include #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 #include //sfr定义特殊功能寄存器 sfr ISP_DA TA =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 控制寄存器 /* 定义命令*/

51单片机50个实例代码

51单片机50个例程代码程序里有中断,串口等驱动,直接复制即可使用1-IO输出-点亮1个LED灯方法1 /*----------------------------------------------- 名称:IO口高低电平控制 论坛:https://www.doczj.com/doc/7a18022621.html, 编写:shifang 日期:2009.5 修改:无 内容:点亮P1口的一个LED灯 该程序是单片机学习中最简单最基础的, 通过程序了解如何控制端口的高低电平 ------------------------------------------------*/ #include //包含头文件,一般情况不需要改动, //头文件包含特殊功能寄存器的定义 sbit LED=P1^0;// 用sbit 关键字定义LED到P1.0端口, //LED是自己任意定义且容易记忆的符号 /*------------------------------------------------ 主函数 ------------------------------------------------*/ void main (void) { //此方法使用bit位对单个端口赋值 LED=1; //将P1.0口赋值1,对外输出高电平 LED=0; //将P1.0口赋值0,对外输出低电平 while (1) //主循环 { //主循环中添加其他需要一直工作的程序 } } 2-IO输出-点亮1个LED灯方法2 /*-----------------------------------------------

名称:IO口高低电平控制 论坛:https://www.doczj.com/doc/7a18022621.html, 编写:shifang 日期:2009.5 修改:无 内容:点亮P1口的一个LED灯 该程序是单片机学习中最简单最基础的, 通过程序了解如何控制端口的高低电平 ------------------------------------------------*/ #include //包含头文件,一般情况不需要改动, //头文件包含特殊功能寄存器的定义 /*------------------------------------------------ 主函数 ------------------------------------------------*/ void main (void) { //此方法使用1个字节对单个端口赋值 P1 = 0xFF; //P1口全部为高电平,对应的LED灯全灭掉, //ff换算成二进制是1111 1111 P1 = 0xfe; //P1口的最低位点亮,可以更改数值是其他的灯点亮 //0xfe是16进制,0x开头表示16进制数, //fe换算成二进制是1111 1110 while (1) //主循环 { //主循环中添加其他需要一直工作的程序 } } 3-IO输出-点亮多个LED灯方法1 /*----------------------------------------------- 名称:IO口高低电平控制 论坛:https://www.doczj.com/doc/7a18022621.html, 编写:shifang 日期:2009.5 修改:无 内容:点亮P1口的多个LED灯

AT24C02EEPROM读写程序

;--------------------------------------------------------------------------------------------------------------------- ;本程序是针对AT89S52单片机编制的EEPROM读写程序(2013.8.4测试通过) ;本程序在4MHZ、12MHZ和24MHZ分别测试通过 ;AT24C02的A0、A1、A2均接GND,设备地址高7位为(1010)000;WP接GND,充许对EEPROM正常读写 ;本程序仅作学习交流之用。 ;--------------------------------------------------------------------------------------------------------------------- SCl equ P2.0 ;SCL接A T89S52的P2.0端口,作为EEPROM的串行输入时钟 SDA equ P2.1 ;SDA接AT89S52的P2.1端口,作为主机与EEPROM之间信息串行传输总线WRITEDATA equ 08H;拟写入EEPROM的数据在主机中的存贮单元地址 READDATA equ 09H ;从EEPROM读取的数据存放到主机存贮单元地址EPROMADDRESS equ 0AH;拟随机读写EEPROM的存贮单元地址 ;------------------------------------------------ ORG 00H LJMP MAIN ;------------------------------------------------ ORG 50H MAIN: MOV SP,#20H;防止堆栈影响已用内存数据 ;以下为写EEPROM过程 mov EPROMADDRESS,#09H;该地址可以随意输入(00H~FFH),但读和写的地址须相同 MOV WRITEDA TA,#01010010B;该数字可以随意输入,并将读和写的数据进行比较;如读数正确则按将读出数据在P1口输出,可在P1口各位分别接LED灯直观显示出来。 LCALL WRITEEEPROMR ;以下为读EEPROM过程 mov EPROMADDRESS,#09H;该地址可以随意输入(00H~FFH),但读和写的地址须相同 LCALL READEEPROMR ;以下为EEPROM读写操作验证 MOV A,WRITEdata MOV B,A MOV A,READDATA CJNE A,B,MAIN1 MOV P1,READDATA;写入数和读出数相等时,读出的数据在P1口输出并按位分别控制LED灯直观显示 sJMP $ MAIN1: MOV P1,#00H;写入数和读出数相等时,LED灯全亮 ;以下可接其它主程序,此处暂为死循环 SJMP $ ;--------------------------------------------------------------------------------------------------------------------- ;WRITEEEPROMR是随机写EEPROM(AT24C02)子程序 ;入口1:EEPROMADRESS(拟读写EEPROM存贮单元地址,00~FFH) ;入口2:WRITEDATA(拟写入EEPROM的字节数据在主机的存放地址)

IC读写EEPROM问题总结

I C读写E E P R O M问题 总结 文件管理序列号:[K8UY-K9IO69-O6M243-OL889-F88688]

2017年6月30日星期五 目的:利用TMS320F2801芯片上外设I2C(2线串口)读写EEPROM数据(24LC128) 关键点1:24LC时钟频率400KHz,寄存器设置如下: I2caRegs.I2CPSC.all = 9; // Prescaler - need 7-12 Mhz on module clk I2caRegs.I2CCLKL = 10; // NOTE: must be non zero I2caRegs.I2CCLKH = 5; // NOTE: must be non zero 时钟频率也可设为200KHz,三个参数分别为9、20、20(CPU时钟频率为100MHz)(未测试?) 关键点2:波形分析 问题:I2C模块是不是只有I2CCNT 减到0才会发出停止信号 I2C模块是硬件的,当检测到发送完了就会发结束自动发信号,不需要人为干预 问题1:字节写操作正常,但是字节读函数出错 原因:写EEPROM是在七位器件地址后添加写标志,而读EEPROM需要在七位器件地址后添加写标志。 关键点:读EEPROM数据需要发送两次命令。第一次为写地址(此地址会被赋值给EEPROM内的地址指针),因此需要添加写标志;第二次为读数据,将写标志改为读标志。

问题2:主机接收时,SDA数据线上有数据传输,且I2CDRR接收数据寄存器有数据更新,但寄存器显示不可读,即CPU认为一直没接收到数据,一直停在下面语句 while 关键点:初始化设置时采用的是FIFO接收方式,因此无效,应查询FIFO 接收中断位while方式查询位。 此位只有在非FIFO中断接收方式时才有效。 问题3:断续单字节读写正常,但是采用连续的单字节读写出错。 原因:EEPROM写过程的结束并不是I2C总线写结束就结束,实际上I2C 总线的写入数据先被保存到了EEPROM内部的缓冲区,当遇到I2C结束条件后,EEPROM才启动内部写过程,这个过程才是保存数据的过程。非常悲哀的是这个过程比较长,官方文档标注为5ms。如果在这5ms以内对EEPROM芯片访问将被忽略。 关键点:读写EEPROM应延时至少5ms,软件延时10ms do{}while(EEPROM_Timer <= 10); //10ms 问题4:查询EEPROM写过程是否结束造成死机,只能查询EEPROM读过程。 官方文档说EEPROM内部写周期最长为5ms,在很多情况下是远远低于 5ms的,为了节约时间,官方给出一个解决办法。当写周期完毕后就开始进行应答查询,来确定EEPROM写周期何时结束。所谓应答查询官方解释为:就是向EEPROM发送一个I2C起始条件后发送器件地址和一个读写标

相关主题
文本预览
相关文档 最新文档