台燈改造【智能台燈】


  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分鍾; 】

來幾張照片:

文末,在此希望這次疫情趕快去,祝願中國加油,湖北加油,武漢加油!!!!!!!!!!!!!!!!!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM