单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 19814|回复: 18
打印 上一主题 下一主题
收起左侧

51单片机读写内部EEPROM详解

  [复制链接]
跳转到指定楼层
楼主
此文档共包含三个程序。

第一个程序最简单易懂,看懂了基本就会读写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. }
复制代码

全部资料下载地址:
51单片机读写内部EEPROM详解.rar (101.88 KB, 下载次数: 159)


评分

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

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏8 转播转播 分享分享2 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
liujueshen 发表于 2017-3-31 09:42 | 只看该作者
好好学习,天天向上
回复

使用道具 举报

板凳
xzf586 发表于 2017-7-22 07:57 | 只看该作者
楼主好样的,多谢,学习一下
回复

使用道具 举报

地板
文龙 发表于 2017-7-29 15:25 | 只看该作者
刚刚学到这里,学习了.
回复

使用道具 举报

5#
周鹏 发表于 2017-11-21 15:12 | 只看该作者
结合我看的资料,你的程序易懂!!!
回复

使用道具 举报

6#
飞跃吧 发表于 2018-4-19 22:08 | 只看该作者
感谢楼主
回复

使用道具 举报

7#
eeadad 发表于 2018-8-15 14:09 | 只看该作者
谢谢了!,学习一下
回复

使用道具 举报

8#
zzzzzkevin 发表于 2019-3-20 23:40 | 只看该作者
好好学习
回复

使用道具 举报

9#
jwl595 发表于 2019-3-21 08:31 | 只看该作者
代码很好,内容十分详细,已经借鉴
回复

使用道具 举报

10#
有心插花花木兰 发表于 2019-3-22 19:06 | 只看该作者
有点复杂,51芯片手册上面有
回复

使用道具 举报

11#
univers 发表于 2019-4-9 10:59 | 只看该作者
谢谢,我还是看看手册,刚学写EEPROM。头好晕啊。
回复

使用道具 举报

12#
白歌 发表于 2019-4-28 11:09 | 只看该作者
学习学习
回复

使用道具 举报

13#
13534702358 发表于 2019-4-28 15:20 | 只看该作者
正需要呢 ,谢谢 !
回复

使用道具 举报

14#
aiwenxue999 发表于 2019-5-16 14:59 | 只看该作者
好东西。谢谢分享。
回复

使用道具 举报

15#
13798559800 发表于 2019-5-20 23:15 来自手机 | 只看该作者
好东西,收藏了
回复

使用道具 举报

16#
ben0147 发表于 2019-5-21 17:06 | 只看该作者
很给力!!!!!
回复

使用道具 举报

17#
LIUSUSHUAI 发表于 2019-6-5 14:42 | 只看该作者
谢谢楼主,学习了
回复

使用道具 举报

18#
宗遥 发表于 2019-6-27 19:32 | 只看该作者
感谢楼主发布 学习了
回复

使用道具 举报

19#
wspytu 发表于 2019-6-28 15:06 | 只看该作者
谢谢分享,好资料
回复

使用道具 举报

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

本版积分规则

QQ|手机版|小黑屋|单片机论坛 |51黑电子论坛单片机 联系QQ:125739409;技术交流QQ群582644647

Powered by 单片机教程网

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