找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 41313|回复: 30
收起左侧

51单片机读写内部EEPROM详解

  [复制链接]
ID:163705 发表于 2017-3-29 16:11 | 显示全部楼层 |阅读模式
此文档共包含三个程序。

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

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

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

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

程序1
  1. /***************************************************************
  2.     作品:EEPROM实验,开机还原关电前LED的亮灭状况
  3.   单片机:STC89C52RC
  4.     晶振:12M
  5. 编译环境:Keil uVision4 V9.00
  6. ***************************************************************/     
  7. //#include <STC89C52RC.H>
  8. #include <reg52.h>
  9. #include <intrins.h>
  10. #define uchar unsigned char   
  11. #define uint unsigned int
  12. /****************特殊功能寄存器声明****************/
  13. sfr ISP_DATA = 0xe2;   
  14. sfr ISP_ADDRH = 0xe3;     
  15. sfr ISP_ADDRL = 0xe4;   
  16. sfr ISP_CMD = 0xe5;   
  17. sfr ISP_TRIG = 0xe6;      
  18. sfr ISP_CONTR = 0xe7;
  19. sbit LED1 = P2^0;
  20. sbit LED2 = P2^1;
  21. sbit K1   = P3^2;                           //按钮1
  22. sbit K2   = P3^3;                           //按钮2
  23. void  cc(uint addr);
  24. void  xcx(uint addr,uchar dat);
  25. uchar dcx(uint addr);
  26. void  Q0();
  27. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  28. 函数:主程序
  29. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  30. /*
  31. void main(void)
  32. {
  33.    uchar V;
  34.    V = dcx(0x2002);                          // 开机读取EEPROM区2002h数据,还原关电前LED的亮灭状况
  35.    if(V == 2)          {LED1=0;LED2=1;}
  36.    else if(V == 6){LED1=0;LED2=0;}
  37.    while(1)
  38.      {
  39.       if(!K1)
  40.             {
  41.               while(!K1);
  42.               LED1=0;LED2=1;
  43.               cc(0x2000);                  // 擦除第1个扇区(2000h~21FFh)
  44.               xcx(0x2002,2);          // 对EEPROM区2002h写入2
  45.             }
  46.           if(!K2)
  47.             {
  48.               while(!K2);
  49.               LED1=0;LED2=0;
  50.               cc(0x2000);                  // 擦除第1个扇区(2000h~21FFh)
  51.               xcx(0x2002,6);                          // 对EEPROM区2002h写入6
  52.             }
  53.      }
  54. }
  55. */
  56. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  57. 函数:擦除某一扇区(每个扇区512字节)
  58. 入口:addr = 某一扇区首地址                          
  59. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  60. void cc(uint addr)
  61. {      
  62. // 打开 IAP 功能(ISP_CONTR.7)=1:允许编程改变Flash, 设置Flash操作等待时间
  63. // 0x83(晶振<5M)   0x82(晶振<10M)   0x81(晶振<20M)   0x80(晶振<40M)
  64.     ISP_CONTR = 0x81;  
  65.     ISP_CMD   = 0x03;                  // 用户可以对"Data Flash/EEPROM区"进行扇区擦除
  66.     ISP_ADDRL = addr;         // ISP/IAP操作时的地址寄存器低八位,
  67.     ISP_ADDRH = addr>>8;      // ISP/IAP操作时的地址寄存器高八位。
  68.         EA =0;   
  69.     ISP_TRIG = 0x46;          // 在ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG先写入46h,
  70.     ISP_TRIG = 0xB9;          // 再写入B9h,ISP/IAP命令才会生效。
  71.     _nop_();
  72.     Q0();                                          // 关闭ISP/IAP
  73. }
  74. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  75. 函数:写一字节
  76. 入口:addr = 扇区单元地址 , dat = 待写入数据
  77. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  78. void xcx(uint addr,uchar dat)
  79. {
  80.     ISP_CONTR = 0x81;                  
  81.     ISP_CMD   = 0x02;              // 用户可以对"Data Flash/EEPROM区"进行字节编程
  82.     ISP_ADDRL = addr;        
  83.     ISP_ADDRH = addr>>8;      
  84.     ISP_DATA  = dat;          // 数据进ISP_DATA
  85.     EA = 0;
  86.     ISP_TRIG = 0x46;         
  87.     ISP_TRIG = 0xB9;         
  88.     _nop_();
  89.     Q0();                                          // 关闭ISP/IAP
  90. }
  91. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  92. 函数:读一字节
  93. 入口:addr = 扇区单元地址
  94. 出口:dat  = 读出的数据
  95. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  96. uchar dcx(uint addr)
  97. {   
  98.     uchar dat;
  99.       
  100.         ISP_CONTR = 0x81;                  
  101.     ISP_CMD   = 0x01;         // 用户可以对"Data Flash/EEPROM区"进行字节读
  102.     ISP_ADDRL = addr;         
  103.     ISP_ADDRH = addr>>8;      
  104.     EA = 0;
  105.     ISP_TRIG = 0x46;         
  106.     ISP_TRIG = 0xB9;         
  107.     _nop_();
  108.     dat = ISP_DATA;                          // 取出数据
  109.         Q0();                                          // 关闭ISP/IAP                  
  110.         return dat;
  111. }
  112. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  113. 函数:关闭ISP/IAP操作
  114. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  115. void Q0()
  116. {
  117.     ISP_CONTR = 0;            // 关闭IAP功能
  118.     ISP_CMD   = 0;            // 待机模式,无ISP操作
  119.     ISP_TRIG  = 0;            // 关闭IAP功能, 清与ISP有关的特殊功能寄存器
  120. }
  121. /*
  122. STC89C52RC内部EEPROM详细地址表:
  123. 第一扇区                   第二扇区                    第三扇区                    第四扇区
  124. 起始地址  结束地址   起始地址   结束地址   起始地址   结束地址   起始地址    结束地址
  125. 2000h      21FFh       2200h       23FFh      2400h       25FFh       2600h        27FFH
  126. 第五扇区                    第六扇区                     第七扇区                    第八扇区
  127. 起始地址   结束地址   起始地址   结束地址    起始地址   结束地址   起始地址    结束地址
  128. 2800h       29FFh       2A00h      2BFFh        2C00h      2DFFh      2E00h        2FFFh
  129. */
