台灯改造【智能台灯】

  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( "双击操作发生!!
" );
 48             printf( "自动模式定时=%d
",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( "打开手动灯光
");
 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( "手动灯光亮度值增加
");
 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( "自动定时时间到!!
" );
123 #endif
124                             }
125                         }
126                         else
127                         {
128 //                              printf( "时间未到
" );
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( "打开自动灯光
");
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( "自动灯光亮度增加
");
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( "检测到人体
" );
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
" );
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
" );
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
" );
52 #endif
53 //                    V_BAT_SITCH_PIN =1;  //开启充电功能
54             }
55             else   //电池电压充电到达最大电压,关闭充电!
56             {
57 #ifdef USER_TEST
58                  printf( "电池状态=4
");
59 #endif
60               V_BAT_SITCH_PIN =0;  //关闭充电功能
61               battery_flag = 0 ;
62             }
63 #ifdef USER_TEST
64           printf( "电池电压值=%f
", ADC_V_BAT );
65             
66 //        if(P25 ==1 )
67 //        {
68 //                 printf( "充电器插上状态
" );
69 //        
70 //        }
71 //        else
72 //                 printf( "充电器无电压
" );
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