其他选项2020年春节,由于受疫情的限制,另外博主也是疫情的重灾区-湖北省襄阳市,一方面响应国家的号召“在家不论跑就是最大的贡献”,另一方也是在家闲不住,于是又准备捣鼓捣鼓前两年改造的台灯,前两年在家改造的台灯,改造完后就去上学去了,今年回来,经爸妈的反馈,在实际使用过程中,还是不好用,但之前的程序没有存档,于是乎,又重新列出了,台灯的几个功能:
1、台灯分两个功能模式:自动模式和手动模式;
2、自动模式----白天自动熄灯;晚上检测到人体后开灯,若人体在一定时间内移动,则灯一直开灯不熄灭,当超过一定时间后,人体不移动或未检测到人体,则灯自动熄灭;---这一场景功能主要是方便晚上起夜上厕所;灯的亮度可调目前分为10个级别;-------这一场景功能主要是晚上上突然开启强光,眼睛会花眼;
3、自动模式----定时时间可调,分为2min,3min,4min,5min四中定时时间可调整;
4、手动模式---手动模式不论是白天还是黑夜都可以开启灯光,切灯光亮度可调10个亮度等级;------这一场景功能主要应用是有时白天需要使用台灯,或晚上看书或做别的事情,若灯光太亮,可以手动调节;
5、双电源自动切换----平时台灯插电,台灯使用的时电源适配器的供电,当出现停电状况,自动切换到锂电池供电;-----这一场景功能主要是我这边有时会停电,家里很不方便,自己也有好多18650电池,正好利用起来;
6、锂电池自动充电 -----当检测到锂电池电源过低时,启用自动充电给台灯内的电池充电,保证电池处于有电状态,以此应急停电;
7、USB充电------台灯另外一个功能也可以当做一个充电宝,目前手上有十几节电池,目前使用的是12节18650电池,一节容量2200mA,所以总容量大概 12x2200mA=26400mA;使用的模块是充电宝拆出来的模块,USB输出标称为5V1A;
8、按键功能------使用原有台灯按键,按键功能目前定义如下:单击---调节亮度;双击----关闭台灯;长按-----模式切换(自动模式和手动模式);
以上是自己目前想出来的几个主要功能,单片机使用的还是较为熟悉的STC12C5A60S2---DIP-40封装,电源基准使用的是从电脑电源电路板上拆的WL431,查了很多资料,没有查出和TL431是什么区别,还是没有查出来,于是自己完全按照TL431管脚实验了下,结果脚位相同,可是使用;MOS管使用的是F9540N和AO3400,使用双适配器5V供电,一路适配器输出电压给电路使用,一路专门给锂电池充电使用;
电路图如下:

由于是使用的充电宝改进的,存在一个问题就是,目前市面上大部分使用的充电宝方案为DW01、8025A单片机和MT5032,会出现一个弊端就是无法使用小电流模式下升压至5V,由于查了许多资料,最终锁定在MT5032这颗升压IC上,经测量发现MT5032管脚的EN使能端是连接在一颗SOP-14芯片上,猜想为一颗单片机,于是,把此管脚切开,直接和VCC接起来即1、2管脚连接起来,直接使能,可以解决这个问题,MT5032大致资料如下:



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








文末,在此希望这次疫情赶快去,祝愿中国加油
,湖北加油
,武汉加油
!!!!!!!!!!!!!!!!!!!
操作
来源:https://www.cnblogs.com/UPUPDay2152/p/12313106.html