复制代码

程序2
  1. /***************************************************************
  2.     作品:EEPROM实验,开机还原关电前LED的亮灭状况
  3.   单片机:STC89C52RC
  4.     晶振:12M
  5. 编译环境:Keil uVision4 V9.00
  6. ***************************************************************/     
  7. //#include <STC89C52RC.H>
  8. #include <reg52.h>
  9. #include <intrins.h>
  10. #define uchar unsigned char   
  11. #define uint unsigned int
  12. /****************特殊功能寄存器声明****************/
  13. sfr ISP_DATA = 0xe2;   
  14. sfr ISP_ADDRH = 0xe3;     
  15. sfr ISP_ADDRL = 0xe4;   
  16. sfr ISP_CMD = 0xe5;   
  17. sfr ISP_TRIG = 0xe6;      
  18. sfr ISP_CONTR = 0xe7;
  19. sbit LED1 = P2^0;
  20. sbit LED2 = P2^1;
  21. sbit K1   = P3^2;                           //按钮1
  22. sbit K2   = P3^3;                           //按钮2
  23. void  cc(uint addr);
  24. void  xcx(uint addr,uchar dat);
  25. uchar dcx(uint addr);
  26. void  Q0();
  27. #ifndef uchar
  28. #define uchar unsigned char
  29. #endif
  30. #ifndef uint
  31. #define uint unsigned int
  32. #endif
  33. /**********************************
  34. PIN口定义
  35. **********************************/
  36. #define LCD1602_DATAPINS P0
  37. sbit LCD1602_E=P2^7;
  38. sbit LCD1602_RW=P2^5;
  39. sbit LCD1602_RS=P2^6;
  40. /**********************************
  41. 函数声明
  42. **********************************/
  43. /*在51单片机12MHZ时钟下的延时函数*/
  44. void Lcd1602_Delay1ms(uint c);   //误差 0us
  45. /*LCD1602写入8位命令子函数*/
  46. void LcdWriteCom(uchar com);
  47. /*LCD1602写入8位数据子函数*/      
  48. void LcdWriteData(uchar dat)        ;
  49. /*LCD1602初始化子程序*/               
  50. void LcdInit();      
  51. /*LCD1602写入字符串*/
  52. void LCDWrite_String(uchar x, uchar y,uchar z, uchar *s);
  53. /*设置LCD1602写入字符串的位置*/
  54. void LCD_set_xy(uchar x, uchar y, uchar z);               
  55. uchar ON_Hour=0x07;          //初始开灯时间  07:00                                                                   1
  56. uchar Warning_TempH=32;         //高温报警温度                                                                                   5
  57. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  58. 函数:主程序
  59. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  60. /*
  61. void main(void)
  62. {
  63.    uchar V;
  64.    V = dcx(0x2002);                          // 开机读取EEPROM区2002h数据,还原关电前LED的亮灭状况
  65.    if(V == 2)          {LED1=0;LED2=1;}
  66.    else if(V == 6){LED1=0;LED2=0;}
  67.    while(1)
  68.      {
  69.       if(!K1)
  70.             {
  71.               while(!K1);
  72.               LED1=0;LED2=1;
  73.               cc(0x2000);                  // 擦除第1个扇区(2000h~21FFh)
  74.               xcx(0x2002,2);          // 对EEPROM区2002h写入2
  75.             }
  76.           if(!K2)
  77.             {
  78.               while(!K2);
  79.               LED1=0;LED2=0;
  80.               cc(0x2000);                  // 擦除第1个扇区(2000h~21FFh)
  81.               xcx(0x2002,6);                          // 对EEPROM区2002h写入6
  82.             }
  83.      }
  84. }
  85. */
  86. void main(void)
  87. {
  88.    LcdInit();
  89. //不注销下面三句,烧录一次
  90. //注销小面三句,再烧录一次
  91. //若两次烧录后现象一致,则操作内部EEPROM成功
  92. /////////////////////////////////////////////////////////////////
  93.    cc(0x2000);                  // 擦除第1个扇区(2000h~21FFh)
  94.    xcx(0x2000,ON_Hour);          // 对EEPROM区2002h写入2
  95.    xcx(0x2001,Warning_TempH);          // 对EEPROM区2002h写入2
  96. /////////////////////////////////////////////////////////////////   
  97.    ON_Hour = dcx(0x2000);
  98.    Warning_TempH = dcx(0x2001);
  99.    if((ON_Hour==0x07)||(Warning_TempH==32))
  100.    {
  101.            LcdWriteCom(0x80);
  102.           LCDWrite_String(0, 1, 7, "SUCCESS");
  103.    }
  104.    else
  105.    LCDWrite_String(0, 1, 5, "ERROR");
  106.    while(1);
  107. }
  108. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  109. 函数:擦除某一扇区(每个扇区512字节)
  110. 入口:addr = 某一扇区首地址                          
  111. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  112. void cc(uint addr)
  113. {      
  114. // 打开 IAP 功能(ISP_CONTR.7)=1:允许编程改变Flash, 设置Flash操作等待时间
  115. // 0x83(晶振<5M)   0x82(晶振<10M)   0x81(晶振<20M)   0x80(晶振<40M)
  116.     ISP_CONTR = 0x81;  
  117.     ISP_CMD   = 0x03;                  // 用户可以对"Data Flash/EEPROM区"进行扇区擦除
  118.     ISP_ADDRL = addr;         // ISP/IAP操作时的地址寄存器低八位,
  119.     ISP_ADDRH = addr>>8;      // ISP/IAP操作时的地址寄存器高八位。
  120.         EA =0;   
  121.     ISP_TRIG = 0x46;          // 在ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG先写入46h,
  122.     ISP_TRIG = 0xB9;          // 再写入B9h,ISP/IAP命令才会生效。
  123.     _nop_();
  124.     Q0();                                          // 关闭ISP/IAP
  125. }
  126. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  127. 函数:写一字节
  128. 入口:addr = 扇区单元地址 , dat = 待写入数据
  129. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  130. void xcx(uint addr,uchar dat)
  131. {
  132.     ISP_CONTR = 0x81;                  
  133.     ISP_CMD   = 0x02;              // 用户可以对"Data Flash/EEPROM区"进行字节编程
  134.     ISP_ADDRL = addr;        
  135.     ISP_ADDRH = addr>>8;      
  136.     ISP_DATA  = dat;          // 数据进ISP_DATA
  137.     EA = 0;
  138.     ISP_TRIG = 0x46;         
  139.     ISP_TRIG = 0xB9;         
  140.     _nop_();
  141.     Q0();                                          // 关闭ISP/IAP
  142. }
  143. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  144. 函数:读一字节
  145. 入口:addr = 扇区单元地址
  146. 出口:dat  = 读出的数据
  147. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  148. uchar dcx(uint addr)
  149. {   
  150.     uchar dat;
  151.       
  152.         ISP_CONTR = 0x81;                  
  153.     ISP_CMD   = 0x01;         // 用户可以对"Data Flash/EEPROM区"进行字节读
  154.     ISP_ADDRL = addr;         
  155.     ISP_ADDRH = addr>>8;      
  156.     EA = 0;
  157.     ISP_TRIG = 0x46;         
  158.     ISP_TRIG = 0xB9;         
  159.     _nop_();
  160.     dat = ISP_DATA;                          // 取出数据
  161.         Q0();                                          // 关闭ISP/IAP                  
  162.         return dat;
  163. }
  164. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  165. 函数:关闭ISP/IAP操作
  166. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  167. void Q0()
  168. {
  169.     ISP_CONTR = 0;            // 关闭IAP功能
  170.     ISP_CMD   = 0;            // 待机模式,无ISP操作
  171.     ISP_TRIG  = 0;            // 关闭IAP功能, 清与ISP有关的特殊功能寄存器
  172. }
  173. /*
  174. STC89C52RC内部EEPROM详细地址表:
  175. 第一扇区                   第二扇区                    第三扇区                    第四扇区
  176. 起始地址  结束地址   起始地址   结束地址   起始地址   结束地址   起始地址    结束地址
  177. 2000h      21FFh       2200h       23FFh      2400h       25FFh       2600h        27FFH
  178. 第五扇区                    第六扇区                     第七扇区                    第八扇区
  179. 起始地址   结束地址   起始地址   结束地址    起始地址   结束地址   起始地址    结束地址
  180. 2800h       29FFh       2A00h      2BFFh        2C00h      2DFFh      2E00h        2FFFh
  181. */
  182. /*******************************************************************************
  183. * 函 数 名         : Lcd1602_Delay1ms
  184. * 函数功能                   : 延时函数,延时1ms
  185. * 输    入         : c
  186. * 输    出         : 无
  187. * 说    名         : 该函数是在12MHZ晶振下,12分频单片机的延时。
  188. *******************************************************************************/
  189. void Lcd1602_Delay1ms(uint c)   //误差 0us
  190. {
  191.     uchar a,b;
  192.         for (; c>0; c--)
  193.         {
  194.                  for (b=199;b>0;b--)
  195.                  {
  196.                           for(a=1;a>0;a--);
  197.                  }      
  198.         }         
  199. }
  200. /*******************************************************************************
  201. * 函 数 名         : void LCDWrite_String(uchar x, uchar y, uchar *s)
  202. * 函数功能                   : 向LCD写入一个字符串
  203. * 输    入         : x,y,*s
  204. * 输    出         : 无
  205. *******************************************************************************/
  206. void LCDWrite_String(uchar x, uchar y, uchar z, uchar *s)        //x 0~15 , y 0,1,2,3
  207. {
  208.         LCD_set_xy(x,y,z);
  209.         while(*s)
  210.         {
  211.                 LcdWriteData(*s);
  212.                 s++;
  213.         }
  214. }
  215. /*******************************************************************************
  216. * 函 数 名         : void LCD_set_xy(uchar x, uchar y,uchar z)
  217. * 函数功能                   : 指定向LCD写入字符串的位置
  218. * 输    入         : x,y,z                 //x:横坐标 y:纵坐标 z:字符串长度
  219. * 输    出         : 无
  220. *******************************************************************************/
  221. void LCD_set_xy(uchar x,uchar y,uchar z)
  222. {
  223.         uchar i;
  224.         if(y==0)
  225.         {
  226.                 LcdWriteCom(0x80+x);
  227.                 for(i=0;i<z;i++)
  228.                 {
  229.                         LcdWriteData(' ');
  230.                 }
  231.                 LcdWriteCom(0x80+x);
  232.         }
  233.         if(y==1)
  234.         {
  235.                 LcdWriteCom(0xc0+x);
  236.                 for(i=0;i<z;i++)
  237.                 {
  238.                         LcdWriteData(' ');
  239.                 }
  240.                 LcdWriteCom(0xc0+x);
  241.         }
  242.         if(y==2)
  243.         {
  244.                 LcdWriteCom(0x94+x);
  245.                 for(i=0;i<z;i++)
  246.                 {
  247.                         LcdWriteData(' ');
  248.                 }
  249.                 LcdWriteCom(0x94+x);
  250.         }
  251.         if(y==3)
  252.         {
  253.                 LcdWriteCom(0xd4+x);
  254.                 for(i=0;i<z;i++)
  255.                 {
  256.                         LcdWriteData(' ');
  257.                 }
  258.                 LcdWriteCom(0xd4+x);
  259.         }
  260. }
  261. /*******************************************************************************
  262. * 函 数 名         : LcdWriteCom
  263. * 函数功能                   : 向LCD写入一个字节的命令
  264. * 输    入         : com
  265. * 输    出         : 无
  266. *******************************************************************************/
  267. #ifndef         LCD1602_4PINS         //当没有定义这个LCD1602_4PINS时
  268. void LcdWriteCom(uchar com)          //写入命令
  269. {
  270.         LCD1602_E = 0;     //使能
  271.         LCD1602_RS = 0;           //选择发送命令
  272.         LCD1602_RW = 0;           //选择写入
  273.       
  274.         LCD1602_DATAPINS = com;     //放入命令
  275.         Lcd1602_Delay1ms(1);                //等待数据稳定
  276.         LCD1602_E = 1;                  //写入时序
  277.         Lcd1602_Delay1ms(5);          //保持时间
  278.         LCD1602_E = 0;
  279. }
  280. #else
  281. void LcdWriteCom(uchar com)          //写入命令
  282. {
  283.         LCD1602_E = 0;         //使能清零
  284.         LCD1602_RS = 0;         //选择写入命令
  285.         LCD1602_RW = 0;         //选择写入
  286.         LCD1602_DATAPINS = com;        //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
  287.         Lcd1602_Delay1ms(1);
  288.         LCD1602_E = 1;         //写入时序
  289.         Lcd1602_Delay1ms(5);
  290.         LCD1602_E = 0;
  291. //        Lcd1602_Delay1ms(1);
  292.         LCD1602_DATAPINS = com << 4; //发送低四位
  293.         Lcd1602_Delay1ms(1);
  294.         LCD1602_E = 1;         //写入时序
  295.         Lcd1602_Delay1ms(5);
  296.         LCD1602_E = 0;
  297. }
  298. #endif
  299. /*******************************************************************************
  300. * 函 数 名         : LcdWriteData
  301. * 函数功能                   : 向LCD写入一个字节的数据
  302. * 输    入         : dat
  303. * 输    出         : 无
  304. *******************************************************************************/                  
  305. #ifndef         LCD1602_4PINS                  
  306. void LcdWriteData(uchar dat)                        //写入数据
  307. {
  308.         LCD1602_E = 0;        //使能清零
  309.         LCD1602_RS = 1;        //选择输入数据
  310.         LCD1602_RW = 0;        //选择写入
  311.         LCD1602_DATAPINS = dat; //写入数据
  312.         Lcd1602_Delay1ms(1);
  313.         LCD1602_E = 1;   //写入时序
  314.         Lcd1602_Delay1ms(5);   //保持时间
  315.         LCD1602_E = 0;
  316. }
  317. #else
  318. void LcdWriteData(uchar dat)                        //写入数据
  319. {
  320.         LCD1602_E = 0;          //使能清零
  321.         LCD1602_RS = 1;          //选择写入数据
  322.         LCD1602_RW = 0;          //选择写入
  323.         LCD1602_DATAPINS = dat;        //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
  324.         Lcd1602_Delay1ms(1);
  325.         LCD1602_E = 1;          //写入时序
  326.         Lcd1602_Delay1ms(5);
  327.         LCD1602_E = 0;
  328.         LCD1602_DATAPINS = dat << 4; //写入低四位
  329.         Lcd1602_Delay1ms(1);
  330.         LCD1602_E = 1;          //写入时序
  331.         Lcd1602_Delay1ms(5);
  332.         LCD1602_E = 0;
  333. }
  334. #endif
  335. /*******************************************************************************
  336. * 函 数 名       : LcdInit()
  337. * 函数功能                 : 初始化LCD屏
  338. * 输    入       : 无
  339. * 输    出       : 无
  340. *******************************************************************************/                  
  341. #ifndef                LCD1602_4PINS
  342. void LcdInit()                                                  //LCD初始化子程序
  343. {
  344.         LcdWriteCom(0x38);  //开显示
  345.         LcdWriteCom(0x0c);  //开显示不显示光标
  346.         LcdWriteCom(0x06);  //写一个指针加1
  347.         LcdWriteCom(0x01);  //清屏
  348.         LcdWriteCom(0x80);  //设置数据指针起点
  349. }
  350. #else
  351. void LcdInit()                                                  //LCD初始化子程序
  352. {
  353.         LcdWriteCom(0x32);         //将8位总线转为4位总线
  354.         LcdWriteCom(0x28);         //在四位线下的初始化
  355.         LcdWriteCom(0x0c);  //开显示不显示光标
  356.         LcdWriteCom(0x06);  //写一个指针加1
  357.         LcdWriteCom(0x01);  //清屏
  358.         LcdWriteCom(0x80);  //设置数据指针起点
  359. }
  360. #endif
