六、一款手电激光电子哨

//浏览器用兼容模式浏览代码

#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; }

 

posted @ 2021-07-13 15:13  来去勿扰  阅读(95)  评论(0)    收藏  举报