2020年春节,由于受疫情的限制,另外博主也是疫情的重灾区-湖北省襄阳市,一方面响应国家的号召“在家不论跑就是最大的贡献”,另一方也是在家闲不住,于是又准备捣鼓捣鼓前两年改造的台灯,前两年在家改造的台灯,改造完后就去上学去了,今年回来,经爸妈的反馈,在实际使用过程中,还是不好用,但之前的程序没有存档,于是乎,又重新列出了,台灯的几个功能:
1、台灯分两个功能模式:自动模式和手动模式;
2、自动模式----白天自动熄灯;晚上检测到人体后开灯,若人体在一定时间内移动,则灯一直开灯不熄灭,当超过一定时间后,人体不移动或未检测到人体,则灯自动熄灭;---这一场景功能主要是方便晚上起夜上厕所;灯的亮度可调目前分为10个级别;-------这一场景功能主要是晚上上突然开启强光,眼睛会花眼;
3、自动模式----定时时间可调,分为2min,3min,4min,5min四中定时时间可调整;
4、手动模式---手动模式不论是白天还是黑夜都可以开启灯光,切灯光亮度可调10个亮度等级;------这一场景功能主要应用是有时白天需要使用台灯,或晚上看书或做别的事情,若灯光太亮,可以手动调节;
5、双电源自动切换----平时台灯插电,台灯使用的时电源适配器的供电,当出现停电状况,自动切换到锂电池供电;-----这一场景功能主要是我这边有时会停电,家里很不方便,自己也有好多18650电池,正好利用起来;
6、锂电池自动充电 -----当检测到锂电池电源过低时,启用自动充电给台灯内的电池充电,保证电池处于有电状态,以此应急停电;
7、USB充电------台灯另外一个功能也可以当做一个充电宝,目前手上有十几节电池,目前使用的是12节18650电池,一节容量2200mA,所以总容量大概 12x2200mA=26400mA;使用的模块是充电宝拆出来的模块,USB输出标称为5V1A;
8、按键功能------使用原有台灯按键,按键功能目前定义如下:单击---调节亮度;双击----关闭台灯;长按-----模式切换(自动模式和手动模式);
以上是自己目前想出来的几个主要功能,单片机使用的还是较为熟悉的STC12C5A60S2---DIP-40封装,电源基准使用的是从电脑电源电路板上拆的WL431,查了很多资料,没有查出和TL431是什么区别,还是没有查出来,于是自己完全按照TL431管脚实验了下,结果脚位相同,可是使用;MOS管使用的是F9540N和AO3400,使用双适配器5V供电,一路适配器输出电压给电路使用,一路专门给锂电池充电使用;
电路图如下:
由于是使用的充电宝改进的,存在一个问题就是,目前市面上大部分使用的充电宝方案为DW01、8025A单片机和MT5032,会出现一个弊端就是无法使用小电流模式下升压至5V,由于查了许多资料,最终锁定在MT5032这颗升压IC上,经测量发现MT5032管脚的EN使能端是连接在一颗SOP-14芯片上,猜想为一颗单片机,于是,把此管脚切开,直接和VCC接起来即1、2管脚连接起来,直接使能,可以解决这个问题,MT5032大致资料如下:
程序如下:
主程序main.c:
1 /* 2 智能台灯 20200215完结 3 By-----Li 4 */ 5 #include "main.h" 6 #include "config.h" 7 #include "gpio.h" 8 #include "timer.h" 9 #include "uart.h" 10 #include "adc.h" 11 #include "interrupt.h" 12 #include "user_timer.h" 13 #include "user_auto_contorl.h" 14 #include "pwm.h" 15 #include "user_funtion_ui.h" 16 #include "user_key.h" 17 #include <stdio.h> 18 #include "delay.h" 19 20 void main() 21 { 22 gpio_init(); // GPIO 电平初始化 23 pwm0_init(); // PWM初始化 24 Timer_Init(); // 定时器初始化 25 user_timer_init(); // 初始化时间数组 26 #ifdef USER_TEST 27 InitUart(); // 串口初始化 28 #endif 29 InitADC(); // ADC初始化 30 user_key_init(); // 按键检测初始化 31 user_ui_init(); //初始化灯光亮度 32 while(1) 33 { 34 add_system_time(); //添加系统时间 35 user_key_scan(USER_KEY_SCAN_PIN ); //按键扫描 36 auto_contorl_bat_battery(); //电池电压充电管理 37 user_ui(); //灯光功能 38 } 39 }
主程序头文件main.h
1 #ifndef _MAIN_H_ 2 #define _MAIN_H_ 3 #include <STC12C5A60S2.H> 4 5 #define USER_KEY_SCAN_PIN P11 //按键输入管脚 6 7 8 void main(); 9 10 #endif
灯光功能函数user_funtion_ui.c
1 #include "user_funtion_ui.h" 2 #include "user_auto_contorl.h" 3 #include "pwm.h" 4 #include "user_key.h" 5 #include "user_timer.h" 6 #include "eeprom.h" 7 #include <stdio.h> 8 #include "delay.h" 9 10 static uint16_t USER_HUMMAN_REACTION_TIME =LED_TIMMING_TWO_MIN ;//灯光定时时长 11 static bit led_mode_flag = 0 ; //LED灯光模式标志位 12 uint8_t pwm_adj_data = 0 ; //LED灯光亮度数据 13 extern bit battery_flag ; //充电标志位 14 15 16 /* 17 Function Name : user_ui_init 18 Function :灯光模式初始化 19 Header:读取灯光亮度数据,设置定时时长 20 */ 21 void user_ui_init() 22 { 23 EA=1; 24 V_BAT_SITCH_PIN =0 ; 25 pwm_adj_data = read_eeprom(0x0000); //读取灯光亮度数据 26 pwm_adj_data = read_eeprom(0x0000); //读取灯光亮度数据 27 clear_time_cnt(ADC_PRINTF_TIME_NUMBER); // 清除检测电池电压间隔时间 28 clear_time_cnt(USER_HUMMAN_REACTION_NUMBER); //清除LED灯亮的时间 29 // check_woman_time(); //设置灯光定时时长 30 } 31 32 /* 33 Function Name : user_ui 34 Function :灯光功能主函数 35 */ 36 37 void user_ui() 38 { 39 static bit led_key_switch_flag = 0 ; // 双击灯光控制标志位 40 static bit auto_time_counts_flag = 0 ; 41 42 check_woman_time(); //设置灯光定时时长 43 if(return_key_state() == KEY_TWO_ACTION ) //双击触发 44 { 45 led_key_switch_flag = ~led_key_switch_flag; 46 #ifdef USER_TEST 47 printf( "双击操作发生!!\n" ); 48 printf( "自动模式定时=%d\n",USER_HUMMAN_REACTION_TIME); 49 #endif 50 rest_key_state(); //释放按键 51 } 52 if(battery_flag != 1 ) 53 { 54 if(return_key_state() == KEY_LONG_PRESS_ACTION ) //长按触发 55 { 56 rest_key_state(); //释放按键 57 led_mode_flag = ~led_mode_flag; 58 // led_mode_flag++; 59 // if(led_mode_flag>=2) 60 // { 61 // led_mode_flag = 0; 62 // } 63 // clean_iap(0x0100 ); //擦除EEROM数据 64 // write_eeprom(0x0100, led_mode_flag); //写入灯光模式 数据 65 66 led_key_switch_flag = 0 ; //每次切换模式,灯都处于打开状态!! 67 if(led_mode_flag == 0 ) 68 { 69 clear_time_cnt(USER_HUMMAN_REACTION_NUMBER); //清除LED灯亮的时间 70 auto_time_counts_flag = 0 ; 71 72 } 73 } 74 75 if( led_mode_flag ) //手动模式调光 76 { 77 if( return_key_state() == KEY_CLICK_ACTION ) 78 { 79 rest_key_state(); //释放按键 80 if(led_key_switch_flag ) 81 { 82 led_key_switch_flag = ~led_key_switch_flag; 83 #ifdef USER_TEST 84 printf( "打开手动灯光\n"); 85 #endif 86 } 87 else 88 { 89 pwm_adj_data +=PWM_LED_STEP_LUMINANCE ; //灯光步进亮度 90 if(pwm_adj_data>PWM_SET_MIN_LUMINANCE) 91 { 92 pwm_adj_data = PWM_SET_MAX_LUMINANCE ; 93 } 94 clean_iap(0x0000 ); //擦除EEROM数据 95 write_eeprom(0x0000, pwm_adj_data); //写入EEROM数据 96 #ifdef USER_TEST 97 printf( "手动灯光亮度值增加\n"); 98 #endif 99 } 100 } 101 if(led_key_switch_flag) //双击手动关灯 102 { 103 pwm_updata( 0xFF ); //打开灯光 104 USER_LED( LED_ALL_OFF ); //关闭指示灯 105 } 106 else 107 { 108 USER_LED( LED_MODE_USER ); //手动模式指示灯 109 pwm_updata( pwm_adj_data ); //打开灯光 110 } 111 } 112 else //自动模式调光 113 { 114 if(check_time_arrive( USER_HUMMAN_REACTION_NUMBER,USER_HUMMAN_REACTION_TIME) ) //检查定时时间是否到达 115 { 116 if(auto_time_counts_flag!=1) 117 { 118 auto_time_counts_flag = 1 ; 119 pwm_updata( 0xFF ); 120 led_key_switch_flag = 0 ; 121 #ifdef USER_TEST 122 printf( "自动定时时间到!!\n" ); 123 #endif 124 } 125 } 126 else 127 { 128 // printf( "时间未到\n" ); 129 130 if(return_key_state() == KEY_CLICK_ACTION ) //单击 131 { 132 rest_key_state(); //释放按键 133 if(led_key_switch_flag) 134 { 135 led_key_switch_flag = ~led_key_switch_flag; 136 #ifdef USER_TEST 137 printf( "打开自动灯光\n"); 138 #endif 139 } 140 else 141 { 142 pwm_adj_data +=PWM_LED_STEP_LUMINANCE ; //灯光步进亮度 143 if(pwm_adj_data>PWM_SET_MIN_LUMINANCE) 144 { 145 pwm_adj_data = PWM_SET_MAX_LUMINANCE ; 146 } 147 clean_iap(0x0000 ); //擦除EEROM数据 148 write_eeprom(0x0000, pwm_adj_data); //写入EEROM数据 149 #ifdef USER_TEST 150 printf( "自动灯光亮度增加\n"); 151 #endif 152 } 153 154 } 155 if(led_key_switch_flag) //双击手动关灯 156 { 157 pwm_updata( 0xFF ); //打开灯光 158 USER_LED( LED_ALL_OFF); //关闭指示灯 159 } 160 else 161 { 162 USER_LED( LED_MODE_AUTO ); //自动模式指示灯 163 pwm_updata( pwm_adj_data ); //打开灯光 164 } 165 166 } 167 if( HUMMAN_REACTION_PIN == 0 )//若检测到人体,则清除时间,重新开始计时! 168 { 169 #ifdef USER_TEST 170 // printf( "检测到人体\n" ); 171 #endif 172 auto_time_counts_flag = 0 ; 173 clear_time_cnt(USER_HUMMAN_REACTION_NUMBER); //清除时间 174 } 175 } 176 } 177 else 178 { 179 pwm_updata( 0xFF ); 180 } 181 } 182 183 /* 184 Function Name : USER_LED 185 Function :灯光模式指示灯 186 Header:红----手动模式 ; 蓝----自动模式 187 */ 188 void USER_LED(uint8_t mode_flag) 189 { 190 switch( mode_flag) 191 { 192 case 0 : 193 USER_CONTORL_B_LED_MODE = LED_INDICATOR_ON ; 194 AUTO_CONTORL_R_LED_MODE = LED_INDICATOR_OFF ; 195 break; 196 case 1 : 197 USER_CONTORL_B_LED_MODE = LED_INDICATOR_OFF ; 198 AUTO_CONTORL_R_LED_MODE = LED_INDICATOR_ON ; 199 break; 200 case 2: 201 USER_CONTORL_B_LED_MODE = LED_INDICATOR_OFF ; 202 AUTO_CONTORL_R_LED_MODE = LED_INDICATOR_OFF ; 203 break; 204 default : break; 205 206 } 207 208 } 209 210 /* 211 Function Name : check_woman_time 212 Function :设置灯光定时时间 213 Header:设置定时时长: 214 1:1 = 2min 215 1:0 = 4min 216 0:1 = 3min 217 1:0 = 5min 218 */ 219 void check_woman_time() //设置灯光定时时间 220 { 221 static uint16_t time_temp = LED_TIMMING_TWO_MIN ; 222 time_temp = USER_HUMMAN_REACTION_TIME; //保存上次定时值 223 if( SET_CHECK_WOMAN_0_TIME_PIN) 224 { 225 if( SET_CHECK_WOMAN_1_TIME_PIN ) 226 USER_HUMMAN_REACTION_TIME = LED_TIMMING_TWO_MIN ; //2 min 227 else 228 USER_HUMMAN_REACTION_TIME = LED_TIMMING_FOUR_MIN ; //4 min 229 230 } 231 else 232 { 233 if( SET_CHECK_WOMAN_1_TIME_PIN ) 234 USER_HUMMAN_REACTION_TIME = LED_TIMMING_THREE_MIN ; //3 min 235 else 236 USER_HUMMAN_REACTION_TIME = LED_TIMMING_FIVE_MIN ; //5 min 237 } 238 if(time_temp != USER_HUMMAN_REACTION_TIME ) //若定时值发生变化 239 { 240 clear_time_cnt(USER_HUMMAN_REACTION_NUMBER); //清除LED灯亮的时间 241 242 } 243 // clear_time_cnt(USER_HUMMAN_REACTION_NUMBER); //清除LED灯亮的时间 244 // clear_time_cnt(ADC_PRINTF_TIME_NUMBER); // 清除检测电池电压间隔时间 245 246 }
灯光功能函数头文件user_funtion_ui.h
1 #ifndef _user_funtion_ui_h_ 2 #define _user_funtion_ui_h_ 3 4 #include "config.h" 5 6 #define USER_CONTORL_B_LED_MODE P21 //自动模式指示灯 7 #define AUTO_CONTORL_R_LED_MODE P24//手动模式指示灯 8 9 #define SET_CHECK_WOMAN_0_TIME_PIN P22 //设置人体检测时间 10 #define SET_CHECK_WOMAN_1_TIME_PIN P23 11 12 #define PWM_LED_STEP_LUMINANCE 20 //灯光步进亮度 13 #define PWM_SET_MIN_LUMINANCE 200 //灯光最小亮度 14 #define PWM_SET_MAX_LUMINANCE 0 //最大亮度 15 16 #define LED_INDICATOR_OFF 1 17 #define LED_INDICATOR_ON 0 18 #define LED_ALL_OFF 2 19 20 #define LED_MODE_USER 1 21 #define LED_MODE_AUTO 0 22 23 #define LED_TIMMING_TWO_MIN 24000 //2min 24 #define LED_TIMMING_THREE_MIN 36000 // 3min 25 #define LED_TIMMING_FOUR_MIN 48000 // 4min 26 #define LED_TIMMING_FIVE_MIN 60000 // 5min 27 28 void check_woman_time() ; //设置灯光定时时间 29 30 void USER_LED(uint8_t mode_flag); 31 32 void user_ui_init(); 33 34 void user_ui(); 35 36 #endif
电池管理功能user_auto_contorl.c
1 #include "user_auto_contorl.h" 2 #include "config.h" 3 #include "user_timer.h" 4 #include "adc_smoothing.h" 5 #include "eeprom.h" 6 #include "pwm.h" 7 #include <stdio.h> 8 9 bit battery_flag = 0 ; ////充电标志位 10 11 12 13 /* 14 Function Name : auto_contorl_bat_battery 15 Function :自动控制电池充电 16 */ 17 void auto_contorl_bat_battery() //自动控制电池充电 18 { 19 float ADC_V_BAT = 0; 20 uint16_t v_ref ,v_bat; 21 22 if(check_time_arrive( ADC_PRINTF_TIME_NUMBER,ADC_PRINTF_TIME) )//采集电池电压间隔 23 { 24 clear_time_cnt(ADC_PRINTF_TIME_NUMBER); 25 v_bat = GetResult(V_BAT_INTPUT_CH); //读取电池电压转换AD后的值 26 v_ref = GetResult(V_REF_INTPUT_CH); //读取TL431基准+2.5V电压转换AD后的值 27 // ADC_V_BAT = v_bat * 2.5f / v_ref; //计算出实际电池电压 28 ADC_V_BAT = v_bat *REFERENCE_VOLTAGE / v_ref; //计算出实际电池电压 29 30 if(ADC_V_BAT <= V_BAT_MIN_VOLTAGE ) //电池电压过低,且未充电,则关闭LED灯,保护电池过放!! 31 { 32 battery_flag = 1 ; //充电标志位 33 V_BAT_SITCH_PIN = 1 ; //开启充电功能 34 #ifdef USER_TEST 35 printf( "电压状态=1\n" ); 36 #endif 37 } 38 else if((ADC_V_BAT>V_BAT_MIN_VOLTAGE )&&( ADC_V_BAT <= V_BAT_START_BATTERY_VOLTAGE ) ) // 电池到达最低临界值,开始充电! 39 { 40 #ifdef USER_TEST 41 printf( "电压状态=2\n" ); 42 #endif 43 battery_flag = 0 ; //充电标志位 44 V_BAT_SITCH_PIN =1; //开启充电功能 45 battery_flag =0; 46 } 47 else if(( ADC_V_BAT >V_BAT_START_BATTERY_VOLTAGE )&&(ADC_V_BAT <= V_BAT_OVER_BATTERY_VOLTAGE )) 48 { 49 battery_flag = 0 ; 50 #ifdef USER_TEST 51 printf( "电压状态=3\n" ); 52 #endif 53 // V_BAT_SITCH_PIN =1; //开启充电功能 54 } 55 else //电池电压充电到达最大电压,关闭充电! 56 { 57 #ifdef USER_TEST 58 printf( "电池状态=4\n"); 59 #endif 60 V_BAT_SITCH_PIN =0; //关闭充电功能 61 battery_flag = 0 ; 62 } 63 #ifdef USER_TEST 64 printf( "电池电压值=%f\n", ADC_V_BAT ); 65 66 // if(P25 ==1 ) 67 // { 68 // printf( "充电器插上状态\n" ); 69 // 70 // } 71 // else 72 // printf( "充电器无电压\n" ); 73 // } 74 75 #endif 76 } 77 78 }
电池管理功能头文件user_auto_contorl.h
1 #ifndef _user_auto_contorl_h_ 2 #define _user_auto_contorl_h_ 3 4 #define V_BAT_INTPUT_CH 0X04 //电池电压采集通道 5 #define V_REF_INTPUT_CH 0X06 //TL431基准电压采集通道 6 #define REFERENCE_VOLTAGE 2.4f //基准电压 +2.5V 7 8 9 /*------------ 电池电压 ------------------*/ 10 #define V_BAT_MIN_VOLTAGE 3.30f //电池最低保护电压 11 #define V_BAT_START_BATTERY_VOLTAGE 3.70f // 电池开始充电电压 12 #define V_BAT_OVER_BATTERY_VOLTAGE 4.20f // 电池结束充电电压 13 //////////////////////////////////////////////////// 14 15 #define HUMMAN_REACTION_PIN P10 //人体感应和光敏开关 16 #define LED_PIN P13 //灯光控制 17 #define V_BAT_SITCH_PIN P20 //充电控制 18 19 20 void auto_contorl_bat_battery(); //自动控制电池充电 21 22 23 24 25 26 #endif
3 #ifndef _config_h_ #define _config_h_ 4 #include <STC12C5A60S2.H> 6 7 8 #define USER_TEST 9 10 #define FOSC 11059200L 11 #define BAUD 9600 12 13 14 15 16 17 ///////////////// 灯光亮度档位 /////////////////// 18 //#define LED_OFF 255 19 //#define LED_PWM_ONE_DATA 191 20 //#define LED_PWM_TWO_DATA 127 21 //#define LED_PWM_THREE_DATA 64 22 //#define LED_PWM_FOUR_DATA 0 23 24 25 ////////////////////// timer_number /////////////////////// 26 #define USER_TIMER_AMOUNT 4 27 28 #define USER_HUMMAN_REACTION_NUMBER 0 //人体感应编号 29 #define ADC_PRINTF_TIME_NUMBER 1 30 #define KEY_TRIGGER_TIMER_NUMBER 2 31 #define KEY_TWO_TRIGGER_TIME_NUMBER 3 32 33 ////////////////////// key_timer ////////////////////// 34 //#define USER_HUMMAN_REACTION_TIME 10000 // 灯光定时时间 35 #define ADC_PRINTF_TIME 1000 //5S 电池检测间隔 36 #define KEY_TRIGGER_TIMER 5 //20ms 消抖时间 37 #define KEY_TWO_TRIGGER_TIME 50 //250MS 双击时间阀值 38 #define KEY_LONG_PRESS_TIME 400 //2s 长按时间阀值 39 40 //#define KEY_LONG_PRESS_TIME 4000 // 4000 x 500us = 2s 41 42 43 44 45 46 47 48 49 50 51 ///////////////////////////////////////////////// 52 53 #define OFF 0 54 #define ON 1 55 56 57 #define BIT0 0x01 58 #define BIT1 0x02 59 #define BIT2 0x04 60 #define BIT3 0x08 61 #define BIT4 0x10 62 #define BIT5 0x20 63 #define BIT6 0x40 64 #define BIT7 0x80 65 66 67 #ifndef uint8_t 68 #define uint8_t unsigned char 69 #endif 70 71 #ifndef uint16_t 72 #define uint16_t unsigned int 73 #endif 74 75 #ifndef uint32_t 76 #define uint32_t unsigned long 77 #endif 78 79 #endif
电池电压滤波adc_smoothing.c
1 #include "adc_smoothing.h" 2 #include "adc.h" 3 4 5 /* 6 Function Name : GetResult 7 Function :ADC滤波 8 Header:采用掐头去尾方法,把最大值和最小值去掉,取平均值 9 */ 10 unsigned int GetResult(unsigned char ch) 11 { 12 unsigned int ADC_min, ADC_max, ADC_tmp, ADC_result, ADC; 13 unsigned char i, j; 14 15 ADC = 0; 16 for(j = 0; j < 16; j++) 17 { 18 ADC_result = 0; 19 ADC_min = ADC_max = GetADCResult(ch); 20 for(i = 0; i < 8; i++) 21 { 22 ADC_tmp = GetADCResult(ch); 23 if(ADC_tmp < ADC_min) 24 { 25 ADC_result += ADC_min; 26 ADC_min = ADC_tmp; 27 } 28 else if(ADC_tmp > ADC_max) 29 { 30 ADC_result += ADC_max; 31 ADC_max = ADC_tmp; 32 } 33 else 34 { 35 ADC_result += ADC_tmp; 36 } 37 } 38 39 ADC_result /= 8; 40 ADC += ADC_result; 41 } 42 ADC /= 16; 43 44 return ADC; 45 }
电池电压滤波adc_smoothing.h
1 #ifndef _adc_smoothing_h_ 2 #define _adc_smoothing_h_ 3 4 #include "config.h" 5 6 unsigned int GetResult(unsigned char ch); 7 8 #endif
定时器timer.c
1 #include "timer.h" 2 #include "config.h" 3 4 #include <STC12C5A60S2.H> 5 6 7 8 9 void Timer_Init() 10 { 11 TMOD |= BIT0;//16位定时器,模式1 12 13 TH0=(65536-5000)/256; // 5000us 14 TL0=(65536-5000)%256; 15 16 17 ET0=1; 18 TR0=1; 19 20 // AUXR=0X94; //辅助寄存器开启定时器T2,启动定时器T2,配置T0,T2时钟为 1T模式 (比STC15C5A 1T 模式快 20%) 21 22 // EA=1; 23 24 25 26 27 }
定时器头文件timer.h
1 #ifndef _TIMER_H_ 2 #define _TIMER_H_ 4 5 void Timer_Init();
模数转换adc.c
1 #include "adc.h" 2 #include <STC12C5A60S2.H> 3 #include "intrins.h" 4 5 /*Define ADC operation const for ADC_CONTR*/ 6 #define ADC_POWER 0x80 //ADC power control bit 7 #define ADC_FLAG 0x10 //ADC complete flag 8 #define ADC_START 0x08 //ADC start control bit 9 #define ADC_SPEEDLL 0x00 //420 clocks 10 #define ADC_SPEEDL 0x20 //280 clocks 11 #define ADC_SPEEDH 0x40 //140 clocks 12 #define ADC_SPEEDHH 0x60 //70 clocks 13 14 void InitADC() 15 { 16 P1ASF = 0x50; //P14,P16为AD输入 17 ADC_RES = 0; 18 ADC_CONTR = ADC_POWER|ADC_SPEEDL; 19 } 20 21 unsigned int GetADCResult(unsigned char ch) 22 { 23 unsigned int AD_result; 24 ADC_RES = 0; 25 ADC_RESL = 0; 26 ADC_CONTR = ADC_POWER | ADC_SPEEDL | ch | ADC_START; 27 _nop_(); //Must wait before inquiry 28 _nop_(); 29 _nop_(); 30 _nop_(); 31 _nop_(); 32 _nop_(); 33 _nop_(); 34 _nop_(); 35 36 while (!(ADC_CONTR & ADC_FLAG));//Wait complete flag 37 38 ADC_CONTR &= ~ADC_FLAG; //Close ADC 39 AD_result = ADC_RES; 40 AD_result <<= 2; 41 AD_result += ADC_RESL; 42 43 return AD_result; //Return ADC result 10bit 44 }
模数转换头文件adc.h
1 #ifndef _adc_h_ 2 #define _adc_h_ 3 4 5 #include "config.h" 6 7 void InitADC(); 8 unsigned int GetADCResult(unsigned char ch); 9 10 //unsigned int GetResult(unsigned char ch); 11 12 13 14 15 16 17 18 #endif
串口通讯(测试)uart.c
1 #include "uart.h" 2 #include "config.h" 3 4 #ifdef USER_TEST 5 6 /*---------------------------- 7 Initial UART 8 ----------------------------*/ 9 void InitUart() 10 { 11 TMOD |= BIT5; //T1 as 8-bit auto reload 12 // TMOD = 0x20; //T1 as 8-bit auto reload 13 SCON = 0x5a; //8 bit data ,no parity bit 14 TH1 = TL1 = -(FOSC/12/32/BAUD); //Set Uart baudrate 15 TR1 = 1; //T1 start running 16 } 17 #endif 18 ///*---------------------------- 19 //Send one byte data to PC 20 //Input: dat (UART data) 21 //Output:- 22 //----------------------------*/ 23 //void SendData(uint8_t dat) 24 //{ 25 // while (!TI); //Wait for the previous data is sent 26 // TI = 0; //Clear TI flag 27 // SBUF = dat; //Send current data 28 //}
串口通讯(测试)uart.h
1 #ifndef _uart_h_ 2 #define _uart_h_ 3 #include "config.h" 4 5 void InitUart(); 6 void SendData(uint8_t dat); 7 8 9 #endif
脉宽调制pwm.c
1 #include "pwm.h" 2 #include <STC12C5A60S2.H> 3 //#include <STC15F2K60S2.H> 4 5 #include "config.h" 6 7 /* 8 PCA时钟频率由CCON中的 CPS2,CPS1,CPS0决定,FOSC分频系数 9 PWM频率 = PCA时钟频率/256;(8位PWM) 10 eg: 11 FOSC = 24000000HZ; 12 CPS2:CPS1:CPS0 = 1:0:0 FOSC不分频,为FOSC时钟频率,即 PCA时钟=FOSC=24000000HZ; 13 PWM频率 = 24000000/256 = 93KHz 14 15 占空比控制由 CCAP1L和CCAP1H控制,CL和CCAP1L比较,CL>=CCAP1L时,PWM口输出1(高电平),反之亦然。 16 eg: 17 当工作在8位模式时, 18 CCAP1L = CCAP1H =0x7F; 占空比位50% 19 20 21 */ 22 23 void pwm0_init() 24 { 25 CMOD = 0X08 ; //选择系统时钟 26 CCON= 0x00; 27 CL= 0x00; 28 CH= 0x00; 29 PCA_PWM0= 0x00; 30 CCAPM0= 0x42; //8位PWM,无中断 31 CCAP0L = CCAP0H =0x00; 32 // CCON= 0x40; //允许PAC计数 33 CR = 1 ; 34 } 35 36 void pwm_updata(uint16_t pwm_data) 37 { 38 // uint16_t pwm_temp; 39 // pwm_data = 100-pwm_data; 40 // pwm_temp = pwm_data<<8; 41 // pwm_temp =(uint8_t)(pwm_temp/100); 42 // CCAP1L = CCAP1H =pwm_temp; 43 CCAP0L = CCAP0H = pwm_data; 44 45 }
脉宽调制pwm.h
1 #ifndef _pwm_h_ 2 #define _pwm_h_ 3 4 //#include "user_config.h" 5 #include "config.h" 6 void pwm0_init(); 7 8 void pwm_updata(uint16_t pwm_data); 9 10 #endif
eerom.c
1 #include <STC12C5A60S2.H> 2 #include "eeprom.h" 3 #include "delay.h" 4 5 #define CMD_READ 1 //IAP字节读命令 6 #define CMD_PROGRAM 2 //IAP字节编程 7 #define CMD_ERASE 3 //IAP扇区擦除命令 8 9 #define ENABLE_IAP 0X82 //SYSCLK<12MHz 10 #define IAP_ADDRESS 0X0000 11 12 void iap_idle() 13 { 14 IAP_CONTR = 0X00 ; //关闭IAP功能 15 IAP_CMD = 0 ; //清除指令待机 16 IAP_TRIG = 0X00 ; //清空触发器寄存器 17 IAP_ADDRH =0X80; //将地址设置到非IAP地址 18 IAP_ADDRL=0X00; 19 20 21 } 22 23 uint8_t read_eeprom( uint16_t read_adder) 24 { 25 uint8_t read_eerom_tmp_data; 26 IAP_CONTR = ENABLE_IAP ; //使能IAP 27 IAP_CMD = CMD_READ; //读eeprom命令 28 IAP_ADDRL = read_adder; 29 IAP_ADDRH = read_adder>>8; //首地址高位 30 IAP_TRIG = 0x5a; //启动命令 31 IAP_TRIG = 0xa5; 32 delay_1us(10); 33 read_eerom_tmp_data =IAP_DATA; 34 iap_idle(); 35 return read_eerom_tmp_data; 36 } 37 38 void write_eeprom(uint16_t write_adder,uint8_t write_dat) 39 { 40 /* 41 1 IAP_DATA 数据寄存器,从此处读,向此处写入 42 2 IAP_ADDRH 数据地址 43 IAP_ADDRL 44 3 IAP_CMD 45 00 无操作 46 01 读 47 02 编程 48 03 擦除 49 4 IAP_TRIG 50 当IAPEN(IAP_CONTR.7)=1时, 51 依次写入5A、A5,IAP才启动命令 52 5 IAP_CONTR 53 .7 0禁止操作 1允许操作 54 .6 0从应用程序启动 1从ISP程序启动 55 .5 0不操作 1单片机自复位 56 .4 地址失效并发送了操作命令引得操作失败,则为1 57 .3 空 58 .2.1.0 选100,系统频率>=6MHz 59 6 PCON .5 为1,则电压偏低,需软件清零 60 读一字节 2个时钟 61 写一字节 55us 62 扇区擦除 21ms 63 */ 64 IAP_CONTR = ENABLE_IAP ; //使能IAP 65 IAP_CMD = CMD_PROGRAM;//编程 66 67 IAP_ADDRL = write_adder; 68 IAP_ADDRH = write_adder>>8; //首地址高位 69 IAP_DATA = write_dat; 70 IAP_TRIG = 0x5a; //启动命令 71 IAP_TRIG = 0xa5; 72 delay_1us(10); 73 iap_idle(); 74 75 } 76 77 void clean_iap(uint16_t clean_adder) //擦除扇区 78 { 79 IAP_CONTR = ENABLE_IAP ; //使能IAP 80 IAP_CMD=CMD_ERASE; 81 IAP_ADDRH=clean_adder>>8; 82 IAP_ADDRL=clean_adder; 83 IAP_TRIG = 0x5a; //启动命令 84 IAP_TRIG = 0xa5; 85 delay_1us(10); 86 iap_idle(); 87 88 89 } 90
eerom.h
1 #ifndef _eeprom_h_ 2 #define _eeprom_h_ 3 4 #include "config.h" 5 void iap_idle(); 6 7 uint8_t read_eeprom( uint16_t read_adder); 8 9 void write_eeprom(uint16_t write_adder,uint8_t write_dat); 10 11 void clean_iap(uint16_t clean_adder) ; //擦除扇区 12 13 #endif
delay.c
1 #include "delay.h" 2 3 4 5 //void delay(unsigned char ms) 6 //{ 7 // unsigned int x, y; 8 // for (x=ms; x>0; x--) 9 // for (y=110; y>0; y--); 10 11 //} 12 13 14 void delay_1us(unsigned int us) 15 { 16 unsigned int x, y; 17 for (x=us; x>0; x--) 18 for (y=500; y>0; y--); 19 }
delay.h
1 #ifndef _delay_h_ 2 #define _delay_h_ 3 4 void delay(unsigned char ms); 5 6 void delay_1us(unsigned int us); 7 8 9 10 11 12 #endif
中断interrupt.c
1 #include "interrupt.h" 2 #include "user_timer.h" 3 #include "adc.h" 4 5 //#include "user_key.h" 6 //#include "key.h" 7 8 #include "config.h" 9 10 11 extern uint16_t timer0_time_cnt; 12 13 14 15 void timer0(void) interrupt 1 //定时器T0中断函数入口 //500us进一次中断 10usX100=1000us=1ms f=1/1ms=1Khz 16 { 17 TH0=(65536-5000)/256; // 5000us 18 TL0=(65536-5000)%256; 19 20 timer0_time_cnt ++ ; //自定义定时查询使用 21 }
中断interrupt.h
1 #ifndef _INTERRUPT_H_ 2 #define _INTERRUPT_H_ 3 4 //#include <STC12C5A60S2.H> 5 6 7 #endif
gpio.c
1 #include "gpio.h" 2 #include "config.h" 3 4 5 void gpio_init() 6 { 7 P1M0 &= ~(BIT0|BIT1) ; // P10 ,P11 设置为输入 8 P1M1 |= (BIT0|BIT1) ; 9 10 11 P1M0 |= BIT3 ; // P13 设置为推挽输出 12 P1M1 &= ~BIT3 ; 13 14 P1M0 &= ~(BIT4|BIT6); // P14,P16设置为高阻态 15 P1M1 |= (BIT4|BIT6); 16 17 18 P2M0 |= (BIT0|BIT1|BIT4) ; // P20,P21,P24 设置为推挽输出 19 P2M1 &= ~(BIT0|BIT1|BIT4) ; 20 21 // P2M0 &= ~BIT5 ; // P25 设置为输入 22 // P2M1 |= BIT5 ; 23 24 }
gpio.h
1 #ifndef _GPIO_H_ 2 #define _GPIO_H_ 3 4 void gpio_init(); 5 6 7 #endif
按键user_key.c
1 #include "user_key.h" 2 #include "config.h" 3 #include "user_timer.h" 4 #include <stdio.h> 5 6 static uint8_t idata key_event_flag = 0; 7 static uint8_t key_event = 0 ; 8 9 10 void user_key_init() 11 { 12 key_event_flag = KEY_NOT_ACTION ; 13 } 14 15 16 unsigned char user_key_scan_even( bit KEY ) 17 { 18 static bit key_state = 1 ; 19 static uint8_t key_step = 0; 20 // static uint8_t key_event; 21 key_state = KEY ; 22 23 #if Key_Default_State 24 key_state = key_state ; 25 26 #else 27 key_state = !key_state ; // 按键未被触发时电平 28 #endif 29 30 31 32 switch( key_step) 33 { 34 case 0: 35 if( key_state ) // 第0步,按键未被触发 36 { 37 key_event = KEY_NOT_ACTION ; //无操作 38 clear_time_cnt(KEY_TRIGGER_TIMER_NUMBER); // 清除消抖时间 39 } 40 else 41 key_step++; // 按键触发 ,进入第1步 42 break; 43 44 case 1: 45 if( key_state ) // 再次确认按键是否按下 , 46 key_step--; // 若没有,则返回第0步 47 else // 如确认按键按下 48 { 49 if(check_time_arrive(KEY_TRIGGER_TIMER_NUMBER, KEY_TRIGGER_TIMER)) // 检查按键按下时间,是否超过设定消抖时间 ,若超过 50 { 51 clear_time_cnt(KEY_TRIGGER_TIMER_NUMBER); // 清除消抖时间 52 53 key_step++; // 进入 第2步 54 } 55 } 56 break; 57 58 case 2: 59 if( key_state ) // 若超过设定消抖时间后,按键弹起 60 { 61 clear_time_cnt(KEY_TRIGGER_TIMER_NUMBER); // 清除消抖时间 62 key_step++; // 进入第3部 63 } 64 else // 若超过设定消抖时间后,按键还未被释放 65 { 66 if(check_time_arrive(KEY_TRIGGER_TIMER_NUMBER, KEY_LONG_PRESS_TIME)) //检查按键按下时间是否超过 长按设定时间 ,若超过 67 { 68 key_event = KEY_LONG_PRESS_ACTION; // 发生长按 动作 69 key_step += 2; // 进入第4步 70 } 71 } 72 break; 73 case 3: 74 if( key_state ) // 按键被释放 75 { 76 if(check_time_arrive(KEY_TRIGGER_TIMER_NUMBER, KEY_TRIGGER_TIMER)) // 检查释放时间是否满足 消抖时间 ,若满足 77 { 78 key_event = KEY_CLICK_ACTION; // 则发生 单击 动作 79 key_step = 0; // 返回 第 0 步 80 } 81 } 82 else // 若按键释放时间 未满足 消抖时间 ,则 83 { 84 clear_time_cnt(KEY_TRIGGER_TIMER_NUMBER); // 清除消抖时间 85 key_step--; // 返回 第3步 ,继续判断按键按下时间, 86 } 87 break; 88 case 4: 89 if( key_state) // 长按 按键释放后 90 { 91 if(check_time_arrive(KEY_TRIGGER_TIMER_NUMBER, KEY_TRIGGER_TIMER)) //检查长按按键 释放 时间是否满足 按键消抖时间 92 { 93 key_event = KEY_LONG_RELEASE_ACTION; // 则 发生 长按 动作 94 key_step = 0; // 返回 第 0 步 95 } 96 } 97 break; 98 default: 99 break; 100 } 101 102 return key_event; 103 } 104 105 void user_key_scan( bit KEY ) 106 { 107 uint8_t key_temp; 108 static uint8_t key_step = 0; 109 key_temp = user_key_scan_even( KEY); //获取单击、长按 110 switch( key_step ) 111 { 112 case 0: 113 { 114 if(key_temp == KEY_CLICK_ACTION ) //单击动作 115 { 116 key_step = 1 ; 117 clear_time_cnt(KEY_TWO_TRIGGER_TIME_NUMBER); //清除时间 118 } 119 else //其他按键类型,直接返回 120 { 121 key_event_flag = key_temp ; 122 key_event = 0 ; 123 } 124 };break; 125 126 case 1 : 127 { 128 if(key_temp == KEY_CLICK_ACTION ) //单击动作 129 { 130 key_event_flag = KEY_TWO_ACTION ; //双击动作 131 key_step = 0 ; 132 133 } 134 else if( check_time_arrive(KEY_TWO_TRIGGER_TIME_NUMBER , KEY_TWO_TRIGGER_TIME )) 135 { 136 key_event_flag = KEY_CLICK_ACTION ; 137 key_step = 0 ; 138 } 139 };break; 140 default : break; 141 } 142 } 143 144 uint8_t return_key_state() //返回按键 事件值 145 { 146 return key_event_flag ; 147 148 } 149 150 151 void rest_key_state() //按键释放 152 { 153 key_event_flag = KEY_NOT_ACTION ; 154 }
按键user_key.h
1 #ifndef _USER_KEY_ 2 #define _USER_KEY_ 3 #include "config.h" 4 5 #define Key_Default_State 1 //按键未触发状态 【 1:高电平 0: 低电平 】 6 7 #define KEY_NOT_ACTION 0 // 按键无动作 8 #define KEY_CLICK_ACTION 1 // 单击动作 9 #define KEY_LONG_PRESS_ACTION 3 // 长按动作 ----> 长按按键触发状态 10 #define KEY_LONG_RELEASE_ACTION 4 // 长按动作 ----> 长按按键释放 11 12 #define KEY_TWO_ACTION 5 //双击 13 14 void user_key_init(); 15 unsigned char user_key_scan_even( bit KEY ); 16 17 void user_key_scan(bit KEY); 18 uint8_t return_key_state(); 19 void rest_key_state(); 20 21 22 23 24 #endif
时间user_timer.c
1 #include "user_timer.h" 2 #include "config.h" 3 #include "interrupt.h" 4 5 uint16_t timer0_time_cnt = 0 ; 6 7 static uint16_t user_timer_array[USER_TIMER_AMOUNT] = {0}; 8 static uint16_t timeout_control_array[USER_TIMER_AMOUNT] = {0}; 9 10 void user_timer_init(void) // 数组初始化 11 { 12 uint8_t i = 0; 13 for(i = 0; i < USER_TIMER_AMOUNT; i++) 14 { 15 user_timer_array[i] = 0; 16 timeout_control_array[i] = 0; 17 } 18 } 19 20 /********************* 21 function: 22 The system reference time is added to the user time array. 23 parameter: 24 null 25 return: 26 null 27 *********************/ 28 void add_system_time(void) // 添加 时间 (放主循环) 29 { 30 uint8_t i = 0 ; 31 uint16_t temp ; 32 33 temp = timer0_time_cnt; 34 timer0_time_cnt = 0; 35 36 for(i = 0; i < USER_TIMER_AMOUNT; i++) 37 { 38 if(user_timer_array[i] <= timeout_control_array[i]) 39 user_timer_array[i] += temp; 40 41 } 42 } 43 44 45 46 /********************* 47 function: 48 Clear the user time count. 49 parameter: 50 USER_TIMER0_CNT ...... USER_TIMERN_CNT or user typedef name 51 return: 52 null 53 *********************/ 54 void clear_time_cnt(uint8_t time_number) // 清除时间 55 { 56 if(USER_TIMER_AMOUNT > time_number) 57 user_timer_array[time_number] = 0; 58 } 59 60 61 /********************* 62 function: 63 time if arrived 64 parameter: 65 <time_number> 66 USER_TIMER0_CNT ...... USER_TIMERN_CNT or user typedef name 67 <time> 68 check time 69 return: 70 null 71 *********************/ 72 73 74 75 76 uint8_t check_time_arrive(uint8_t time_number, uint16_t time) // 检查设定时间,是否到达 77 { 78 if(USER_TIMER_AMOUNT > time_number) 79 { 80 timeout_control_array[time_number] = time; 81 82 if(time <= user_timer_array[time_number]) 83 { 84 85 return 1; 86 } 87 else 88 return 0; 89 } 90 return 0; 91 }
时间user_time.h
1 #ifndef _USER_TIMER_ 2 #define _USER_TIMER_ 3 4 #include "config.h" 5 6 void user_timer_init(void); 7 void add_system_time(void); // 添加 时间 (放主循环) 8 9 void clear_time_cnt(uint8_t time_number); // 清除时间 10 11 uint8_t check_time_arrive(uint8_t time_number, uint16_t time); 12 13 #endif
管脚分配如下:
P10 ------ 光敏、人体感应(1--无触发, 0---- 触发)
P11 ------ 按键
P13 ----- PWM 灯光亮度调节
P14 ------ 电池电压输入
P16 ------ TL431 +2.5V 基准输入
P20 ------ 充电控制 1--- 开 ; 0---- 关
P21 ------ 灯光模式指示LED(蓝灯)
P24 ------ 灯光指示模式LED(红灯)
P22,P23 -------- 人体检测时间 【 1:1 -- 3分钟; 0:1 --- 6分钟; 1:0 -- 9分钟; 0:0 -- 12分钟; 】
来几张照片:
文末,在此希望这次疫情赶快去,祝愿中国加油,湖北加油,武汉加油!!!!!!!!!!!!!!!!!!!
操作
来源:https://www.cnblogs.com/UPUPDay2152/p/12313106.html