1

7 Commits

Author SHA1 Message Date
eleksir
92f8bc21cb Update README.md 2019-08-17 12:02:56 +03:00
eleksir
a212bbc28a Port changes from photoresistor branch
* Poll RTC by trigger, set via ISR
* Change blink state by trigger, set via ISR
* Set time compensation trigger in ISR
* Refresh clock by timer
* Re-calculate displayed time only ater rtcsync or when time adjusted by buttons
* Simplify draw algo
2019-08-17 11:50:23 +03:00
eleksir
7614c86dd9 Cherry-pick last commit from photoresistor branch 2019-06-12 12:51:27 +03:00
eleksir
90a8f53a49 Added tag v1.5 for changeset e2d9f51a55f1 2019-06-02 15:30:39 +03:00
eleksir
c29c1ee876 Added info about tags in default branch. 2019-06-02 15:30:06 +03:00
eleksir
68b8702396 Bring changes from tag v1.4 2019-06-02 15:27:04 +03:00
eleksir
9c800ee335 Added info about photoresistor branch to README.md 2019-05-21 16:13:41 +03:00
3 changed files with 35 additions and 168 deletions

View File

@@ -12,8 +12,6 @@
* usb phone charger as power supply * usb phone charger as power supply
* 2 push buttons * 2 push buttons
* 1 on/off switch * 1 on/off switch
* 1 photoresistor
* 1 resistor to make secund shoulder of photosensitive "bridge", 10 kOhms, 0.25 watts
* Gainta G521G enclosure (92x66.5x28мм) * Gainta G521G enclosure (92x66.5x28мм)
* 5m power cord * 5m power cord
@@ -26,3 +24,12 @@
### Additional Notes: ### Additional Notes:
My RTC module is not very accurate due to bad quartz chrystal calibration, looks like it is not exactly 32768 Hz and clock runs faster than it should be, giving about 5-8 seconds runaway per day. So i have to implement time correction in software (temperature changes during day/month/year is not very big - about 10 degrees Celsius, so we can use software compensation without thermal compensation). My RTC module is not very accurate due to bad quartz chrystal calibration, looks like it is not exactly 32768 Hz and clock runs faster than it should be, giving about 5-8 seconds runaway per day. So i have to implement time correction in software (temperature changes during day/month/year is not very big - about 10 degrees Celsius, so we can use software compensation without thermal compensation).
This project split into 2 branches:
* **default** that contains generic clock without any additional elements
* **photoresistor** that contains additional hardware - photocell bridge - and software algorithm that compensates ambient light sensed by photocell basing on LED display charachteristics.
### Stable tags for branches:
v1.6 - default
v1.7 - photoresistor

Binary file not shown.

View File

