/*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;
}
|