使用STC8H1K08单片机做一个电机定时控制程序,想着使用内部EEPROM保存电机工作时间和停止时间,结果按键设置好数值之后断电重启显示又变为000,保存不到值。一直找不错原因,发帖寻求帮助,希望得到解决,谢谢!
下面是我写的完整程序,麻烦大家指出我调用不了EEPROM的原因:
#include<STC8H.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
//#include "reg51.h"
#include "intrins.h"
/*sfr IAP_DATA = 0xC2;
sfr IAP_ADDRH = 0xC3;
sfr IAP_ADDRL = 0xC4;
sfr IAP_CMD = 0xC5;
sfr IAP_TRIG = 0xC6;
sfr IAP_CONTR = 0xC7;
sfr IAP_TPS = 0xF5;*/
#define uchar unsigned char
#define uint unsigned int
#define Offset 0x2000
sbit L1=P1^1;//定义千位
sbit L2=P1^2;// 百位
sbit L3=P1^3;// 十位
sbit KEY_CH=P1^5; //模式设置
sbit KEY_ADD=P1^6; //加
sbit KEY_DEC=P1^7; //减
sbit INB=P5^4;
sbit INA=P1^4;
//定义变量
uchar code smgduan[13]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff,0x89,0x92};//共阳极,显示段码值0~9,空,H,S;
bit ch;//定义上下限设置
uchar d1,d2,d3,mode;//显示数据各位暂存变量
uint day ,out;//关停天数,启动时间
unsigned long int time,second,minute,hour;
void init_IO()
{
P1M0 = 0x1f; //设置P1.1为ADC口
P1M1 = 0x00;
P3M0 = 0x00; //设置P3.0~P3.7为开漏模式
P3M1 = 0x00;
P5M0 = 0x10; //设置P3.0~P3.7为开漏模式
P5M1 = 0x00;
}
/*------------------------------------------------
mS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
void DelayMs(uchar n)//12M
{
uchar i, j;
while (n--)
{
for(i=0;i<10;i++);
for(j=0;j<105;j++);
}
}
/*内部EEPROM*/
//单片机内部EEPROM不使能
void IapIdle()
{
IAP_CONTR = 0; //关闭IAP功能
IAP_CMD = 0; //清除命令寄存器
IAP_TRIG = 0; //清除触发寄存器
IAP_ADDRH = 0x80; //将地址设置到非IAP区域
IAP_ADDRL = 0;
// IAP_DATA=0; //清除数据
}
//从单片机内部EEPROM读一个字节,从0x0000地址开始
uchar EEPROM_Read(uint addr)
{
uchar dat;
IAP_CONTR = 0x80; //使能IAP,SYSCLK<24MHz 0x81 SYSCLK<=24
IAP_TPS = 12; //设置等待参数12MHz
IAP_CMD = 1; //设置IAP读命令
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_ADDRL = addr & 0xff; //设置IAP低地址
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_();
dat = IAP_DATA; //读IAP数据
IapIdle(); //关闭IAP功能
return dat;
}
//往单片机内部EEPROM写一个字节
void EEPROM_Write(uint addr, uchar dat)
{
IAP_CONTR = 0x80; //使能IAP
IAP_TPS = 12; //设置等待参数12MHz
IAP_CMD = 2; //设置IAP写命令
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_ADDRL = addr & 0xff; //设置IAP低地址
IAP_DATA = dat; //写IAP数据
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_();
IapIdle(); //关闭IAP功能
}
//擦除单片机内部EEPROM的一个扇区
//写8个扇区中随便一个的地址,便擦除该扇区,写入前要先擦除
void EEPROM_Erase(uint addr)
{
IAP_CONTR = 0x80; //使能IAP
IAP_TPS = 12; //设置等待参数12MHz
IAP_CMD = 3; //设置IAP擦除命令
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_ADDRL = addr & 0xff; //设置IAP低地址
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_();
IapIdle(); //关闭IAP功能
}
/*------------------------------------------------
* 函数名 : DigDisplay()
* 函数功能 : 数码管显示函数
* 输入 : 无
* 输出 : 无
------------------------------------------------*/
void Display()
{
L1=1;
P3=smgduan[d1];
DelayMs(1);
L1=0;
L2=1;
P3=smgduan[d2];
DelayMs(1);
L2=0;
L3=1;
P3=smgduan[d3];
DelayMs(1);
L3=0;
}
/*------------------------------------------------
按键扫描程序
------------------------------------------------*/
void keyscan()
{
if(!KEY_CH)
{
DelayMs(100);
if(!KEY_CH)
ch=!ch;
while(!KEY_CH);
}
if(ch==1)
{
d1 =11; //H,停限定
d2= day/10;
d3= day%10;
Display();
if(!KEY_ADD)
{
DelayMs(20);
if(!KEY_ADD)
{
day+=5;
if(day>=100)
day=99; //最大加到100
}
while(!KEY_ADD);
}
if(!KEY_DEC)
{
DelayMs(50);
if(!KEY_DEC)
{
if(day<=0)
{day=0;}
else
day-=1;
}
while(!KEY_DEC);
}
}
if(ch==0)
{
d1 =12; //S ,启限定
d2= out/10;
d3 =out%10;
Display();
if(!KEY_ADD)
{
DelayMs(20);
if(!KEY_ADD)
{
out+=5;
if(out>=99) //上下限3度区间
out=99;
}
while(!KEY_ADD);
}
if(!KEY_DEC)
{
DelayMs(50);
if(!KEY_DEC)
{
if(out<=0)
{out=0;}
else
out-=1;
}
while(!KEY_DEC);
}
}
}
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
AUXR &= 0x7f; //定时器时钟12T模式
TMOD |= 0xf0; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH0=0xb0; //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出
TL0=0x3c; //50ms
EA=1; //总中断打开
ET0=1; //定时器中断打开
TF0=0; //清除TF0标志
TR0=1; //定时器开关打开
}
/*------------------------------------------------
定时器中断子程序 12MHZ 12T
------------------------------------------------*/
void Timer0_isr(void) interrupt 1 using 1
{
int n;
TH0=0xb0; //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出
TL0=0x3c; //50ms
if(mode==0 && out!=0)
{
n++;
if(n==49)//一秒后
{
n=0;
second++;
}
if(second==2)//等2秒
{
INA=1;//启动水泵
}
if(second==(out+2)) //out+2秒后
{
INA=0;//关闭
}
if(second==2+out+3600*day) //2+out+day后time清零
{
second=0;
}
}
else if(mode==1)
{
n=0;
second=0;
INA=0;
}
}
/*------------------------------------------------
主函数
------------------------------------------------*/
void main (void)
{
int c;
init_IO();
mode=0;
INA=0;
day=EEPROM_Read(0x2000); //天数
out=EEPROM_Read(0x2001);
Init_Timer0();
while (1)
{
while ( mode==0) //不按按键时
{
// Init_Timer0();
d1=day/100; d2=(day%100)/10; d3=(day%100)%10;
Display();
if(!KEY_CH ||!KEY_ADD || !KEY_DEC)
{
mode=1;
}
}
while ( mode==1) //按按键时
{
keyscan();
EEPROM_Erase(0x2000); //存储前必须先擦除
EEPROM_Write(0x2000, day); //
EEPROM_Write(0x2001, out);
if(KEY_CH && KEY_ADD && KEY_DEC)
{
c++;
DelayMs(10);
if(c==9000)//停留9秒
{
c=0;
mode=0;
}
}
}
}
}
|