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功能
- }
复制代码
|