久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

標題: 51單片機讀寫內部EEPROM詳解 [打印本頁]

作者: 854100995    時間: 2017-3-29 16:11
標題: 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, 下載次數: 364)



作者: liujueshen    時間: 2017-3-31 09:42
好好學習,天天向上
作者: xzf586    時間: 2017-7-22 07:57
樓主好樣的,多謝,學習一下
作者: 文龍    時間: 2017-7-29 15:25
剛剛學到這里,學習了.
作者: 周鵬    時間: 2017-11-21 15:12
結合我看的資料,你的程序易懂!!!
作者: 飛躍吧    時間: 2018-4-19 22:08
感謝樓主

作者: eeadad    時間: 2018-8-15 14:09
謝謝了!,學習一下
作者: zzzzzkevin    時間: 2019-3-20 23:40
好好學習
作者: jwl595    時間: 2019-3-21 08:31
代碼很好,內容十分詳細,已經借鑒
作者: 有心插花花木蘭    時間: 2019-3-22 19:06
有點復雜,51芯片手冊上面有
作者: univers    時間: 2019-4-9 10:59
謝謝,我還是看看手冊,剛學寫EEPROM。頭好暈啊。
作者: 白歌    時間: 2019-4-28 11:09
學習學習
作者: 13534702358    時間: 2019-4-28 15:20
正需要呢 ,謝謝 !
作者: aiwenxue999    時間: 2019-5-16 14:59
好東西。謝謝分享。
作者: 13798559800    時間: 2019-5-20 23:15
好東西,收藏了
作者: ben0147    時間: 2019-5-21 17:06
很給力!!!!!
作者: LIUSUSHUAI    時間: 2019-6-5 14:42
謝謝樓主,學習了
作者: 宗遙    時間: 2019-6-27 19:32
感謝樓主發布 學習了
作者: wspytu    時間: 2019-6-28 15:06
謝謝分享,好資料
作者: 時之沙丶流年    時間: 2019-8-24 14:34
可以可以
作者: zhouxianen    時間: 2019-11-1 11:27
資料不錯,謝謝!
作者: rsurb0371    時間: 2019-11-13 22:51
我必須對你提出表揚和感謝,程序簡單易懂,注釋詳細!
謝謝你的無私奉獻!
作者: 風暴之靈1022    時間: 2019-11-18 11:55
學習了~
作者: 好學007    時間: 2020-3-16 17:37
給力!
作者: coffeepod    時間: 2020-4-16 17:21
墻都不服,就服你
作者: zbfdyw    時間: 2020-4-19 22:26
這個程序比較符合初學者,注解很仔細,很細心,真的很不錯,感謝你。
作者: liangsheng0212    時間: 2020-4-21 13:04
謝謝樓主,真心不錯
作者: 15857778517    時間: 2022-12-12 10:13
51單片機讀寫內部EEPROM詳解
http://www.zg4o1577.cn/bbs/dpj-80082-1.html
(出處: http://www.zg4o1577.cn/bbs/)

作者: kz0018    時間: 2023-5-18 00:01
點贊一個,三個例子說的詳細,學習了。
作者: Q__Q    時間: 2023-5-22 11:56
收藏了 謝謝樓主 寫的很詳細 感覺自己能看懂         很給力!
作者: 美琴的備胎    時間: 2023-6-25 14:25
謝謝好兄弟,問題解決了




歡迎光臨 (http://www.zg4o1577.cn/bbs/) Powered by Discuz! X3.1
主站蜘蛛池模板: 午夜精品久久久久久久久久久久久 | 二区视频| 国产精品国产三级国产aⅴ浪潮 | 一级毛片免费视频观看 | 天堂精品视频 | 国产精品久久精品 | 欧美日韩1区 | 国产精品美女久久久av超清 | 午夜小视频在线播放 | 在线精品观看 | 亚州午夜精品 | 国产福利资源在线 | 欧美精品一区二区在线观看 | 成人蜜桃av| 成人在线欧美 | 天堂综合网 | 米奇7777狠狠狠狠视频 | 国产黄色大片在线免费观看 | 国产日韩一区二区 | 免费国产一区 | 亚洲精品一区二区三区蜜桃久 | 国产成人免费一区二区60岁 | 蜜桃在线视频 | 国产视频在线一区二区 | 国产精品久久久久免费 | 国产精品a一区二区三区网址 | 日本精品视频一区二区三区四区 | 中文字幕一二三区 | 亚洲一区在线日韩在线深爱 | 日朝毛片 | 日韩中文字幕一区二区 | 久久综合香蕉 | 在线播放国产一区二区三区 | 一区二区免费在线观看 | 热re99久久精品国产99热 | 青青久久av北条麻妃海外网 | 999久久久 | 国产日韩欧美精品一区二区 | 在线观看免费av网 | 国产亚洲人成a在线v网站 | 天天噜天天干 |