复制代码

程序3
  1. /***************************************************************
  2.     作品:EEPROM实验,开机还原关电前LED的亮灭状况
  3.   单片机:STC89C52RC
  4.     晶振:12M
  5. 编译环境:Keil uVision4 V9.00
  6. ***************************************************************/     
  7. //#include <STC89C52RC.H>
  8. #include <reg52.h>
  9. #include <intrins.h>
  10. #define uchar unsigned char   
  11. #define uint unsigned int
  12. /****************特殊功能寄存器声明****************/
  13. sfr ISP_DATA = 0xe2;   
  14. sfr ISP_ADDRH = 0xe3;     
  15. sfr ISP_ADDRL = 0xe4;   
  16. sfr ISP_CMD = 0xe5;   
  17. sfr ISP_TRIG = 0xe6;      
  18. sfr ISP_CONTR = 0xe7;
  19. sbit LED1 = P2^0;
  20. sbit LED2 = P2^1;
  21. sbit K1   = P3^2;                           //按钮1
  22. sbit K2   = P3^3;                           //按钮2
  23. void  cc(uint addr);
  24. void  xcx(uint addr,uchar dat);
  25. uchar dcx(uint addr);
  26. void  Q0();
  27. #ifndef uchar
  28. #define uchar unsigned char
  29. #endif
  30. #ifndef uint
  31. #define uint unsigned int
  32. #endif
  33. /**********************************
  34. PIN口定义
  35. **********************************/
  36. #define LCD1602_DATAPINS P0
  37. sbit LCD1602_E=P2^7;
  38. sbit LCD1602_RW=P2^5;
  39. sbit LCD1602_RS=P2^6;
  40. /**********************************
  41. 函数声明
  42. **********************************/
  43. /*在51单片机12MHZ时钟下的延时函数*/
  44. void Lcd1602_Delay1ms(uint c);   //误差 0us
  45. /*LCD1602写入8位命令子函数*/
  46. void LcdWriteCom(uchar com);
  47. /*LCD1602写入8位数据子函数*/      
  48. void LcdWriteData(uchar dat)        ;
  49. /*LCD1602初始化子程序*/               
  50. void LcdInit();      
  51. /*LCD1602写入字符串*/
  52. void LCDWrite_String(uchar x, uchar y,uchar z, uchar *s);
  53. /*设置LCD1602写入字符串的位置*/
  54. void LCD_set_xy(uchar x, uchar y, uchar z);               
  55. void IntConfiguration();
  56. /*
  57. uchar ON_Hour=0x07;          //初始开灯时间  07:00                                                                   1
  58. uchar Warning_TempH=32;         //高温报警温度                                                                                   5
  59. */
  60. uchar ON_Hour;          //初始开灯时间  07:00                                                                   1
  61. uchar Warning_TempH;         //高温报警温度      
  62. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  63. 函数:主程序
  64. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  65. void main(void)
  66. {
  67.    LcdInit();
  68.    IntConfiguration();
  69. /////////////////////////////////////////////////////////////////
  70. /*
  71.    cc(0x2000);                  // 擦除第1个扇区(2000h~21FFh)
  72.    xcx(0x2000,ON_Hour);          // 对EEPROM区2002h写入2
  73.    xcx(0x2001,Warning_TempH);          // 对EEPROM区2002h写入2
  74. */
  75. /////////////////////////////////////////////////////////////////   
  76.    while(1)
  77.    {
  78.    ON_Hour = dcx(0x2000);
  79.    Warning_TempH = dcx(0x2001);
  80.    if((ON_Hour==0x07)||(Warning_TempH==32))
  81.    {
  82.            LcdWriteCom(0x80);
  83.           LCDWrite_String(0, 1, 7, "SUCCESS");
  84.    }
  85.    else
  86.    LcdWriteCom(0x80);
  87.    LCDWrite_String(0, 1, 5, "ERROR");
  88.    }
  89.    /*
  90.    uchar V;
  91.    V = dcx(0x2002);                          // 开机读取EEPROM区2002h数据,还原关电前LED的亮灭状况
  92.    if(V == 2)          {LED1=0;LED2=1;}
  93.    else if(V == 6){LED1=0;LED2=0;}
  94.    while(1)
  95.      {
  96.       if(!K1)
  97.             {
  98.               while(!K1);
  99.               LED1=0;LED2=1;
  100.               cc(0x2000);                  // 擦除第1个扇区(2000h~21FFh)
  101.               xcx(0x2002,2);          // 对EEPROM区2002h写入2
  102.             }
  103.           if(!K2)
  104.             {
  105.               while(!K2);
  106.               LED1=0;LED2=0;
  107.               cc(0x2000);                  // 擦除第1个扇区(2000h~21FFh)
  108.               xcx(0x2002,6);                          // 对EEPROM区2002h写入6
  109.             }
  110.      }
  111.          */
  112. }
  113. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  114. 函数:擦除某一扇区(每个扇区512字节)
  115. 入口:addr = 某一扇区首地址                          
  116. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  117. void cc(uint addr)
  118. {      
  119. // 打开 IAP 功能(ISP_CONTR.7)=1:允许编程改变Flash, 设置Flash操作等待时间
  120. // 0x83(晶振<5M)   0x82(晶振<10M)   0x81(晶振<20M)   0x80(晶振<40M)
  121.     ISP_CONTR = 0x81;  
  122.     ISP_CMD   = 0x03;                  // 用户可以对"Data Flash/EEPROM区"进行扇区擦除
  123.     ISP_ADDRL = addr;         // ISP/IAP操作时的地址寄存器低八位,
  124.     ISP_ADDRH = addr>>8;      // ISP/IAP操作时的地址寄存器高八位。
  125.         EA =0;   
  126.     ISP_TRIG = 0x46;          // 在ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG先写入46h,
  127.     ISP_TRIG = 0xB9;          // 再写入B9h,ISP/IAP命令才会生效。
  128.     _nop_();
  129.     Q0();                                          // 关闭ISP/IAP
  130. }
  131. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  132. 函数:写一字节
  133. 入口:addr = 扇区单元地址 , dat = 待写入数据
  134. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  135. void xcx(uint addr,uchar dat)
  136. {
  137.     ISP_CONTR = 0x81;                  
  138.     ISP_CMD   = 0x02;              // 用户可以对"Data Flash/EEPROM区"进行字节编程
  139.     ISP_ADDRL = addr;        
  140.     ISP_ADDRH = addr>>8;      
  141.     ISP_DATA  = dat;          // 数据进ISP_DATA
  142.     EA = 0;
  143.     ISP_TRIG = 0x46;         
  144.     ISP_TRIG = 0xB9;         
  145.     _nop_();
  146.     Q0();                                          // 关闭ISP/IAP
  147. }
  148. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  149. 函数:读一字节
  150. 入口:addr = 扇区单元地址
  151. 出口:dat  = 读出的数据
  152. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  153. uchar dcx(uint addr)
  154. {   
  155.     uchar dat;
  156.       
  157.         ISP_CONTR = 0x81;                  
  158.     ISP_CMD   = 0x01;         // 用户可以对"Data Flash/EEPROM区"进行字节读
  159.     ISP_ADDRL = addr;         
  160.     ISP_ADDRH = addr>>8;      
  161.     EA = 0;
  162.     ISP_TRIG = 0x46;         
  163.     ISP_TRIG = 0xB9;         
  164.     _nop_();
  165.     dat = ISP_DATA;                          // 取出数据
  166.         Q0();                                          // 关闭ISP/IAP                  
  167.         return dat;
  168. }
  169. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  170. 函数:关闭ISP/IAP操作
  171. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  172. void Q0()
  173. {
  174.     ISP_CONTR = 0;            // 关闭IAP功能
  175.     ISP_CMD   = 0;            // 待机模式,无ISP操作
  176.     ISP_TRIG  = 0;            // 关闭IAP功能, 清与ISP有关的特殊功能寄存器
  177.         EA=1;
  178. }
  179. /*
  180. STC89C52RC内部EEPROM详细地址表:
  181. 第一扇区                   第二扇区                    第三扇区                    第四扇区
  182. 起始地址  结束地址   起始地址   结束地址   起始地址   结束地址   起始地址    结束地址
  183. 2000h      21FFh       2200h       23FFh      2400h       25FFh       2600h        27FFH
  184. 第五扇区                    第六扇区                     第七扇区                    第八扇区
  185. 起始地址   结束地址   起始地址   结束地址    起始地址   结束地址   起始地址    结束地址
  186. 2800h       29FFh       2A00h      2BFFh        2C00h      2DFFh      2E00h        2FFFh
  187. */
  188. /*******************************************************************************
  189. * 函 数 名         : Lcd1602_Delay1ms
  190. * 函数功能                   : 延时函数,延时1ms
  191. * 输    入         : c
  192. * 输    出         : 无
  193. * 说    名         : 该函数是在12MHZ晶振下,12分频单片机的延时。
  194. *******************************************************************************/
  195. void Lcd1602_Delay1ms(uint c)   //误差 0us
  196. {
  197.     uchar a,b;
  198.         for (; c>0; c--)
  199.         {
  200.                  for (b=199;b>0;b--)
  201.                  {
  202.                           for(a=1;a>0;a--);
  203.                  }      
  204.         }         
  205. }
  206. /*******************************************************************************
  207. * 函 数 名         : void LCDWrite_String(uchar x, uchar y, uchar *s)
  208. * 函数功能                   : 向LCD写入一个字符串
  209. * 输    入         : x,y,*s
  210. * 输    出         : 无
  211. *******************************************************************************/
  212. void LCDWrite_String(uchar x, uchar y, uchar z, uchar *s)        //x 0~15 , y 0,1,2,3
  213. {
  214.         LCD_set_xy(x,y,z);
  215.         while(*s)
  216.         {
  217.                 LcdWriteData(*s);
  218.                 s++;
  219.         }
  220. }
  221. /*******************************************************************************
  222. * 函 数 名         : void LCD_set_xy(uchar x, uchar y,uchar z)
  223. * 函数功能                   : 指定向LCD写入字符串的位置
  224. * 输    入         : x,y,z                 //x:横坐标 y:纵坐标 z:字符串长度
  225. * 输    出         : 无
  226. *******************************************************************************/
  227. void LCD_set_xy(uchar x,uchar y,uchar z)
  228. {
  229.         uchar i;
  230.         if(y==0)
  231.         {
  232.                 LcdWriteCom(0x80+x);
  233.                 for(i=0;i<z;i++)
  234.                 {
  235.                         LcdWriteData(' ');
  236.                 }
  237.                 LcdWriteCom(0x80+x);
  238.         }
  239.         if(y==1)
  240.         {
  241.                 LcdWriteCom(0xc0+x);
  242.                 for(i=0;i<z;i++)
  243.                 {
  244.                         LcdWriteData(' ');
  245.                 }
  246.                 LcdWriteCom(0xc0+x);
  247.         }
  248.         if(y==2)
  249.         {
  250.                 LcdWriteCom(0x94+x);
  251.                 for(i=0;i<z;i++)
  252.                 {
  253.                         LcdWriteData(' ');
  254.                 }
  255.                 LcdWriteCom(0x94+x);
  256.         }
  257.         if(y==3)
  258.         {
  259.                 LcdWriteCom(0xd4+x);
  260.                 for(i=0;i<z;i++)
  261.                 {
  262.                         LcdWriteData(' ');
  263.                 }
  264.                 LcdWriteCom(0xd4+x);
  265.         }
  266. }
  267. /*******************************************************************************
  268. * 函 数 名         : LcdWriteCom
  269. * 函数功能                   : 向LCD写入一个字节的命令
  270. * 输    入         : com
  271. * 输    出         : 无
  272. *******************************************************************************/
  273. #ifndef         LCD1602_4PINS         //当没有定义这个LCD1602_4PINS时
  274. void LcdWriteCom(uchar com)          //写入命令
  275. {
  276.         LCD1602_E = 0;     //使能
  277.         LCD1602_RS = 0;           //选择发送命令
  278.         LCD1602_RW = 0;           //选择写入
  279.       
  280.         LCD1602_DATAPINS = com;     //放入命令
  281.         Lcd1602_Delay1ms(1);                //等待数据稳定
  282.         LCD1602_E = 1;                  //写入时序
  283.         Lcd1602_Delay1ms(5);          //保持时间
  284.         LCD1602_E = 0;
  285. }
  286. #else
  287. void LcdWriteCom(uchar com)          //写入命令
  288. {
  289.         LCD1602_E = 0;         //使能清零
  290.         LCD1602_RS = 0;         //选择写入命令
  291.         LCD1602_RW = 0;         //选择写入
  292.         LCD1602_DATAPINS = com;        //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
  293.         Lcd1602_Delay1ms(1);
  294.         LCD1602_E = 1;         //写入时序
  295.         Lcd1602_Delay1ms(5);
  296.         LCD1602_E = 0;
  297. //        Lcd1602_Delay1ms(1);
  298.         LCD1602_DATAPINS = com << 4; //发送低四位
  299.         Lcd1602_Delay1ms(1);
  300.         LCD1602_E = 1;         //写入时序
  301.         Lcd1602_Delay1ms(5);
  302.         LCD1602_E = 0;
  303. }
  304. #endif
  305. /*******************************************************************************
  306. * 函 数 名         : LcdWriteData
  307. * 函数功能                   : 向LCD写入一个字节的数据
  308. * 输    入         : dat
  309. * 输    出         : 无
  310. *******************************************************************************/                  
  311. #ifndef         LCD1602_4PINS                  
  312. void LcdWriteData(uchar dat)                        //写入数据
  313. {
  314.         LCD1602_E = 0;        //使能清零
  315.         LCD1602_RS = 1;        //选择输入数据
  316.         LCD1602_RW = 0;        //选择写入
  317.         LCD1602_DATAPINS = dat; //写入数据
  318.         Lcd1602_Delay1ms(1);
  319.         LCD1602_E = 1;   //写入时序
  320.         Lcd1602_Delay1ms(5);   //保持时间
  321.         LCD1602_E = 0;
  322. }
  323. #else
  324. void LcdWriteData(uchar dat)                        //写入数据
  325. {
  326.         LCD1602_E = 0;          //使能清零
  327.         LCD1602_RS = 1;          //选择写入数据
  328.         LCD1602_RW = 0;          //选择写入
  329.         LCD1602_DATAPINS = dat;        //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
  330.         Lcd1602_Delay1ms(1);
  331.         LCD1602_E = 1;          //写入时序
  332.         Lcd1602_Delay1ms(5);
  333.         LCD1602_E = 0;
  334.         LCD1602_DATAPINS = dat << 4; //写入低四位
  335.         Lcd1602_Delay1ms(1);
  336.         LCD1602_E = 1;          //写入时序
  337.         Lcd1602_Delay1ms(5);
  338.         LCD1602_E = 0;
  339. }
  340. #endif
  341. /*******************************************************************************
  342. * 函 数 名       : LcdInit()
  343. * 函数功能                 : 初始化LCD屏
  344. * 输    入       : 无
  345. * 输    出       : 无
  346. *******************************************************************************/                  
  347. #ifndef                LCD1602_4PINS
  348. void LcdInit()                                                  //LCD初始化子程序
  349. {
  350.         LcdWriteCom(0x38);  //开显示
  351.         LcdWriteCom(0x0c);  //开显示不显示光标
  352.         LcdWriteCom(0x06);  //写一个指针加1
  353.         LcdWriteCom(0x01);  //清屏
  354.         LcdWriteCom(0x80);  //设置数据指针起点
  355. }
  356. #else
  357. void LcdInit()                                                  //LCD初始化子程序
  358. {
  359.         LcdWriteCom(0x32);         //将8位总线转为4位总线
  360.         LcdWriteCom(0x28);         //在四位线下的初始化
  361.         LcdWriteCom(0x0c);  //开显示不显示光标
  362.         LcdWriteCom(0x06);  //写一个指针加1
  363.         LcdWriteCom(0x01);  //清屏
  364.         LcdWriteCom(0x80);  //设置数据指针起点
  365. }
  366. #endif
  367. void IntConfiguration()
  368. {
  369.         //设置INT0
  370.         IT0=1;//跳变沿出发方式(下降沿)
  371.         EX0=1;//打开INT0的中断允许。
  372.         //设置INT1
  373.         IT1=1;//跳变沿出发方式(下降沿)
  374.         EX1=1;//打开INT0的中断允许。
  375.         EA=1;//打开总中断      
  376. }
  377. void Int0() interrupt 1                 
  378. {
  379.    cc(0x2000);                  // 擦除第1个扇区(2000h~21FFh)
  380.    xcx(0x2000,0x07);          // 对EEPROM区2002h写入2
  381.    xcx(0x2001,32);
  382.    LcdInit();
  383. }
  384. void Int1() interrupt 2                 
  385. {
  386.    cc(0x2000);                  // 擦除第1个扇区(2000h~21FFh)
  387.    xcx(0x2000,0x08);          // 对EEPROM区2002h写入2
  388.    xcx(0x2001,33);
  389.    LcdInit();
  390. }
