/*STC15W204;18650電池供電;頻率:12M
T0-1ms作為計數基準 ;T2-20ms作為按鍵檢測
P5.5 蜂鳴器
按下P3.0,設定增加;按下P3.1,設定減小 ;按下P3.2,儲存設定數值;P3.3,開始/停止計數
四位數碼管,使用中間兩個(手頭現有)
*/
/*
要求:
開機,讀取預存倒計時數值,按壓“開始”按鈕,每秒數值減1,直到0終止,鳴笛2聲提醒,恢復到開機等待狀態;
再次按壓“開始”,再次反復,,,;
任何時候,可以通過“+”“-”按鈕調整初始值,按壓“存儲鍵”,數值被儲存。
使用18650電池供電,帶充電接口;
為節省電能,當等待時間大于5分鐘后,自動關閉顯示,進入掉電模式;可通過按壓“開始”按鍵,恢復到開機等待狀態
*/
#include<STC15.H>
#include<intrins.h>
#define STC_Y1 97560U // 89C/LEXX、90C/LEXX
#define STC_Y3 14050U // 10F/Lxx、11F/Lxx 、12C/LExx、15F104E/L104E(A版)、15F204E/L204EA(A版)
#define STC_Y5 13043U // 15F/L/Wxx(Y3內核個別型號除外)、15F104W
#define uchar unsigned char //宏定義字符型變量
#define uint unsigned int //宏定義整型變量
#define Fosc 12000000UL
#define Core STC_Y5
/********************************************************************
命令定義
*********************************************************************/
#define CMD_IDLE 0 //EEPROM無操作
#define CMD_READ 1 //讀取字節
#define CMD_PROGRAM 2 //寫入字節
#define CMD_ERASE 3 //擦除字節
/********************************************************************
編程周期由晶振決定
*********************************************************************/
//#define ENABLE_IAP 0X80 //編程周期由晶振決定(如果<30MHZ選用此項)
//#define ENABLE_IAP 0X81 //編程周期由晶振決定(如果<24MHZ選用此項)
//#define ENABLE_IAP 0X82 //編程周期由晶振決定(如果<20MHZ選用此項)
#define ENABLE_IAP 0X83 //編程周期由晶振決定(如果<12MHZ選用此項)
//#define ENABLE_IAP 0X84 //編程周期由晶振決定(如果<6MHZ選用此項)
//#define ENABLE_IAP 0X85 //編程周期由晶振決定(如果<3MHZ選用此項)
//#define ENABLE_IAP 0X86 //編程周期由晶振決定(如果<2MHZ選用此項)
//#define ENABLE_IAP 0X87 //編程周期由晶振決定(如果<1MHZ選用此項)
#define IAP_ADDRESS 0X0000 //內部EEPROM地址
unsigned char code duanma[12]={0x3F,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x8c};//
sbit led_2=P3^6;
sbit led_3=P3^7;
sbit a6=P5^4;//g
sbit a5=P1^0;//f
sbit a4=P1^3;//e
sbit a3=P1^4;//d
sbit a2=P1^5;//c
sbit a1=P1^2;//b
sbit a0=P1^1;//a
sbit buzzer=P5^5;
unsigned char pwm,pwmcun;
unsigned long counter;
unsigned char Trg; //點按
unsigned char Cont; //長按
unsigned char cnt_plus; //長按延時
unsigned char cnt_plus_time; //長按速度
unsigned char start=0; //開始按鍵
/**
* 功能:延時t毫秒
* 入參:1~65535
*/
void delay_ms(unsigned int t)
{
unsigned int i;
do{
i = Fosc / Core;
while(--i);
}while(--t);
}
/********************************************************************
掉電模式(無操作5分鐘后關機省電)
*********************************************************************/
void kongxian()
{
PCON = 0x02; //MCU進入掉電模式
_nop_();
_nop_();
}
/********************************************************************
操作函數
*********************************************************************/
void IapIdle()
{
IAP_CONTR=0;
IAP_CMD=0;
IAP_TRIG=0;
IAP_ADDRH=0X80;
IAP_ADDRL=0;
}
/********************************************************************
讀取一個字節函數
*********************************************************************/
uchar IapReadByte(uint addr)
{
uchar dat;
IAP_CONTR=ENABLE_IAP;
IAP_CMD=CMD_READ;
IAP_ADDRL=addr;
IAP_ADDRH=addr>>8;
IAP_TRIG=0X5A;
IAP_TRIG=0XA5;
_nop_();
_nop_();
_nop_();
dat=IAP_DATA;
IapIdle();
return dat;
}
/********************************************************************
寫入一個字節函數
*********************************************************************/
void IapProgramByte(uint addr,uchar dat)
{
IAP_CONTR=ENABLE_IAP;
IAP_CMD=CMD_PROGRAM;
IAP_ADDRL=addr;
IAP_ADDRH=addr>>8;
IAP_DATA=dat;
IAP_TRIG=0X5A;
IAP_TRIG=0XA5;
_nop_();
_nop_();
_nop_();
IapIdle();
}
/********************************************************************
擦除一個字節函數
*********************************************************************/
void IapEraseSector(uint addr)
{
IAP_CONTR=ENABLE_IAP;
IAP_CMD=CMD_ERASE;
IAP_ADDRL=addr;
IAP_ADDRH=addr>>8;
IAP_TRIG=0X5A;
IAP_TRIG=0XA5;
_nop_();
_nop_();
_nop_();
IapIdle();
}
/**************************************
****************定時器初始化函數****************
**************************************/
void InitTimer(void)
{
AUXR &= 0x7F; //定時器時鐘12T模式
TMOD &= 0xF0; //設置定時器模式
TL0 = 0x18; //設置定時初值
TH0 = 0xFC; //設置定時初值1ms
TF0 = 0; //清除TF0標志
TR0 = 1; //定時器0開始計時
ET0 = 1; //T0中斷使能
AUXR &= 0xFB; //定時器2時鐘12T模式
T2L = 0xE0; //設置定時初值
T2H = 0xB1; //設置定時初值
AUXR |= 0x10; //定時器2開始計時
IE2 |= 0x04; //T2使能
EA = 1; //開總中斷
IT1 = 0; //0,上升沿和下降沿都能中斷。
EX1 =1; //使能INT1中斷
}
/********************************數碼管延時關斷函數******************************************/
void guanduan (void)//用于關斷數碼管的位選
{
delay_ms(1);//延時
led_2=1;//關斷百位
led_3=1;//關斷十位
delay_ms(2);//延時
}
/********************************10us延時函數************************************************/
void delay_10us (unsigned int a)//24MHz時鐘時的10微秒延時函數
{
unsigned int b;
while(a--)
{
for(b=0;b<12;b++);
}
}
/********************************sound數************************************************/
void sound(unsigned int jj,ii ) //jj,時長;ii,頻率
{
unsigned int i;
for(i=0;i<=jj*5;i++)
{buzzer=~buzzer;
if(buzzer)
{delay_10us(ii);}
else {delay_10us(ii-12);}
}
buzzer=0;
}
/********************************字段函數(顯示)********************************************/
void ziduan(unsigned char a)
{
a6=a&0x40;//g
a5=a&0x20;//f
a4=a&0x10;//e
a3=a&0x08;//d
a2=a&0x04;//c
a1=a&0x02;//b
a0=a&0x01;//a
}
/********************************顯示函數****************************************************/
void display(signed int a)//顯示函數(顯示實際數據除以10,支持顯示負數,負數顯示方式為百位顯示負號"-"十位和個位顯示數據)
{
unsigned char shiwei,gewei,d;//定義十位,個位,每次顯示幀數
shiwei=a/10;//計算十位
gewei=a%10;//計算個位
for(d=0;d<20;d++)//顯示部分,每次顯示20個循環(20幀)
{
ziduan(duanma[shiwei]);//顯示十位
led_2=0;//打開十位
guanduan();//延時關斷十位
ziduan(duanma[gewei]);//顯示個位
led_3=0;//打開個位
guanduan();//延時關斷個位
}
}
/**************************************
****************按鍵檢測****************
**************************************/
void Key(void)
{
unsigned char ReadData=P3^0xff;//若為0,表示沒有按鍵
Trg=ReadData&(ReadData^Cont);
Cont=ReadData;
if (Cont==0)
{
cnt_plus=0; //長按標志清0
}
if (Trg&0x04) //按下P3.2,00000100;儲存當前數值
{
sound(50,17);
IapEraseSector(0X0000); delay_ms(5);
IapProgramByte(0X0000,pwm); delay_ms(5);
pwmcun=pwm;
}
if (Trg&0x01) //按下P3.0,00000001,設定增加
{
start=0;
pwm++;
if(pwm==99)
{
pwm=0;
}
}
if (Trg&0x02) //按下P3.1,00000010,設定減小
{
start=0;
pwm--;
if(pwm==0)
{
pwm=99;
}
}
if(Trg&0x08) //按下P3.3,00001000,計數/停止
{
start=~start;
counter=0;
sound(50,17);
pwm=pwmcun;
}
if (cnt_plus<50)
{
cnt_plus++; //開始長按延時
}
if (cnt_plus>=50) //長按1秒后開始動作
{
cnt_plus_time++; //長按時速度變化
if (cnt_plus_time>30)
{
cnt_plus_time=0;
if (Cont&0X01) //長按P1.3,連加5
{
if(pwm<=(pwmcun-10))
{
pwm=pwm+5;
}
else
{
pwm++;
}
}
if (Cont&0X02) //長按P1.4,連減5
{
if(pwm>=10)
{
pwm=pwm-5;
}
else
{
pwm--;
}
}
}
}
}
/**************************************
****************主函數***************
**************************************/
void main ()
{ start=0;
sound(100,17);
P5M0=0xff;//P5都是推挽模式
P5M1=0x00;
P1M0=0xff;//P1都是推挽模式
P1M1=0x00;
InitTimer();
pwmcun=IapReadByte(0X0000);//讀取設定起始數值
delay_ms(5);
pwm = pwmcun;
buzzer=0;
counter = 0 ;
while(1)
{
display(pwm);
}
}
/**************************************
****************T0中斷,1ms用于倒計數****************
**************************************/
void Timer0Interrupt(void) interrupt 1
{
if(start) //計數狀態,T0用于倒計數
{
counter++;
if(counter==1000) //每秒(1000ms)倒計時1
{
counter = 0 ;
pwm--;
if(pwm==0) //計數完成,滴滴2聲,停止
{
start=0;
led_2=led_3=1;
pwm=pwmcun;
sound(80,17);
delay_ms(100);
sound(80,17);
delay_ms(400);
sound(80,17);
delay_ms(100);
sound(80,17);
}
}
}
if(start==0) //倒計數結束后,T0用于延時關機
{
counter++;
if(counter==300000) //5分鐘
{
led_2=led_3=1;
sound(300,17);
start=~start;
kongxian();
}
}
}
/**************************************
****************T2中斷,20ms用于檢測按鍵****************
**************************************/
void t2int() interrupt 12
{
IE2 &= ~0x04; //關閉定時器T2
Key(); //執行鍵盤掃描
IE2 |= 0x04; //啟動定時器T2
}
void exint1() interrupt 2 //INT1中斷入口
{
counter=0;
}
|