//浏览器用兼容模式浏览代码
#include "stc/config.h"
#include "stc/delay.h"
#include "stc/GPIO.h"
#include "stc/TIMER.h"
#include "stc/EXTI.h"
bit B_1ms=0;
u16 T_2s=0;
#define Const_Key_Jitter 40 //抖动计数
#define Const_Key_Long 1100 //长按1秒
#define Const_Key_Long5s 2050 //长按3秒
u16 INT1_Cnt;
u16 INT0_Cnt;
bit INT1_Short_Click;
bit INT0_Short_Click;
bit Long_Click;
bit INT1_Lock;
bit INT0_Lock;
u8 key_num;
bit INT1_Short_Flag;
bit INT1_Long_Flag;
bit INT0_Short_Flag;
bit INT0_Long_Flag;
bit INT0_LONG_Click; //有3秒,也锁住,为了判断是否按时间更长
bit INT0_Long5S_Flag;
u8 LIGHT_Cnt;
bit LASER_FLAG=0;
//STC15W eeprom需要重写
#define CMD_IDLE 0
#define CMD_READ 1
#define CMD_WRITE 2
#define CMD_ERASE 3
#define ENABLE_IAP 0X82 //if SYSCLK<20KHZ
#define IAP_ADDRESS 0X0000
/***************************************/
void Delay(u8 n)
{
while(n--);
}
//========================================================================
// 函数: void IapIdle(void)
// 描述: 禁止访问ISP/IAP.
// 参数: non.
// 返回: non.
// 版本: V1.0, 2016-4-22
//========================================================================
void IapIdle(void)
{
IAP_CONTR=0; //禁止ISP/IAP操作
IAP_CMD=0; //去除ISP/IAP命令
IAP_TRIG=0; //防止ISP/IAP命令误触发
IAP_ADDRH=0xff; //清0地址高字节
IAP_ADDRL=0xff; //清0地址低字节,指向非EEPROM区,防止误操作
}
/****************************************
擦除是按页进行的,即每次都是512个字节
****************************************/
//========================================================================
// 函数: Erase_Eeprom(u16 addr)
// 描述: 把指定地址的EEPROM扇区擦除.
// 参数: addr: 要擦除的扇区EEPROM的地址.
// 返回: non.
// 版本: V1.0, 2016-4-2
//========================================================================
void Erase_Eeprom(u16 addr)
{
// EA=0;
IAP_CONTR=ENABLE_IAP; //使能IAP 同时设置等待时间
IAP_CMD=CMD_ERASE; //设置IAP命令
IAP_ADDRL=(u8)(addr&0xff); //设置IAP低地址
IAP_ADDRH=(u8)(addr>>8); //设置IAP高地址
IAP_TRIG=0X5a; //写触发命令(0x5a) 写触摸命令以后 命令才会生效 手册713页
IAP_TRIG=0Xa5; //写触发命令(0xa5)
Delay(3); //等待ISP/IAP/EEPROM操作完成
IapIdle(); //关闭IAP功能
// EA=1;
}
/***************************************************
写入前,必须先擦除本页
****************************************************/
void Write_Eeprom(u16 addr,u8 dat)
{
IAP_CONTR=ENABLE_IAP; //使能IAP 同时设置等待时间
IAP_CMD=CMD_WRITE; //设置IAP命令
IAP_ADDRL=(u8)(addr&0xff); //设置IAP低地址
IAP_ADDRH=(u8)(addr>>8); //设置IAP高地址
IAP_DATA=dat; //写ISP/IAP/EEPROM数据
IAP_TRIG=0X5a; //写触发命令(0x5a) 写触摸命令以后 命令才会生效 手册713页
IAP_TRIG=0Xa5; //写触发命令(0xa5)
Delay(7); //等待ISP/IAP/EEPROM操作完成
IapIdle(); //关闭IAP功能
}
/******************************************************
读出时,可任意地址
*******************************************************/
u8 Read_Eeprom(u16 addr)
{
u8 dat; //数据缓冲区
IAP_CONTR=ENABLE_IAP; //使能IAP 同时设置等待时间
IAP_CMD=CMD_READ; //设置IAP命令
IAP_ADDRL=(u8)(addr&0xff); //设置IAP低地址
IAP_ADDRH=(u8)(addr>>8); //设置IAP高地址
IAP_TRIG=0X5a; //写触发命令(0x5a) 写触摸命令以后 命令才会生效 手册713页
IAP_TRIG=0Xa5; //写触发命令(0xa5)
Delay(5); //等待ISP/IAP/EEPROM操作完成
dat=IAP_DATA; //读ISP/IAP/EEPROM数据
IapIdle(); //关闭IAP功能
return dat;
}
/*******************************************************
键1当短按有效时,继续计数
短按为松手后判断
键1长按3S用于设置开启/关闭激光同步哨子功能 ,5S以上单独开启/关闭激光
键2为电子警哨,即按即响
*******************************************************/
void Key_Scan()
{
if(INT0==1)
{
INT0_Cnt=0; //按下计数清0
if(INT0_Lock==1) //长按锁标志
{
INT0_Lock=0;
}
else if (INT0_Short_Click==1) //短按标志且电源开启
{
INT0_Short_Click=0;
INT0_Short_Flag=1; //,短按有效,且松手去判断
}
else if (INT0_LONG_Click==1)
{
INT0_LONG_Click=0;
INT0_Long_Flag=1;
}
}
else if(INT0_Lock==0) //有键按下,且自锁标志为0,即第一次按下
{
INT0_Cnt++;
if((INT0_Cnt>=Const_Key_Jitter)&&(INT0_Short_Click==0)&&(INT0_LONG_Click==0))
{
INT0_Short_Click=1; //短按有效标志
}
if((INT0_Cnt>=Const_Key_Long)&&(INT0_LONG_Click==0)) //说明是长按,开自锁
{
// INT0_Lock=1; //长按锁住
INT0_Short_Click=0; //短接清0
INT0_LONG_Click=1;
// INT0_Long_Flag=1; //长按有效标志
if(LASER==0)
{
LASER=1;
delay_ms(100);
LASER=0;
delay_ms(100);
LASER=1;
delay_ms(100);
LASER=0;
}
else //如果是长按开激光,只要按3S就关
{
INT0_Lock=1;
INT0_LONG_Click=0;
LASER=0;
}
}
if(INT0_Cnt>=Const_Key_Long5s) //说明是长按,开自锁
{
INT0_LONG_Click=0;
INT0_Lock=1;
LASER=~LASER;
}
}
if(INT1==1)
{
INT1_Cnt=0; //按下计数清0
if(INT1_Lock==1) //长按锁标志
{
INT1_Lock=0;
}
else if (INT1_Short_Click==1) //短按标志且电源开启
{
INT1_Short_Click=0;
INT1_Short_Flag=1; //短按有效,且松手去判断
}
}
else if(INT1_Lock==0) //有键按下,且自锁标志为0,即第一次按下
{
INT1_Cnt++;
if(INT1_Cnt>=Const_Key_Jitter)
{
INT1_Short_Click=1; //短按有效标志
}
if(INT1_Cnt>=Const_Key_Long) //说明是长按,开自锁
{
INT1_Lock=1; //长按锁住
INT1_Short_Click=0;
INT0_LONG_Click=1;
INT1_Long_Flag=1; //长按有效标志
}
}
}
/*******************************************************
判断
键1在开机状态下,短按切换功能
仅键1长按时,开关机切换
仅键2长按时,暂定功能
键1键2同时长按时,开启另一功能
*******************************************************/
void KEY_Result()
{
if(INT0_Short_Flag)
{
INT0_Short_Flag=0;
key_num++;
if(key_num>=4)key_num=0;
if(key_num==1)WLIGHT=1;
}
if(INT0_Long_Flag&&(INT1_Long_Flag)) //同时按下两键,
{
INT0_Long_Flag=0;
INT1_Long_Flag=0;
}
else if(INT0_Long_Flag&&(INT1)) // 按键1满足长按,用按键2在松手状态
{
INT0_Long_Flag=0;
LASER_FLAG=~LASER_FLAG;
EA=0;
Erase_Eeprom(0x0000);
Write_Eeprom(0x0000,LASER_FLAG);
EA=1;
}
else if(INT0&&(INT1_Long_Flag)) //按键1在松手状态,按键2满足长按
{
INT1_Long_Flag=0;
}
}
/****************
2.8k
***************/
void Delay210us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 3;
j = 62;
do
{
while (--j);
} while (--i);
}
void Delay195us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
i = 3;
j = 21;
do
{
while (--j);
} while (--i);
}
void Delay185us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 2;
j = 250;
do
{
while (--j);
} while (--i);
}
void Delay178us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
i = 2;
j = 231;
do
{
while (--j);
} while (--i);
}
void Delay170us() //@11.0592MHz
{
unsigned char i, j;
i = 2;
j = 209;
do
{
while (--j);
} while (--i);
}
/*************************************************
警哨发声
**************************************************/
void SoundProc()
{
u8 i;
for(i=0;i<20;i++) // 22
{
BELL=1; //
Delay170us(); //
BELL=0;
Delay170us();
}
for(i=0;i<8;i++) //9
{
BELL=1;
Delay185us();
BELL=0;
Delay185us();
}
for(i=0;i<10;i++) //9
{
BELL=1;
Delay178us();
BELL=0;
Delay178us();
}
for(i=0;i<20;i++) //32
{
BELL=1;
Delay210us(); //
BELL=0;
Delay210us();
}
for(i=0;i<10;i++) //10
{
BELL=1;
Delay195us();
BELL=0;
Delay195us();
}
}
void main( )
{
bit xy=0;
GPIO_Inilize();
Timer0_Inilize();
Exti_Inilize();
LASER_FLAG=Read_Eeprom(0x0000); //同步标志
delay_ms(5);
TR0=1;
EA=1;
while(1)
{
if(B_1ms==1)
{
B_1ms=0;
if(++T_2s>=1000)
{
T_2s=0;
if(INT1&&(key_num==0)&&INT0)//,进入睡眠状态
{
TR0=0;
WLIGHT=0;
BELL=0;
// LASER=0;
INT1_Clear(); //清标志 IE1=0
INT1_Enable(); //使能按键中断EX1=1,用于唤醒
INT0_Clear(); //清标志
INT0_Enable(); //使能按键中断用于唤醒
MCU_POWER_DOWN(); //进入睡眠 PCON |= 2
NOP7();
}
}
Key_Scan();
KEY_Result();
}
if((LIGHT_Cnt>=56)&&(key_num==2)) //闪
{
WLIGHT=~WLIGHT;
LIGHT_Cnt=0;
}
if(key_num==3) //弱光
{
if(LIGHT_Cnt>12&&(xy==0))
{
WLIGHT=1;
xy=1;
LIGHT_Cnt=0;
}
if((xy==1)&&(LIGHT_Cnt>2))
{
WLIGHT=0;
LIGHT_Cnt=0;
xy=0;
}
}
if((INT1==0)&&INT0)
{
if(LASER_FLAG!=0)LASER=1;
SoundProc();
LASER=0;
}
}
}
/********************* Timer0中断函数************************/
void timer0_int (void) interrupt TIMER0_VECTOR
{
TF0=0;
B_1ms=1;
LIGHT_Cnt++;
}
/********************* 外部中断1中断函数,哨音发声************************/
void Ext_INT1 (void) interrupt INT1_VECTOR //进中断时已经清除标志
{
INT1_Disable(); //关闭按键中断使能 EX1=0
TR0=1;
}
void Ext_INT0(void) interrupt INT0_VECTOR
{
INT0_Disable();
TR0=1;
}