复制代码
163702u7rzlq1j88ibczbl.png
全部资料下载地址:
51单片机读写内部EEPROM详解.rar (101.88 KB, 下载次数: 361)

评分

参与人数 3黑币 +13 收起 理由
小白来报到 + 5 很给力!
phoebejeva + 5 赞一个!
sy333 + 3 赞一个!

查看全部评分

回复

使用道具 举报

ID:19123 发表于 2017-3-31 09:42 | 显示全部楼层
好好学习,天天向上
回复

使用道具 举报

ID:135253 发表于 2017-7-22 07:57 | 显示全部楼层
楼主好样的,多谢,学习一下
回复

使用道具 举报

ID:151834 发表于 2017-7-29 15:25 | 显示全部楼层
刚刚学到这里,学习了.
回复

使用道具 举报

ID:37147 发表于 2017-11-21 15:12 | 显示全部楼层
结合我看的资料,你的程序易懂!!!
回复

使用道具 举报

ID:247307 发表于 2018-4-19 22:08 | 显示全部楼层
感谢楼主
回复

使用道具 举报

ID:376438 发表于 2018-8-15 14:09 | 显示全部楼层
谢谢了!,学习一下
回复

使用道具 举报

ID:479915 发表于 2019-3-20 23:40 | 显示全部楼层
好好学习
回复

