-
Notifications
You must be signed in to change notification settings - Fork 0
/
Bike_Lampe.cpp
507 lines (432 loc) · 15.5 KB
/
Bike_Lampe.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
/******************************************************************************
* alternative software for a *
* Solarstorm X2 bike flashlight *
* uC Attiny44,84 and https://github.com/SpenceKonde/ATTinyCore *
* Author: Space Teddy *
*******************************************************************************/
//****************************** includes *************************************
#include <Arduino.h>
#include <avr/eeprom.h>
#include <SoftwareSerial.h>
//************************* Tiny Core defines *********************************
#define ATTINY_CORE 1 //- Attiny Core
//#define ATTINYX4 1
#define USE_SOFTWARE_SERIAL 1 // (0 = hardware serial, 1 = software serial)
#define HAVE_ADC 1 // (1 = has ADC functions)
//************************ Application defines ********************************
#define LED_100_75 7 //Battery voltage indicator LED 100% to 75%
#define LED_75_50 4 //Battery voltage indicator LED 75% to 50%
#define LED_50_25 8 //Battery voltage indicator LED 50% to 25%
#define BUTTON 0 //control button input pin
#define MOSFET_GATE 2 //PWM output for front light dimming
#define NTC_VOLTAGE 1 //analog input pin for temperature via NTC
#define VBAT_VOLTAGE 0 //analog input pin for battery undervoltage detection
#define LIGHT_STATE_OFF 0 //various light states
#define LIGHT_STATE_ON_P1 1
#define LIGHT_STATE_ON_P2 2
#define LIGHT_STATE_ON_P3 3
#define LIGHT_STATE_ON_P4 4
#define LIGHT_STATE_SETUP 5
#define LIGHT_STATE_SETUP_P1 6
#define LIGHT_STATE_SETUP_P2 7
#define LIGHT_STATE_SETUP_P3 8
#define LIGHT_STATE_SETUP_P4 9
#define LIGHT_STATE_SETUP_EXIT 10
#define SETUP_ENTRY_TIME 3000 //3 seconds button press to enter profile setup
#define LIGHT_DEFAULT_P1 2 //profile 1-4 default values
#define LIGHT_DEFAULT_P2 64
#define LIGHT_DEFAULT_P3 128
#define LIGHT_DEFAULT_P4 255
#define ADC_RESOLUTION 48 //ADC resulution is 4.8mV
#define ADC_VBAT_DEVIDER 6 //factor of Vbat voltage devider
#define ADC_NSAMPLES 8 //count of ADC avarage samples
#define BATTERY_75 236 //75% battery limit 6,925V aka 1,154V
#define BATTERY_50 220 //50% battery limit 6,45V aka 1.075V
#define BATTERY_25 203 //25% battery limit 5,975V aka 0,996V
#define BATTERY_SHUTOFF 187 //battery undervoltage protection limit 5,5V aka 0,91666V
#define TEMP_70_HIGH 258 //assumption NTC has B=3800 and R=10k@25°C
#define TEMP_75_SHUTOFF 224
#define EEPROM_ADDRESS_PROFILE1 0x10 //profile 1-4 EEPROM adresses
#define EEPROM_ADDRESS_PROFILE2 0x11
#define EEPROM_ADDRESS_PROFILE3 0x12
#define EEPROM_ADDRESS_PROFILE4 0x13
#define VERSION 1 //Version of X2 firmware
#define DEBUG 1 //Debug enable = 1
//************************* global variables **********************************
uint8_t light_state = 0;
uint8_t pwm = 0; //actual pwm in use
//******************************* objects *************************************
#if DEBUG == 1
SoftwareSerial Debug(3,4); //(RX,TX) pin number
#endif
//****************************** functions ************************************
//----------------------------- ADV average -----------------------------------
uint16_t analogRead_avg( uint8_t channel, uint8_t nsamples )
{
uint32_t sum = 0;
for (uint8_t i = 0; i < nsamples; ++i ) {
sum += analogRead( channel );
}
#if DEBUG == 1
Debug.print(F("ADC:"));Debug.println((uint16_t)( sum / nsamples ),DEC); //ADC value Debug
#endif
return (uint16_t)( sum / nsamples );
}
//-------------------------- set pwm dutycycle -------------------------------
uint8_t set_pwm_dutycycle(uint8_t pwm_value) //set front lights with fading
{
if(pwm_value == 0)
{
analogWrite(MOSFET_GATE,0);
return pwm_value;
}
if(pwm_value > pwm)
{
while(pwm != pwm_value)
{
analogWrite(MOSFET_GATE,pwm++);
delay(5);
}
}
if(pwm_value <= pwm)
{
while(pwm != pwm_value)
{
analogWrite(MOSFET_GATE,pwm--);
delay(5);
}
}
#if DEBUG == 1
Debug.print(F("PWM:"));Debug.println(pwm_value,DEC);
#endif
return pwm_value;
}
//---------------------- setup profile pwm dutycycle --------------------------
uint8_t setup_profile_pwm_dutycycle(uint8_t profile) //set front lights with fading
{
uint8_t pwm_value;
while(digitalRead(BUTTON) == LOW)
{
analogWrite(MOSFET_GATE,pwm_value++);
#if DEBUG == 1
Debug.print("PWM:");Debug.println(pwm_value,DEC);
#endif
delay(25);
if(pwm_value > 255)
{
pwm_value = 0;
}
}
return pwm_value;
}
//------------------------ check battery voltage ------------------------------
uint16_t get_battery_voltage(void)
{
uint16_t battery_adc = 0;
static uint8_t ledState = LOW; //ledState used to set the LED
static uint32_t previousMillis = 0; //will store last time LED was updated
const uint16_t interval = 500; //interval at which to blink (milliseconds)
battery_adc = analogRead_avg(VBAT_VOLTAGE, ADC_NSAMPLES);
#if DEBUG == 1
Debug.print(F("Vbat:"));Debug.println(battery_adc,DEC);delay(5);
#endif
if(battery_adc >= BATTERY_75)
{
digitalWrite(LED_100_75, HIGH);
digitalWrite(LED_75_50, HIGH);
digitalWrite(LED_50_25, HIGH);
#if DEBUG == 1
Debug.println(F("Batt_100-75%"));
#endif
}
if(battery_adc < BATTERY_75 && battery_adc >= BATTERY_50)
{
digitalWrite(LED_100_75, LOW);
digitalWrite(LED_75_50, HIGH);
digitalWrite(LED_50_25, HIGH);
#if DEBUG == 1
Debug.println(F("Batt_75-50%"));
#endif
}
if(battery_adc < BATTERY_50 && battery_adc >= BATTERY_25)
{
digitalWrite(LED_100_75, LOW);
digitalWrite(LED_75_50, LOW);
digitalWrite(LED_50_25, HIGH);
#if DEBUG == 1
Debug.println(F("Batt_50-25%"));
#endif
}
if(battery_adc < BATTERY_25 && battery_adc >= BATTERY_SHUTOFF)
{
uint32_t currentMillis = millis();
if(currentMillis - previousMillis > interval)
{
previousMillis = currentMillis; //save the last time you blinked the LED
if (ledState == LOW) //if the LED is off turn it on and vice-versa:
ledState = HIGH;
else
ledState = LOW;
digitalWrite(LED_50_25, ledState);
#if DEBUG == 1
Debug.print(F("Batt_<25% "));Debug.println(ledState,DEC);
#endif
}
}
if(battery_adc < BATTERY_SHUTOFF)
{
pwm = set_pwm_dutycycle(0); //battery undervoltage switch OFF front lights
for(uint8_t i=0;i<10;i++)
{
#if DEBUG == 1
Debug.println(F("Battery shutoff"));
#endif
digitalWrite(LED_100_75, HIGH);
digitalWrite(LED_75_50, HIGH);
digitalWrite(LED_50_25, HIGH);
delay(500);
digitalWrite(LED_100_75, LOW);
digitalWrite(LED_75_50, LOW);
digitalWrite(LED_50_25, LOW);
delay(500);
}
while(1); //halt
}
return 1;
}
//-------------------------- check temperature -------------------------------
uint16_t get_temperature(void)
{
uint16_t temperature_adc = 0;
temperature_adc = analogRead_avg(NTC_VOLTAGE, ADC_NSAMPLES);
#if DEBUG == 1
Debug.print(F("T_ADC:"));Debug.println(temperature_adc,DEC);delay(1000); //Temperature ADC value Debug
#endif
if(temperature_adc <= TEMP_70_HIGH && temperature_adc > TEMP_75_SHUTOFF)
{
#if DEBUG == 1
Debug.println(F("TEMP HIGH"));
#endif
pwm = set_pwm_dutycycle(10); //Temp switch OFF front lights indication
}
if(temperature_adc <= TEMP_75_SHUTOFF)
{
#if DEBUG == 1
Debug.println(F("TEMP shutoff"));
#endif
for(uint8_t i=0;i<10;i++)
{
pwm = set_pwm_dutycycle(2); //Temp switch OFF front lights indication
digitalWrite(LED_100_75, HIGH);
digitalWrite(LED_75_50, HIGH);
digitalWrite(LED_50_25, HIGH);
delay(500);
pwm = set_pwm_dutycycle(0); //Temp switch OFF front lights indication
digitalWrite(LED_100_75, LOW);
digitalWrite(LED_75_50, LOW);
digitalWrite(LED_50_25, LOW);
delay(500);
}
pwm = set_pwm_dutycycle(0); //finally switch OFF front lights
delay(5000); //wait 5 sec. for cooling down
}
return temperature_adc;
}
//----------------------- set_bike_light_profiles ------------------------------
uint8_t set_bike_light_profile(uint8_t profile, uint8_t pwm_value)
{
if(profile == 1)
{
eeprom_write_byte((uint8_t*)EEPROM_ADDRESS_PROFILE1,pwm_value); //
}
if(profile == 2)
{
eeprom_write_byte((uint8_t*)EEPROM_ADDRESS_PROFILE2,pwm_value); //
}
if(profile == 3)
{
eeprom_write_byte((uint8_t*)EEPROM_ADDRESS_PROFILE3,pwm_value); //
}
if(profile == 4)
{
eeprom_write_byte((uint8_t*)EEPROM_ADDRESS_PROFILE4,pwm_value); //
}
#if DEBUG == 1
Debug.print(F("Profile"));Debug.print(profile,DEC);Debug.print(F(":"));Debug.println(pwm_value,DEC);
#endif
return 1;
}
//----------------------- get_bike_light_profiles ------------------------------
uint8_t get_bike_light_profile(uint8_t profile)
{
uint8_t profilex;
//reads setting parameters from eeprom
if(profile == 0)
{
profilex = 0; //OFF
}
if(profile == 1)
{
profilex = eeprom_read_byte((const uint8_t*)EEPROM_ADDRESS_PROFILE1); //reads out saved My_addr byte
}
if(profile == 2)
{
profilex = eeprom_read_byte((const uint8_t*)EEPROM_ADDRESS_PROFILE2); //reads out saved My_addr byte
}
if(profile == 3)
{
profilex = eeprom_read_byte((const uint8_t*)EEPROM_ADDRESS_PROFILE3); //reads out saved My_addr byte
}
if(profile == 4)
{
profilex = eeprom_read_byte((const uint8_t*)EEPROM_ADDRESS_PROFILE4); //reads out saved My_addr byte
}
#if DEBUG == 1
Debug.print(F("PWM:"));Debug.println(profilex,DEC);
#endif
return profilex;
}
//----------------------------- check default profile -----------------------------------
void check_default_profile(void)
{
uint8_t profile_arr[5];
for(uint8_t i=1;i<5;i++)
{
profile_arr[i] = get_bike_light_profile(i);
#if DEBUG == 1
Debug.print(profile_arr[i],DEC);Debug.print(F(";"));
#endif
}
#if DEBUG == 1
Debug.println(F(""));
#endif
if( profile_arr[1] == 255 && profile_arr[2] == 255 && profile_arr[3] == 255 && profile_arr[4] == 255)
{
set_bike_light_profile(1, LIGHT_DEFAULT_P1);
set_bike_light_profile(2, LIGHT_DEFAULT_P2);
set_bike_light_profile(3, LIGHT_DEFAULT_P3);
set_bike_light_profile(4, LIGHT_DEFAULT_P4);
}
}
//----------------------------- check button -----------------------------------
uint8_t check_button(void) //set front lights with fading
{
uint32_t time_start = 0;
uint32_t time_stop = 0;
if(digitalRead(BUTTON) == LOW)
{
delay(150);
light_state++;
if(light_state > LIGHT_STATE_ON_P4)
{
light_state = LIGHT_STATE_OFF;
pwm = set_pwm_dutycycle(0);
}
#if DEBUG == 1
Debug.print("Light State:");Debug.println(light_state,DEC);
#endif
pwm = set_pwm_dutycycle(get_bike_light_profile(light_state));
time_start = millis();
#if DEBUG == 1
Debug.print(F("time_start:"));Debug.println(time_start,DEC);
#endif
while(digitalRead(BUTTON) == LOW){ //checks long button press
time_stop = millis();
#if DEBUG == 1
Debug.print(F("time_stop:"));Debug.println(time_stop,DEC);
#endif
if(time_stop > (time_start + SETUP_ENTRY_TIME) && light_state < LIGHT_STATE_SETUP) //if button is pressed for 3 seconds then go to setup
{
light_state = LIGHT_STATE_SETUP; //now you're in general profile setup
pwm = set_pwm_dutycycle(0);
#if DEBUG == 1
Debug.println(F("Light PWM SETUP:"));
#endif
digitalWrite(LED_100_75, LOW);
digitalWrite(LED_75_50, LOW);
digitalWrite(LED_50_25, HIGH);
delay(1000);
for(uint8_t i=1;i<5;i++)
{
while(digitalRead(BUTTON) == HIGH){
if(i==1)
{
digitalWrite(LED_100_75, LOW);
digitalWrite(LED_75_50, LOW);
digitalWrite(LED_50_25, HIGH);
}
if(i==2)
{
digitalWrite(LED_100_75, LOW);
digitalWrite(LED_75_50, HIGH);
digitalWrite(LED_50_25, HIGH);
}
if(i==3)
{
digitalWrite(LED_100_75, HIGH);
digitalWrite(LED_75_50, LOW);
digitalWrite(LED_50_25, HIGH);
}
if(i==4)
{
digitalWrite(LED_100_75, HIGH);
digitalWrite(LED_75_50, HIGH);
digitalWrite(LED_50_25, LOW);
}
}
delay(200);
if(digitalRead(BUTTON) == LOW )
{
light_state = LIGHT_STATE_SETUP + i;
#if DEBUG == 1
Debug.print(F("Light SETUP:"));Debug.println(light_state - 5,DEC);
#endif
pwm = setup_profile_pwm_dutycycle(i);
#if DEBUG == 1
Debug.print(F(" PWM:"));Debug.println(pwm,DEC);
#endif
set_bike_light_profile(i, pwm);
}
delay(500);
}
light_state = LIGHT_STATE_OFF;
return light_state;
}
}
}
return light_state;
}
//******************************* setup ***************************************
void setup()
{
pinMode(LED_100_75,OUTPUT); //*********************************
pinMode(LED_75_50,OUTPUT); //* *
pinMode(LED_50_25,OUTPUT); //* I/O pin configuration *
pinMode(MOSFET_GATE,OUTPUT); //* *
pinMode(BUTTON,INPUT_PULLUP); //* *
//*********************************
#if DEBUG == 1
Debug.begin(115200); //setup DebugSerial to 115200baud
#endif
analogReference(DEFAULT); //analog reference voltage 5V
#if DEBUG == 1
Debug.print(F("X2")); //welcome message
#endif
check_default_profile(); //checks if EEPROM has no profile saved
#if DEBUG == 1
Debug.print(F("Light State:"));Debug.print(LIGHT_STATE_OFF,DEC);
#endif
light_state = LIGHT_STATE_OFF; //light is OFF
while(digitalRead(BUTTON) == HIGH){ //connected to battery but in OFF mode
get_battery_voltage(); //only temp and battery voltage is measured
get_temperature(); //for battery energy indicator LED's
}
delay(100); //100ms button debounce delay
}
//******************************* main loop ***********************************
void loop()
{
check_button();
get_battery_voltage();
get_temperature();
}