此文檔共包含三個程序。
第一個程序最簡單易懂,看懂了基本就會讀寫51單片機內部EEPROM了。
第二個程序和第一個讀寫EEPROM原理差不多,包含有LCD1602操作方法,有寫字符串的方法。
第三個程序在原有基礎上增加了外部中斷功能,細心的人會發(fā)現,操作內部EEPROM過程會將總中斷關閉,實際上程序要用到中斷時只需在原有的EEPROM操作后加上開總中斷即可。
驗證第二、第三個程序時需按程序內主程序中的操作說明進行燒錄單片機,以驗證是否成功操作單片機內部EEPROM。
程序1: - /***************************************************************
- 作品:EEPROM實驗,開機還原關電前LED的亮滅狀況
- 單片機:STC89C52RC
- 晶振:12M
- 編譯環(huán)境:Keil uVision4 V9.00
- ***************************************************************/
- //#include <STC89C52RC.H>
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- /****************特殊功能寄存器聲明****************/
- sfr ISP_DATA = 0xe2;
- sfr ISP_ADDRH = 0xe3;
- sfr ISP_ADDRL = 0xe4;
- sfr ISP_CMD = 0xe5;
- sfr ISP_TRIG = 0xe6;
- sfr ISP_CONTR = 0xe7;
- sbit LED1 = P2^0;
- sbit LED2 = P2^1;
- sbit K1 = P3^2; //按鈕1
- sbit K2 = P3^3; //按鈕2
- void cc(uint addr);
- void xcx(uint addr,uchar dat);
- uchar dcx(uint addr);
- void Q0();
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:主程序
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- /*
- void main(void)
- {
- uchar V;
- V = dcx(0x2002); // 開機讀取EEPROM區(qū)2002h數據,還原關電前LED的亮滅狀況
- if(V == 2) {LED1=0;LED2=1;}
- else if(V == 6){LED1=0;LED2=0;}
- while(1)
- {
- if(!K1)
- {
- while(!K1);
- LED1=0;LED2=1;
- cc(0x2000); // 擦除第1個扇區(qū)(2000h~21FFh)
- xcx(0x2002,2); // 對EEPROM區(qū)2002h寫入2
- }
- if(!K2)
- {
- while(!K2);
- LED1=0;LED2=0;
- cc(0x2000); // 擦除第1個扇區(qū)(2000h~21FFh)
- xcx(0x2002,6); // 對EEPROM區(qū)2002h寫入6
- }
- }
- }
- */
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:擦除某一扇區(qū)(每個扇區(qū)512字節(jié))
- 入口:addr = 某一扇區(qū)首地址
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void cc(uint addr)
- {
- // 打開 IAP 功能(ISP_CONTR.7)=1:允許編程改變Flash, 設置Flash操作等待時間
- // 0x83(晶振<5M) 0x82(晶振<10M) 0x81(晶振<20M) 0x80(晶振<40M)
- ISP_CONTR = 0x81;
- ISP_CMD = 0x03; // 用戶可以對"Data Flash/EEPROM區(qū)"進行扇區(qū)擦除
- ISP_ADDRL = addr; // ISP/IAP操作時的地址寄存器低八位,
- ISP_ADDRH = addr>>8; // ISP/IAP操作時的地址寄存器高八位。
- EA =0;
- ISP_TRIG = 0x46; // 在ISPEN(ISP_CONTR.7)=1時,對ISP_TRIG先寫入46h,
- ISP_TRIG = 0xB9; // 再寫入B9h,ISP/IAP命令才會生效。
- _nop_();
- Q0(); // 關閉ISP/IAP
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:寫一字節(jié)
- 入口:addr = 扇區(qū)單元地址 , dat = 待寫入數據
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void xcx(uint addr,uchar dat)
- {
- ISP_CONTR = 0x81;
- ISP_CMD = 0x02; // 用戶可以對"Data Flash/EEPROM區(qū)"進行字節(jié)編程
- ISP_ADDRL = addr;
- ISP_ADDRH = addr>>8;
- ISP_DATA = dat; // 數據進ISP_DATA
- EA = 0;
- ISP_TRIG = 0x46;
- ISP_TRIG = 0xB9;
- _nop_();
- Q0(); // 關閉ISP/IAP
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:讀一字節(jié)
- 入口:addr = 扇區(qū)單元地址
- 出口:dat = 讀出的數據
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- uchar dcx(uint addr)
- {
- uchar dat;
-
- ISP_CONTR = 0x81;
- ISP_CMD = 0x01; // 用戶可以對"Data Flash/EEPROM區(qū)"進行字節(jié)讀
- ISP_ADDRL = addr;
- ISP_ADDRH = addr>>8;
- EA = 0;
- ISP_TRIG = 0x46;
- ISP_TRIG = 0xB9;
- _nop_();
- dat = ISP_DATA; // 取出數據
- Q0(); // 關閉ISP/IAP
- return dat;
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:關閉ISP/IAP操作
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void Q0()
- {
- ISP_CONTR = 0; // 關閉IAP功能
- ISP_CMD = 0; // 待機模式,無ISP操作
- ISP_TRIG = 0; // 關閉IAP功能, 清與ISP有關的特殊功能寄存器
- }
- /*
- STC89C52RC內部EEPROM詳細地址表:
- 第一扇區(qū) 第二扇區(qū) 第三扇區(qū) 第四扇區(qū)
- 起始地址 結束地址 起始地址 結束地址 起始地址 結束地址 起始地址 結束地址
- 2000h 21FFh 2200h 23FFh 2400h 25FFh 2600h 27FFH
- 第五扇區(qū) 第六扇區(qū) 第七扇區(qū) 第八扇區(qū)
- 起始地址 結束地址 起始地址 結束地址 起始地址 結束地址 起始地址 結束地址
- 2800h 29FFh 2A00h 2BFFh 2C00h 2DFFh 2E00h 2FFFh
- */
復制代碼
程序2: - /***************************************************************
- 作品:EEPROM實驗,開機還原關電前LED的亮滅狀況
- 單片機:STC89C52RC
- 晶振:12M
- 編譯環(huán)境:Keil uVision4 V9.00
- ***************************************************************/
- //#include <STC89C52RC.H>
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- /****************特殊功能寄存器聲明****************/
- sfr ISP_DATA = 0xe2;
- sfr ISP_ADDRH = 0xe3;
- sfr ISP_ADDRL = 0xe4;
- sfr ISP_CMD = 0xe5;
- sfr ISP_TRIG = 0xe6;
- sfr ISP_CONTR = 0xe7;
- sbit LED1 = P2^0;
- sbit LED2 = P2^1;
- sbit K1 = P3^2; //按鈕1
- sbit K2 = P3^3; //按鈕2
- void cc(uint addr);
- void xcx(uint addr,uchar dat);
- uchar dcx(uint addr);
- void Q0();
- #ifndef uchar
- #define uchar unsigned char
- #endif
- #ifndef uint
- #define uint unsigned int
- #endif
- /**********************************
- PIN口定義
- **********************************/
- #define LCD1602_DATAPINS P0
- sbit LCD1602_E=P2^7;
- sbit LCD1602_RW=P2^5;
- sbit LCD1602_RS=P2^6;
- /**********************************
- 函數聲明
- **********************************/
- /*在51單片機12MHZ時鐘下的延時函數*/
- void Lcd1602_Delay1ms(uint c); //誤差 0us
- /*LCD1602寫入8位命令子函數*/
- void LcdWriteCom(uchar com);
- /*LCD1602寫入8位數據子函數*/
- void LcdWriteData(uchar dat) ;
- /*LCD1602初始化子程序*/
- void LcdInit();
- /*LCD1602寫入字符串*/
- void LCDWrite_String(uchar x, uchar y,uchar z, uchar *s);
- /*設置LCD1602寫入字符串的位置*/
- void LCD_set_xy(uchar x, uchar y, uchar z);
- uchar ON_Hour=0x07; //初始開燈時間 07:00 1
- uchar Warning_TempH=32; //高溫報警溫度 5
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:主程序
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- /*
- void main(void)
- {
- uchar V;
- V = dcx(0x2002); // 開機讀取EEPROM區(qū)2002h數據,還原關電前LED的亮滅狀況
- if(V == 2) {LED1=0;LED2=1;}
- else if(V == 6){LED1=0;LED2=0;}
- while(1)
- {
- if(!K1)
- {
- while(!K1);
- LED1=0;LED2=1;
- cc(0x2000); // 擦除第1個扇區(qū)(2000h~21FFh)
- xcx(0x2002,2); // 對EEPROM區(qū)2002h寫入2
- }
- if(!K2)
- {
- while(!K2);
- LED1=0;LED2=0;
- cc(0x2000); // 擦除第1個扇區(qū)(2000h~21FFh)
- xcx(0x2002,6); // 對EEPROM區(qū)2002h寫入6
- }
- }
- }
- */
- void main(void)
- {
- LcdInit();
- //不注銷下面三句,燒錄一次
- //注銷小面三句,再燒錄一次
- //若兩次燒錄后現象一致,則操作內部EEPROM成功
- /////////////////////////////////////////////////////////////////
- cc(0x2000); // 擦除第1個扇區(qū)(2000h~21FFh)
- xcx(0x2000,ON_Hour); // 對EEPROM區(qū)2002h寫入2
- xcx(0x2001,Warning_TempH); // 對EEPROM區(qū)2002h寫入2
- /////////////////////////////////////////////////////////////////
- ON_Hour = dcx(0x2000);
- Warning_TempH = dcx(0x2001);
- if((ON_Hour==0x07)||(Warning_TempH==32))
- {
- LcdWriteCom(0x80);
- LCDWrite_String(0, 1, 7, "SUCCESS");
- }
- else
- LCDWrite_String(0, 1, 5, "ERROR");
- while(1);
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:擦除某一扇區(qū)(每個扇區(qū)512字節(jié))
- 入口:addr = 某一扇區(qū)首地址
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void cc(uint addr)
- {
- // 打開 IAP 功能(ISP_CONTR.7)=1:允許編程改變Flash, 設置Flash操作等待時間
- // 0x83(晶振<5M) 0x82(晶振<10M) 0x81(晶振<20M) 0x80(晶振<40M)
- ISP_CONTR = 0x81;
- ISP_CMD = 0x03; // 用戶可以對"Data Flash/EEPROM區(qū)"進行扇區(qū)擦除
- ISP_ADDRL = addr; // ISP/IAP操作時的地址寄存器低八位,
- ISP_ADDRH = addr>>8; // ISP/IAP操作時的地址寄存器高八位。
- EA =0;
- ISP_TRIG = 0x46; // 在ISPEN(ISP_CONTR.7)=1時,對ISP_TRIG先寫入46h,
- ISP_TRIG = 0xB9; // 再寫入B9h,ISP/IAP命令才會生效。
- _nop_();
- Q0(); // 關閉ISP/IAP
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:寫一字節(jié)
- 入口:addr = 扇區(qū)單元地址 , dat = 待寫入數據
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void xcx(uint addr,uchar dat)
- {
- ISP_CONTR = 0x81;
- ISP_CMD = 0x02; // 用戶可以對"Data Flash/EEPROM區(qū)"進行字節(jié)編程
- ISP_ADDRL = addr;
- ISP_ADDRH = addr>>8;
- ISP_DATA = dat; // 數據進ISP_DATA
- EA = 0;
- ISP_TRIG = 0x46;
- ISP_TRIG = 0xB9;
- _nop_();
- Q0(); // 關閉ISP/IAP
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:讀一字節(jié)
- 入口:addr = 扇區(qū)單元地址
- 出口:dat = 讀出的數據
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- uchar dcx(uint addr)
- {
- uchar dat;
-
- ISP_CONTR = 0x81;
- ISP_CMD = 0x01; // 用戶可以對"Data Flash/EEPROM區(qū)"進行字節(jié)讀
- ISP_ADDRL = addr;
- ISP_ADDRH = addr>>8;
- EA = 0;
- ISP_TRIG = 0x46;
- ISP_TRIG = 0xB9;
- _nop_();
- dat = ISP_DATA; // 取出數據
- Q0(); // 關閉ISP/IAP
- return dat;
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:關閉ISP/IAP操作
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void Q0()
- {
- ISP_CONTR = 0; // 關閉IAP功能
- ISP_CMD = 0; // 待機模式,無ISP操作
- ISP_TRIG = 0; // 關閉IAP功能, 清與ISP有關的特殊功能寄存器
- }
- /*
- STC89C52RC內部EEPROM詳細地址表:
- 第一扇區(qū) 第二扇區(qū) 第三扇區(qū) 第四扇區(qū)
- 起始地址 結束地址 起始地址 結束地址 起始地址 結束地址 起始地址 結束地址
- 2000h 21FFh 2200h 23FFh 2400h 25FFh 2600h 27FFH
- 第五扇區(qū) 第六扇區(qū) 第七扇區(qū) 第八扇區(qū)
- 起始地址 結束地址 起始地址 結束地址 起始地址 結束地址 起始地址 結束地址
- 2800h 29FFh 2A00h 2BFFh 2C00h 2DFFh 2E00h 2FFFh
- */
- /*******************************************************************************
- * 函 數 名 : Lcd1602_Delay1ms
- * 函數功能 : 延時函數,延時1ms
- * 輸 入 : c
- * 輸 出 : 無
- * 說 名 : 該函數是在12MHZ晶振下,12分頻單片機的延時。
- *******************************************************************************/
- void Lcd1602_Delay1ms(uint c) //誤差 0us
- {
- uchar a,b;
- for (; c>0; c--)
- {
- for (b=199;b>0;b--)
- {
- for(a=1;a>0;a--);
- }
- }
- }
- /*******************************************************************************
- * 函 數 名 : void LCDWrite_String(uchar x, uchar y, uchar *s)
- * 函數功能 : 向LCD寫入一個字符串
- * 輸 入 : x,y,*s
- * 輸 出 : 無
- *******************************************************************************/
- void LCDWrite_String(uchar x, uchar y, uchar z, uchar *s) //x 0~15 , y 0,1,2,3
- {
- LCD_set_xy(x,y,z);
- while(*s)
- {
- LcdWriteData(*s);
- s++;
- }
- }
- /*******************************************************************************
- * 函 數 名 : void LCD_set_xy(uchar x, uchar y,uchar z)
- * 函數功能 : 指定向LCD寫入字符串的位置
- * 輸 入 : x,y,z //x:橫坐標 y:縱坐標 z:字符串長度
- * 輸 出 : 無
- *******************************************************************************/
- void LCD_set_xy(uchar x,uchar y,uchar z)
- {
- uchar i;
- if(y==0)
- {
- LcdWriteCom(0x80+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0x80+x);
- }
- if(y==1)
- {
- LcdWriteCom(0xc0+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0xc0+x);
- }
- if(y==2)
- {
- LcdWriteCom(0x94+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0x94+x);
- }
- if(y==3)
- {
- LcdWriteCom(0xd4+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0xd4+x);
- }
- }
- /*******************************************************************************
- * 函 數 名 : LcdWriteCom
- * 函數功能 : 向LCD寫入一個字節(jié)的命令
- * 輸 入 : com
- * 輸 出 : 無
- *******************************************************************************/
- #ifndef LCD1602_4PINS //當沒有定義這個LCD1602_4PINS時
- void LcdWriteCom(uchar com) //寫入命令
- {
- LCD1602_E = 0; //使能
- LCD1602_RS = 0; //選擇發(fā)送命令
- LCD1602_RW = 0; //選擇寫入
-
- LCD1602_DATAPINS = com; //放入命令
- Lcd1602_Delay1ms(1); //等待數據穩(wěn)定
- LCD1602_E = 1; //寫入時序
- Lcd1602_Delay1ms(5); //保持時間
- LCD1602_E = 0;
- }
- #else
- void LcdWriteCom(uchar com) //寫入命令
- {
- LCD1602_E = 0; //使能清零
- LCD1602_RS = 0; //選擇寫入命令
- LCD1602_RW = 0; //選擇寫入
- LCD1602_DATAPINS = com; //由于4位的接線是接到P0口的高四位,所以傳送高四位不用改
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //寫入時序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- // Lcd1602_Delay1ms(1);
- LCD1602_DATAPINS = com << 4; //發(fā)送低四位
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //寫入時序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- }
- #endif
- /*******************************************************************************
- * 函 數 名 : LcdWriteData
- * 函數功能 : 向LCD寫入一個字節(jié)的數據
- * 輸 入 : dat
- * 輸 出 : 無
- *******************************************************************************/
- #ifndef LCD1602_4PINS
- void LcdWriteData(uchar dat) //寫入數據
- {
- LCD1602_E = 0; //使能清零
- LCD1602_RS = 1; //選擇輸入數據
- LCD1602_RW = 0; //選擇寫入
- LCD1602_DATAPINS = dat; //寫入數據
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //寫入時序
- Lcd1602_Delay1ms(5); //保持時間
- LCD1602_E = 0;
- }
- #else
- void LcdWriteData(uchar dat) //寫入數據
- {
- LCD1602_E = 0; //使能清零
- LCD1602_RS = 1; //選擇寫入數據
- LCD1602_RW = 0; //選擇寫入
- LCD1602_DATAPINS = dat; //由于4位的接線是接到P0口的高四位,所以傳送高四位不用改
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //寫入時序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- LCD1602_DATAPINS = dat << 4; //寫入低四位
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //寫入時序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- }
- #endif
- /*******************************************************************************
- * 函 數 名 : LcdInit()
- * 函數功能 : 初始化LCD屏
- * 輸 入 : 無
- * 輸 出 : 無
- *******************************************************************************/
- #ifndef LCD1602_4PINS
- void LcdInit() //LCD初始化子程序
- {
- LcdWriteCom(0x38); //開顯示
- LcdWriteCom(0x0c); //開顯示不顯示光標
- LcdWriteCom(0x06); //寫一個指針加1
- LcdWriteCom(0x01); //清屏
- LcdWriteCom(0x80); //設置數據指針起點
- }
- #else
- void LcdInit() //LCD初始化子程序
- {
- LcdWriteCom(0x32); //將8位總線轉為4位總線
- LcdWriteCom(0x28); //在四位線下的初始化
- LcdWriteCom(0x0c); //開顯示不顯示光標
- LcdWriteCom(0x06); //寫一個指針加1
- LcdWriteCom(0x01); //清屏
- LcdWriteCom(0x80); //設置數據指針起點
- }
- #endif
復制代碼
程序3: - /***************************************************************
- 作品:EEPROM實驗,開機還原關電前LED的亮滅狀況
- 單片機:STC89C52RC
- 晶振:12M
- 編譯環(huán)境:Keil uVision4 V9.00
- ***************************************************************/
- //#include <STC89C52RC.H>
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- /****************特殊功能寄存器聲明****************/
- sfr ISP_DATA = 0xe2;
- sfr ISP_ADDRH = 0xe3;
- sfr ISP_ADDRL = 0xe4;
- sfr ISP_CMD = 0xe5;
- sfr ISP_TRIG = 0xe6;
- sfr ISP_CONTR = 0xe7;
- sbit LED1 = P2^0;
- sbit LED2 = P2^1;
- sbit K1 = P3^2; //按鈕1
- sbit K2 = P3^3; //按鈕2
- void cc(uint addr);
- void xcx(uint addr,uchar dat);
- uchar dcx(uint addr);
- void Q0();
- #ifndef uchar
- #define uchar unsigned char
- #endif
- #ifndef uint
- #define uint unsigned int
- #endif
- /**********************************
- PIN口定義
- **********************************/
- #define LCD1602_DATAPINS P0
- sbit LCD1602_E=P2^7;
- sbit LCD1602_RW=P2^5;
- sbit LCD1602_RS=P2^6;
- /**********************************
- 函數聲明
- **********************************/
- /*在51單片機12MHZ時鐘下的延時函數*/
- void Lcd1602_Delay1ms(uint c); //誤差 0us
- /*LCD1602寫入8位命令子函數*/
- void LcdWriteCom(uchar com);
- /*LCD1602寫入8位數據子函數*/
- void LcdWriteData(uchar dat) ;
- /*LCD1602初始化子程序*/
- void LcdInit();
- /*LCD1602寫入字符串*/
- void LCDWrite_String(uchar x, uchar y,uchar z, uchar *s);
- /*設置LCD1602寫入字符串的位置*/
- void LCD_set_xy(uchar x, uchar y, uchar z);
- void IntConfiguration();
- /*
- uchar ON_Hour=0x07; //初始開燈時間 07:00 1
- uchar Warning_TempH=32; //高溫報警溫度 5
- */
- uchar ON_Hour; //初始開燈時間 07:00 1
- uchar Warning_TempH; //高溫報警溫度
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:主程序
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void main(void)
- {
- LcdInit();
- IntConfiguration();
- /////////////////////////////////////////////////////////////////
- /*
- cc(0x2000); // 擦除第1個扇區(qū)(2000h~21FFh)
- xcx(0x2000,ON_Hour); // 對EEPROM區(qū)2002h寫入2
- xcx(0x2001,Warning_TempH); // 對EEPROM區(qū)2002h寫入2
- */
- /////////////////////////////////////////////////////////////////
- while(1)
- {
- ON_Hour = dcx(0x2000);
- Warning_TempH = dcx(0x2001);
- if((ON_Hour==0x07)||(Warning_TempH==32))
- {
- LcdWriteCom(0x80);
- LCDWrite_String(0, 1, 7, "SUCCESS");
- }
- else
- LcdWriteCom(0x80);
- LCDWrite_String(0, 1, 5, "ERROR");
- }
- /*
- uchar V;
- V = dcx(0x2002); // 開機讀取EEPROM區(qū)2002h數據,還原關電前LED的亮滅狀況
- if(V == 2) {LED1=0;LED2=1;}
- else if(V == 6){LED1=0;LED2=0;}
- while(1)
- {
- if(!K1)
- {
- while(!K1);
- LED1=0;LED2=1;
- cc(0x2000); // 擦除第1個扇區(qū)(2000h~21FFh)
- xcx(0x2002,2); // 對EEPROM區(qū)2002h寫入2
- }
- if(!K2)
- {
- while(!K2);
- LED1=0;LED2=0;
- cc(0x2000); // 擦除第1個扇區(qū)(2000h~21FFh)
- xcx(0x2002,6); // 對EEPROM區(qū)2002h寫入6
- }
- }
- */
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:擦除某一扇區(qū)(每個扇區(qū)512字節(jié))
- 入口:addr = 某一扇區(qū)首地址
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void cc(uint addr)
- {
- // 打開 IAP 功能(ISP_CONTR.7)=1:允許編程改變Flash, 設置Flash操作等待時間
- // 0x83(晶振<5M) 0x82(晶振<10M) 0x81(晶振<20M) 0x80(晶振<40M)
- ISP_CONTR = 0x81;
- ISP_CMD = 0x03; // 用戶可以對"Data Flash/EEPROM區(qū)"進行扇區(qū)擦除
- ISP_ADDRL = addr; // ISP/IAP操作時的地址寄存器低八位,
- ISP_ADDRH = addr>>8; // ISP/IAP操作時的地址寄存器高八位。
- EA =0;
- ISP_TRIG = 0x46; // 在ISPEN(ISP_CONTR.7)=1時,對ISP_TRIG先寫入46h,
- ISP_TRIG = 0xB9; // 再寫入B9h,ISP/IAP命令才會生效。
- _nop_();
- Q0(); // 關閉ISP/IAP
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:寫一字節(jié)
- 入口:addr = 扇區(qū)單元地址 , dat = 待寫入數據
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void xcx(uint addr,uchar dat)
- {
- ISP_CONTR = 0x81;
- ISP_CMD = 0x02; // 用戶可以對"Data Flash/EEPROM區(qū)"進行字節(jié)編程
- ISP_ADDRL = addr;
- ISP_ADDRH = addr>>8;
- ISP_DATA = dat; // 數據進ISP_DATA
- EA = 0;
- ISP_TRIG = 0x46;
- ISP_TRIG = 0xB9;
- _nop_();
- Q0(); // 關閉ISP/IAP
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:讀一字節(jié)
- 入口:addr = 扇區(qū)單元地址
- 出口:dat = 讀出的數據
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- uchar dcx(uint addr)
- {
- uchar dat;
-
- ISP_CONTR = 0x81;
- ISP_CMD = 0x01; // 用戶可以對"Data Flash/EEPROM區(qū)"進行字節(jié)讀
- ISP_ADDRL = addr;
- ISP_ADDRH = addr>>8;
- EA = 0;
- ISP_TRIG = 0x46;
- ISP_TRIG = 0xB9;
- _nop_();
- dat = ISP_DATA; // 取出數據
- Q0(); // 關閉ISP/IAP
- return dat;
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函數:關閉ISP/IAP操作
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void Q0()
- {
- ISP_CONTR = 0; // 關閉IAP功能
- ISP_CMD = 0; // 待機模式,無ISP操作
- ISP_TRIG = 0; // 關閉IAP功能, 清與ISP有關的特殊功能寄存器
- EA=1;
- }
- /*
- STC89C52RC內部EEPROM詳細地址表:
- 第一扇區(qū) 第二扇區(qū) 第三扇區(qū) 第四扇區(qū)
- 起始地址 結束地址 起始地址 結束地址 起始地址 結束地址 起始地址 結束地址
- 2000h 21FFh 2200h 23FFh 2400h 25FFh 2600h 27FFH
- 第五扇區(qū) 第六扇區(qū) 第七扇區(qū) 第八扇區(qū)
- 起始地址 結束地址 起始地址 結束地址 起始地址 結束地址 起始地址 結束地址
- 2800h 29FFh 2A00h 2BFFh 2C00h 2DFFh 2E00h 2FFFh
- */
- /*******************************************************************************
- * 函 數 名 : Lcd1602_Delay1ms
- * 函數功能 : 延時函數,延時1ms
- * 輸 入 : c
- * 輸 出 : 無
- * 說 名 : 該函數是在12MHZ晶振下,12分頻單片機的延時。
- *******************************************************************************/
- void Lcd1602_Delay1ms(uint c) //誤差 0us
- {
- uchar a,b;
- for (; c>0; c--)
- {
- for (b=199;b>0;b--)
- {
- for(a=1;a>0;a--);
- }
- }
- }
- /*******************************************************************************
- * 函 數 名 : void LCDWrite_String(uchar x, uchar y, uchar *s)
- * 函數功能 : 向LCD寫入一個字符串
- * 輸 入 : x,y,*s
- * 輸 出 : 無
- *******************************************************************************/
- void LCDWrite_String(uchar x, uchar y, uchar z, uchar *s) //x 0~15 , y 0,1,2,3
- {
- LCD_set_xy(x,y,z);
- while(*s)
- {
- LcdWriteData(*s);
- s++;
- }
- }
- /*******************************************************************************
- * 函 數 名 : void LCD_set_xy(uchar x, uchar y,uchar z)
- * 函數功能 : 指定向LCD寫入字符串的位置
- * 輸 入 : x,y,z //x:橫坐標 y:縱坐標 z:字符串長度
- * 輸 出 : 無
- *******************************************************************************/
- void LCD_set_xy(uchar x,uchar y,uchar z)
- {
- uchar i;
- if(y==0)
- {
- LcdWriteCom(0x80+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0x80+x);
- }
- if(y==1)
- {
- LcdWriteCom(0xc0+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0xc0+x);
- }
- if(y==2)
- {
- LcdWriteCom(0x94+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0x94+x);
- }
- if(y==3)
- {
- LcdWriteCom(0xd4+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0xd4+x);
- }
- }
- /*******************************************************************************
- * 函 數 名 : LcdWriteCom
- * 函數功能 : 向LCD寫入一個字節(jié)的命令
- * 輸 入 : com
- * 輸 出 : 無
- *******************************************************************************/
- #ifndef LCD1602_4PINS //當沒有定義這個LCD1602_4PINS時
- void LcdWriteCom(uchar com) //寫入命令
- {
- LCD1602_E = 0; //使能
- LCD1602_RS = 0; //選擇發(fā)送命令
- LCD1602_RW = 0; //選擇寫入
-
- LCD1602_DATAPINS = com; //放入命令
- Lcd1602_Delay1ms(1); //等待數據穩(wěn)定
- LCD1602_E = 1; //寫入時序
- Lcd1602_Delay1ms(5); //保持時間
- LCD1602_E = 0;
- }
- #else
- void LcdWriteCom(uchar com) //寫入命令
- {
- LCD1602_E = 0; //使能清零
- LCD1602_RS = 0; //選擇寫入命令
- LCD1602_RW = 0; //選擇寫入
- LCD1602_DATAPINS = com; //由于4位的接線是接到P0口的高四位,所以傳送高四位不用改
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //寫入時序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- // Lcd1602_Delay1ms(1);
- LCD1602_DATAPINS = com << 4; //發(fā)送低四位
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //寫入時序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- }
- #endif
- /*******************************************************************************
- * 函 數 名 : LcdWriteData
- * 函數功能 : 向LCD寫入一個字節(jié)的數據
- * 輸 入 : dat
- * 輸 出 : 無
- *******************************************************************************/
- #ifndef LCD1602_4PINS
- void LcdWriteData(uchar dat) //寫入數據
- {
- LCD1602_E = 0; //使能清零
- LCD1602_RS = 1; //選擇輸入數據
- LCD1602_RW = 0; //選擇寫入
- LCD1602_DATAPINS = dat; //寫入數據
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //寫入時序
- Lcd1602_Delay1ms(5); //保持時間
- LCD1602_E = 0;
- }
- #else
- void LcdWriteData(uchar dat) //寫入數據
- {
- LCD1602_E = 0; //使能清零
- LCD1602_RS = 1; //選擇寫入數據
- LCD1602_RW = 0; //選擇寫入
- LCD1602_DATAPINS = dat; //由于4位的接線是接到P0口的高四位,所以傳送高四位不用改
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //寫入時序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- LCD1602_DATAPINS = dat << 4; //寫入低四位
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //寫入時序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- }
- #endif
- /*******************************************************************************
- * 函 數 名 : LcdInit()
- * 函數功能 : 初始化LCD屏
- * 輸 入 : 無
- * 輸 出 : 無
- *******************************************************************************/
- #ifndef LCD1602_4PINS
- void LcdInit() //LCD初始化子程序
- {
- LcdWriteCom(0x38); //開顯示
- LcdWriteCom(0x0c); //開顯示不顯示光標
- LcdWriteCom(0x06); //寫一個指針加1
- LcdWriteCom(0x01); //清屏
- LcdWriteCom(0x80); //設置數據指針起點
- }
- #else
- void LcdInit() //LCD初始化子程序
- {
- LcdWriteCom(0x32); //將8位總線轉為4位總線
- LcdWriteCom(0x28); //在四位線下的初始化
- LcdWriteCom(0x0c); //開顯示不顯示光標
- LcdWriteCom(0x06); //寫一個指針加1
- LcdWriteCom(0x01); //清屏
- LcdWriteCom(0x80); //設置數據指針起點
- }
- #endif
- void IntConfiguration()
- {
- //設置INT0
- IT0=1;//跳變沿出發(fā)方式(下降沿)
- EX0=1;//打開INT0的中斷允許。
- //設置INT1
- IT1=1;//跳變沿出發(fā)方式(下降沿)
- EX1=1;//打開INT0的中斷允許。
- EA=1;//打開總中斷
- }
- void Int0() interrupt 1
- {
- cc(0x2000); // 擦除第1個扇區(qū)(2000h~21FFh)
- xcx(0x2000,0x07); // 對EEPROM區(qū)2002h寫入2
- xcx(0x2001,32);
- LcdInit();
- }
- void Int1() interrupt 2
- {
- cc(0x2000); // 擦除第1個扇區(qū)(2000h~21FFh)
- xcx(0x2000,0x08); // 對EEPROM區(qū)2002h寫入2
- xcx(0x2001,33);
- LcdInit();
- }
復制代碼
全部資料下載地址:
51單片機讀寫內部EEPROM詳解.rar
(101.88 KB, 下載次數: 364)
2017-8-12 02:36 上傳
點擊文件名下載附件
|