@@ -6,33 +6,12 @@
* 2 buttons for adjusting time. * 2 buttons for adjusting time.
*/ */
/* /* DS1307 lib by FrankieChu for Seeed RTC module, in my case
* uRTCLib * Grove___RTC_DS1307-1.0.0.zip */
* https://github.com/Naguissa/uRTCLib #include <DS1307.h>
* it has support for both DS1307 and DS3231, that i own.
* It is more fat than ds1307-dedicated or ds3231-dedicated lib, but i do not
* want to invent wheel if i have one.
*/
#include <uRTCLib.h>
/*
* SevSeg
* https://github.com/DeanIsMe/SevSeg
* it has simple api and ideally works in my case
*/
#include <SevSeg.h> #include <SevSeg.h>
/* disable time compensation DS1307 clock;
* as we borrow more accurate chrystal and solder it to rtc breakboard
*/
//#define TIMECOMP
/* 0.5 second/day compensation flag */
//#define OFIVECOMP
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
uRTCLib clock;
SevSeg Display; SevSeg Display;
/* push button stuff */ /* push button stuff */
@@ -47,24 +26,11 @@ unsigned long previousPushTimer = 0;
/* dot blinking stuff */ /* dot blinking stuff */
volatile bool dot = true; volatile bool dot = true;
#ifdef TIMECOMP
/* time inaccuracy compensation flag */ /* time inaccuracy compensation flag */
volatile bool compflag1 = true; volatile bool compflag1 = true;
volatile bool compflag2 = false; volatile bool compflag2 = false;
const uint8_t timeSkew = 9; // assume that clock runs faster than should const uint8_t timeSkew = 8; // assume that clock runs faster than should
#ifdef OFIVECOMP
volatile bool timeSkewEven = false; // comp. 1 additional second per 2 days volatile bool timeSkewEven = false; // comp. 1 additional second per 2 days
#endif
#endif
/* ambient light compensation aka night mode */
const int photoPin = A2;
volatile bool measureAmbLight = true;
unsigned int ambLight = 0; // actual value
unsigned int ambLight2 = 0; // previous med. value
unsigned int ambLight3 = 0; // pre-previous med. value
unsigned long previousLightTimer = 0;
const long refresh_interval = 40; // refresh rate 25Hz
/* time vars */ /* time vars */
volatile uint8_t mysecond; volatile uint8_t mysecond;
@@ -82,12 +48,7 @@ void setup()
byte digitPins[] = {9, 10, 11, 12}; byte digitPins[] = {9, 10, 11, 12};
byte segmentPins[] = {2, 3, 4, 5, 6, 7, 8, 13}; byte segmentPins[] = {2, 3, 4, 5, 6, 7, 8, 13};
bool resistorsOnSegments = true; // 8 resistors, 330 Ohms each bool resistorsOnSegments = true; // 8 resistors, 330 Ohms each
/* updateWithDelays defaults to false and it is recommended value, bool updateWithDelays = false; // Default. Recommended
* but i was unable to make my display to change brightness notably with
* recommended value, so i have to use updateWithDelays=true,
* in this case brightness gets changed.
*/
bool updateWithDelays = true;
/* without it there is visual bug at 0 o'clock, and in current version /* without it there is visual bug at 0 o'clock, and in current version
* of SevSeg' setChars() does not dots at all */ * of SevSeg' setChars() does not dots at all */
@@ -98,14 +59,16 @@ void setup()
Display.setBrightness(100); Display.setBrightness(100);
// setup clock // setup clock
Wire.begin(); clock.begin();
clock.set_rtc_address(0x68);
// if rtc returns incorrect time, reset it to some default value // if rtc returns incorrect time, reset it to some default value
clock.refresh(); clock.getTime();
if ((clock.hour() > 23) || (clock.minute() > 59)) { if ((clock.hour > 23) || (clock.minute > 59)) {
clock.set(30, 52, 15, 6, 23, 2, 19); // Saturday, 23 Feb 2019 15:52:30 clock.fillByYMD(2019, 2, 23); // 23 Feb 2019
clock.fillByHMS(15, 52, 30); // 15:52:30"
clock.fillDayOfWeek(SAT); // Saturday
clock.setTime(); // put date to rtc
} }
// setup control buttons // setup control buttons
@@ -127,18 +90,6 @@ void setup()
TCCR1B |= (1 << CS12); // 256 prescaler TCCR1B |= (1 << CS12); // 256 prescaler
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt
interrupts(); // enable all interrupts interrupts(); // enable all interrupts
/* increase sampling rate of analogRead()
* by setting an ADC prescale from 128 to 16, so it takes less time to read
* sensor
*/
sbi(ADCSRA, ADPS2);
cbi(ADCSRA, ADPS1);
cbi(ADCSRA, ADPS0);
// setup ambient brigtness sensor
pinMode(photoPin, INPUT);
ambLight = analogRead(photoPin);
} }
ISR(TIMER1_OVF_vect) ISR(TIMER1_OVF_vect)
@@ -154,69 +105,44 @@ ISR(TIMER1_OVF_vect)
else else
dot = true; dot = true;
#ifdef TIMECOMP
/* time compensation magic */ /* time compensation magic */
if ((myhour == 21) and (myminute == 21) and (mysecond == 21) if ((myhour == 21) and (myminute == 21) and (mysecond == 21)
and (compflag2)) { and (compflag2)) {
compflag1 = true; compflag1 = true;
#ifdef OFIVECOMP
(timeSkewEven) ? timeSkewEven = false : timeSkewEven; (timeSkewEven) ? timeSkewEven = false : timeSkewEven;
#endif
} }
if ((myhour == 21) and (myminute == 21) and (mysecond == 23)) { if ((myhour == 21) and (myminute == 21) and (mysecond == 23)) {
compflag1 = false; compflag1 = false;
compflag2 = true; compflag2 = true;
} }
#endif
} }
void loop() void loop()
{ {
unsigned long currentMillis = millis(); unsigned long currentMillis = millis();
#ifdef TIMECOMP
/* /*
* Let's implement time compenstion for individual rtc module time * Let's implement time compenstion for individual rtc module time
* charachteristics. In in my case quartz resonator as inaccurate as * charachteristics. In in my case quartz resonator as inaccurate as
* about +9.5 seconds per 24 hours * about +8.5 seconds per 24 hours
*/ */
if (compflag1 && compflag2) { if (compflag1 && compflag2) {
#ifdef OFIVECOMP
if (timeSkewEven) { if (timeSkewEven) {
clock.set( clock.fillByHMS(myhour, myminute, (mysecond - timeSkew - 1));
(mysecond - timeSkew - 1),
clock.minute(),
clock.hour(),
clock.dayOfWeek(),
clock.day(),
clock.month(),
clock.year()
);
} else { } else {
#endif clock.fillByHMS(myhour, myminute, (mysecond - timeSkew));
clock.set(
(mysecond - timeSkew),
clock.minute(),
clock.hour(),
clock.dayOfWeek(),
clock.day(),
clock.month(),
clock.year()
);
#ifdef OFIVECOMP
} }
#endif
clock.setTime();
compflag2 = false; compflag2 = false;
} }
#endif
if (rtcsync) { if (rtcsync) {
clock.refresh(); clock.getTime();
mysecond = clock.second(); mysecond = clock.second;
myminute = clock.minute(); myminute = clock.minute;
myhour = clock.hour(); myhour = clock.hour;
updateTimeStr(myhour, myminute); updateTimeStr(myhour, myminute);
rtcsync = false; rtcsync = false;
} }
@@ -245,86 +171,21 @@ void loop()
if (digitalRead(hrs_btn) == LOW) { if (digitalRead(hrs_btn) == LOW) {
myhour++; myhour++;
(myhour > 23) ? myhour = 0 : myhour; (myhour > 23) ? myhour = 0 : myhour;
clock.set( clock.fillByHMS(myhour, myminute, 0);
0, clock.setTime();
myminute,
myhour,
clock.dayOfWeek(),
clock.day(),
clock.month(),
clock.year()
);
} }
if (digitalRead(min_btn) == LOW) { if (digitalRead(min_btn) == LOW) {
myminute++; myminute++;
(myminute > 59) ? myminute = 0 : myminute; (myminute > 59) ? myminute = 0 : myminute;
clock.set( clock.fillByHMS(myhour, myminute, 0);
0, clock.setTime();
myminute,
myhour,
clock.dayOfWeek(),
clock.day(),
clock.month(),
clock.year()
);
} }
} }
updateTimeStr(myhour, myminute); updateTimeStr(myhour, myminute);
} }
if ((currentMillis - previousLightTimer >= refresh_interval) or
(previousLightTimer > currentMillis)) { // millis() reset every ~49 days
previousLightTimer = currentMillis;
ambLight = analogRead(photoPin);
ambLight = (ambLight + ambLight2 + ambLight3) / 3;
/* Ambient light compensation
* ambLight can be in range of 0..1023, if it 910+, it has point to use
* fullbright.
* Use table comparsion (not function of ambLight) because of non-linear
* charachteristics of led indicator, that cannot be described via simple
* formula.
*/
if (ambLight >= 910) {
Display.setBrightness(100);
} else if ((ambLight < 900) and (ambLight >= 860)) {
Display.setBrightness(75);
} else if ((ambLight < 850) and (ambLight >= 810)) {
Display.setBrightness(45);
} else if ((ambLight < 800) and (ambLight >= 760)) {
Display.setBrightness(25);
} else if ((ambLight < 750) and (ambLight >= 710)) {
Display.setBrightness(18);
} else if ((ambLight < 700) and (ambLight >= 660)) {
Display.setBrightness(12);
} else if ((ambLight < 650) and (ambLight >= 610)) {
Display.setBrightness(10);
} else if ((ambLight < 600) and (ambLight >= 560)) {
Display.setBrightness(7);
} else if ((ambLight < 550) and (ambLight >= 410)) {
Display.setBrightness(4);
} else if ((ambLight < 400) and (ambLight >= 360)) {
Display.setBrightness(0);
} else if ((ambLight < 350) and (ambLight >= 310)) {
Display.setBrightness(-3);
} else if ((ambLight < 300) and (ambLight >= 260)) {
Display.setBrightness(-6);
} else if ((ambLight < 250) and (ambLight >= 210)) {
Display.setBrightness(-10);
} else if ((ambLight < 200) and (ambLight >= 160)) {
Display.setBrightness(-14);
} else if ((ambLight < 150) and (ambLight >= 110)) {
Display.setBrightness(-18);
} else if (ambLight < 100) {
Display.setBrightness(-22);
}
ambLight3 = ambLight2;
ambLight2 = ambLight;
}
Display.refreshDisplay(); Display.refreshDisplay();
} }
@@ -341,5 +202,4 @@ void updateTimeStr(uint8_t h, uint8_t m)
} }
} }
/* vim: set filetype=cpp: */ /* vim: set filetype=cpp: */