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分鍾; 】
來幾張照片:
文末,在此希望這次疫情趕快去,祝願中國加油,湖北加油
,武漢加油
!!!!!!!!!!!!!!!!!!!