使用道具 举报

ID:308951 发表于 2019-3-21 08:31 | 显示全部楼层
代码很好,内容十分详细,已经借鉴
回复

使用道具 举报

ID:495323 发表于 2019-3-22 19:06 | 显示全部楼层
有点复杂,51芯片手册上面有
回复

使用道具 举报

ID:382454 发表于 2019-4-9 10:59 | 显示全部楼层
谢谢,我还是看看手册,刚学写EEPROM。头好晕啊。
回复

使用道具 举报

ID:496304 发表于 2019-4-28 11:09 | 显示全部楼层
学习学习
回复

使用道具 举报

ID:517794 发表于 2019-4-28 15:20 | 显示全部楼层
正需要呢 ,谢谢 !
回复

使用道具 举报

ID:339320 发表于 2019-5-16 14:59 | 显示全部楼层
好东西。谢谢分享。
回复

使用道具 举报

ID:543352 发表于 2019-5-20 23:15 来自手机 | 显示全部楼层
好东西,收藏了
回复

使用道具 举报

ID:403027 发表于 2019-5-21 17:06 | 显示全部楼层
很给力!!!!!
回复

使用道具 举报

ID:538501 发表于 2019-6-5 14:42 | 显示全部楼层
谢谢楼主,学习了
回复

使用道具 举报

