1、EEPROM扇區擦除或讀寫的時候不能與其他的程序同時跑。要解決EEPROM擦除或讀寫的時候不影響數碼管動態掃描需要學會統籌調度,這要結合具體應用處理,不是三言兩語說的清的。
2、讀取128以上數據顯示出錯多為數據類型使用不當。想寫入6666需要拆分為兩個字節,讀取后再合并還原。
測試程序:
- //測試條件:STC8H實驗板,MCU型號STC8H3K48S2
- //注意:測試本示例時,需在ISP下載時將【允許低壓復位(禁止低壓中斷)】關閉
- #include <STC8H.H>
- #include <intrins.h> //庫頭文件
- #define uint unsigned int //宏定義數據類型uint
- #define uchar unsigned char //宏定義數據類型uchar
- #define IAP_ADDRESS 0x0000 //測試地址
- //順序共陰極數碼管段碼表,段碼a-h順序接PX0-PX7
- uchar code table[]={//共陰數碼管段碼"0~f-."
- 0x3f,0x06,0x5b,0x4f,
- 0x66,0x6d,0x7d,0x07,
- 0x7f,0x6f,0x77,0x7c,
- 0x39,0x5e,0x79,0x71,0x40,0x80};
- uchar data dis_buf[8]; //緩存數組
- uint num,sec;
- uchar i;
- uint sign;
- void Timer0Init(); //定時器初始化聲明
- void IapIdle(); //關閉IAP/EEPROM
- uchar IapRead(uint addr); //讀取EEPROM數據
- void IapProgram(uint addr, uchar dat);//寫入EEPROM數據
- void IapErase(uint addr); //擦除EEPROM扇區
- //初始化單片機端口
- void McuInit()
- {
- P0M0 = 0xff; P0M1 = 0x00;
- P1M0 = 0x00; P1M1 = 0x00;
- P2M0 = 0x00; P2M1 = 0x00;
- P3M0 = 0x00; P3M1 = 0x00;
- P4M0 = 0x00; P4M1 = 0x00;
- P5M0 = 0x00; P5M1 = 0x00;
- P6M0 = 0x00; P6M1 = 0x00;
- P7M0 = 0x00; P7M1 = 0x00;
- }
- //關閉單片機端口
- void McuSleep()
- {
- P0M0 = 0x00; P0M1 = 0xff;
- P1M0 = 0x00; P1M1 = 0xff;
- P2M0 = 0x00; P2M1 = 0xff;
- P3M0 = 0x00; P3M1 = 0xff;
- P4M0 = 0x00; P4M1 = 0xff;
- P5M0 = 0x00; P5M1 = 0xff;
- P6M0 = 0x00; P6M1 = 0xff;
- P7M0 = 0x00; P7M1 = 0xff;
- }
- void main()
- {
- McuInit();
- if(IapRead(IAP_ADDRESS)==0xff)//如果沒有保存過數據
- {
- IapProgram(IAP_ADDRESS, 0);//扇區首地址寫0
- sec=0;
- sign=1;
- }
- else
- {
- // for(i=1;i<12;i++) //測試寫10次
- for(i=1;i<511;i++) //測試寫滿510個字節
- {
- if(IapRead(IAP_ADDRESS+i)==0xff)//如果遇到沒有保存數據的單元
- {
- sec=IapRead(IAP_ADDRESS+i-1);//讀取前一個字節保存的數據
- sign=i; //地址緩存
- break; //跳出循環
- }
- }
- }
- // if(sign==11) //測試寫10次
- if(sign==510) //如果寫滿510
- {
- IapErase(IAP_ADDRESS); //擦除扇區
- IapProgram(IAP_ADDRESS, 0);//首地址寫0
- sign=1;
- }
- PCON &= 0xDF; //清0掉電標志
- ELVD = 1; //開低壓中斷
- EA = 1; //開總中斷
- Timer0Init(); //初始化定時器
- while(1)
- {
- if(TF0) //查詢T0中斷請求標志
- {
- TF0=0; //T0中斷請求標志清0
- if(++num>=1000) //1秒
- {
- num=0;
- sec=++sec%250;
- }
- dis_buf[0]=table[sec/100%10];
- dis_buf[1]=table[sec/10%10];
- dis_buf[2]=table[sec%10];
- P0=0x00; //段消隱
- P2=~(0x01<<i); //送段碼
- P0=dis_buf[i]; //送位碼
- i=++i%3; //循環計數
- }//耗時569us
- }
- }
- void PowerLost() interrupt 6 //低壓中斷
- {
- EA = 0; //關閉總中斷
- McuSleep(); //關閉所有端口(停止所有耗電電路)
- IapProgram(IAP_ADDRESS+sign,sec);//寫數據到EEPROM
- while((PCON & 0x20) != 0) //復查低壓標志
- {
- PCON &= 0xDF; //清除低壓標志
- _nop_();
- _nop_(); //坐等掉電
- }
- IAP_CONTR = 0x20; //發現是誤報,重啟單片機,恢復正常工作
- }
- void Timer0Init(void) //1毫秒@11.0592MHz
- {
- AUXR |= 0x80; //定時器時鐘1T模式
- TMOD &= 0xF0; //設置定時器模式
- TL0 = 0xCD; //設置定時初始值
- TH0 = 0xD4; //設置定時初始值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
- }
- //關閉IAP/EEPROM
- void IapIdle()
- {
- IAP_CONTR = 0; //關閉IAP功能
- IAP_CMD = 0; //清除命令寄存器
- IAP_TRIG = 0; //清除觸發寄存器
- IAP_ADDRH = 0x80; //將地址設置到非IAP區域
- IAP_ADDRL = 0;
- }
- //讀取EEPROM數據
- uchar IapRead(uint addr)
- {
- uchar dat;
- IAP_CONTR = 0x80; //使能IAP
- IAP_TPS = 12; //設置等待參數12MHz
- IAP_CMD = 1; //設置IAP讀命令
- IAP_ADDRL = addr; //設置IAP低地址
- IAP_ADDRH = addr >> 8; //設置IAP高地址
- IAP_TRIG = 0x5a; //寫觸發命令(0x5a)
- IAP_TRIG = 0xa5; //寫觸發命令(0xa5)
- _nop_();
- dat = IAP_DATA; //讀IAP數據
- IapIdle(); //關閉IAP功能
- return dat;
- }
- //寫入EEPROM數據
- void IapProgram(uint addr, uchar dat)
- {
- IAP_CONTR = 0x80; //使能IAP
- IAP_TPS = 12; //設置等待參數12MHz
- IAP_CMD = 2; //設置IAP寫命令
- IAP_ADDRL = addr; //設置IAP低地址
- IAP_ADDRH = addr >> 8; //設置IAP高地址
- IAP_DATA = dat; //寫IAP數據
- IAP_TRIG = 0x5a; //寫觸發命令(0x5a)
- IAP_TRIG = 0xa5; //寫觸發命令(0xa5)
- _nop_();
- IapIdle(); //關閉IAP功能
- }
- void IapErase(uint addr)
- {
- IAP_CONTR = 0x80; //使能IAP
- IAP_TPS = 12; //設置等待參數12MHz
- IAP_CMD = 3; //設置IAP擦除命令
- IAP_ADDRL = addr; //設置IAP低地址
- IAP_ADDRH = addr >> 8; //設置IAP高地址
- IAP_TRIG = 0x5a; //寫觸發命令(0x5a)
- IAP_TRIG = 0xa5; //寫觸發命令(0xa5)
- _nop_(); //
- IapIdle(); //關閉IAP功能
- }
復制代碼
|