使用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;
}
}
}
}
}
|