ID:379335 发表于 2019-6-27 19:32 | 显示全部楼层
感谢楼主发布 学习了
回复

使用道具 举报

ID:313854 发表于 2019-6-28 15:06 | 显示全部楼层
谢谢分享,好资料
回复

使用道具 举报

ID:578706 发表于 2019-8-24 14:34 | 显示全部楼层
可以可以
回复

使用道具 举报

ID:628823 发表于 2019-11-1 11:27 | 显示全部楼层
资料不错,谢谢!
回复

使用道具 举报

ID:434663 发表于 2019-11-13 22:51 | 显示全部楼层
我必须对你提出表扬和感谢,程序简单易懂,注释详细!
谢谢你的无私奉献!
回复

使用道具 举报

ID:636592 发表于 2019-11-18 11:55 | 显示全部楼层
学习了~
回复

使用道具 举报

ID:387697 发表于 2020-3-16 17:37 | 显示全部楼层
给力!
回复

使用道具 举报

ID:721764 发表于 2020-4-16 17:21 | 显示全部楼层
墙都不服,就服你
回复

使用道具 举报

ID:402026 发表于 2020-4-19 22:26 | 显示全部楼层
这个程序比较符合初学者,注解很仔细,很细心,真的很不错,感谢你。
回复

使用道具 举报

ID:718783 发表于 2020-4-21 13:04 | 显示全部楼层
谢谢楼主,真心不错
回复

使用道具 举报

ID:502124 发表于 2022-12-12 10:13 | 显示全部楼层
51单片机读写内部EEPROM详解
http://www.51hei.com/bbs/dpj-80082-1.html
(出处: http://www.51hei.com/bbs/)
回复

使用道具 举报

ID:1011444 发表于 2023-5-18 00:01 | 显示全部楼层
点赞一个,三个例子说的详细,学习了。
回复

使用道具 举报

ID:641483 发表于 2023-5-22 11:56 | 显示全部楼层
收藏了 谢谢楼主 写的很详细 感觉自己能看懂         很给力!
回复

使用道具 举报

ID:891089 发表于 2023-6-25 14:25 来自手机 | 显示全部楼层
谢谢好兄弟,问题解决了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表