1

3 Commits

Author SHA1 Message Date
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
6 changed files with 87 additions and 185 deletions

6
.gitignore vendored
View File

@@ -1,6 +0,0 @@
.vscode/*
*.swp
*.bak
*.old
*.orig
*.clang-format

6
.hgignore Normal file
View File

@@ -0,0 +1,6 @@
^\.vscode
\.swp$
\.bak$
\.old$
\.orig$
\.clang-format

3
.hgtags Normal file
View File

@@ -0,0 +1,3 @@
ee4999ebdd2d1b54512facafdd03c8a530ea4bfa v1.0
1167bd4b622768ed17e116a4cbac3db90031e6f8 v1.1
109112211e454e608911949914eaa2722fbfed7d v1.2

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.5 - default
v1.4 - photoresistor

Binary file not shown.

View File

@@ -11,9 +11,6 @@
#include <DS1307.h> #include <DS1307.h>
#include <SevSeg.h> #include <SevSeg.h>
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
DS1307 clock; DS1307 clock;
SevSeg Display; SevSeg Display;
@@ -23,32 +20,20 @@ const long adjust_interval = 200; // delay between consecutive number increments
const long bounce_delay = 20; // contact bounce compensation const long bounce_delay = 20; // contact bounce compensation
const int hrs_btn = A0; // put hour adjusting button on A0 lane const int hrs_btn = A0; // put hour adjusting button on A0 lane
const int min_btn = A1; // put minute adjusting button on A1 lane const int min_btn = A1; // put minute adjusting button on A1 lane
volatile bool btn_pushed = false; // is button pushed? bool btn_pushed = false; // is button pushed?
unsigned long currentPushTimer;
unsigned long previousPushTimer = 0; unsigned long previousPushTimer = 0;
uint8_t minutes;
uint8_t hours;
/* dot blinking stuff */ /* dot blinking stuff */
volatile bool dot = true; unsigned long currentMillis;
unsigned long previousMillis = 0;
const long interval = 500;
bool dot = true;
/* time inaccuracy compensation flag */ /* time inaccuracy compensation flag */
volatile bool compflag1 = true; bool compflag = true;
volatile bool compflag2 = false;
const uint8_t timeSkew = 8; // assume that clock runs faster than should
volatile bool timeSkewEven = false; // comp. 1 additional second per 2 days
/* ambient light compensation aka night mode */
const int photoPin = A2;
volatile bool measureAmbLight = true;
unsigned int ambLight = 0;
unsigned long previousLightTimer = 0;
const long refresh_interval = 40; // refresh rate 25Hz
/* time vars */
volatile uint8_t mysecond;
volatile uint8_t myminute;
volatile uint8_t myhour;
/* rtc sync flag */
volatile bool rtcsync = true;
void setup() void setup()
{ {
@@ -58,12 +43,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 */
@@ -89,96 +69,22 @@ void setup()
// setup control buttons // setup control buttons
pinMode(hrs_btn, INPUT_PULLUP); pinMode(hrs_btn, INPUT_PULLUP);
pinMode(min_btn, INPUT_PULLUP); pinMode(min_btn, INPUT_PULLUP);
/* Timer stuff
* timer0 being used in millis() micros() delay() etc, it has 8 bit resolution
* timer2 being used in analogWrite() tone() notone(), it has 8 bit resolution
* timer1 being used in servo lib has 16 bit resolution
* We'll use timer1, since we have no mechanical parts and don't need servo lib
*/
// initialize timer1
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 34286; // preload timer 65536-16MHz/256/2Hz
TCCR1B |= (1 << CS12); // 256 prescaler
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt
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)
{
/* Feed clock twice per second */
TCNT1 = 34286; // preload timer
// do not read rtc if time beng adjusted by buttons
(btn_pushed) ? rtcsync : rtcsync = true;
/* Also switch dot */
if (dot)
dot = false;
else
dot = true;
/* time compensation magic */
if ((myhour == 21) and (myminute == 21) and (mysecond == 21)
and (compflag2)) {
compflag1 = true;
(timeSkewEven) ? timeSkewEven = false : timeSkewEven;
}
if ((myhour == 21) and (myminute == 21) and (mysecond == 23)) {
compflag1 = false;
compflag2 = true;
}
} }
void loop() void loop()
{ {
unsigned long currentMillis = millis(); currentMillis = millis();
currentPushTimer = currentMillis;
char str[4];
float d;
/*
* Let's implement time compenstion for individual rtc module time
* charachteristics. In in my case quartz resonator as inaccurate as
* about +8.5 seconds per 24 hours
*/
if (compflag1 && compflag2) {
if (timeSkewEven) {
clock.fillByHMS(myhour, myminute, (mysecond - timeSkew - 1));
} else {
clock.fillByHMS(myhour, myminute, (mysecond - timeSkew));
}
clock.setTime();
compflag2 = false;
}
if (rtcsync) {
clock.getTime(); clock.getTime();
mysecond = clock.second;
myminute = clock.minute;
myhour = clock.hour;
updateTimeStr(myhour, myminute);
rtcsync = false;
}
// push button magic // push button magic
if ((!btn_pushed) and if ((!btn_pushed) and
((digitalRead(hrs_btn) == LOW) or (digitalRead(min_btn) == LOW))) { ((digitalRead(hrs_btn) == LOW) or (digitalRead(min_btn) == LOW))) {
if (currentMillis - previousPushTimer >= initial_delay) { if (currentPushTimer - previousPushTimer >= initial_delay) {
previousPushTimer = currentMillis; previousPushTimer = currentPushTimer;
btn_pushed = true; btn_pushed = true;
} }
} }
@@ -186,93 +92,79 @@ void loop()
if (btn_pushed and if (btn_pushed and
(digitalRead(hrs_btn) != LOW) and (digitalRead(min_btn) != LOW)) { (digitalRead(hrs_btn) != LOW) and (digitalRead(min_btn) != LOW)) {
// compensate possible contact bounce with delay // compensate possible contact bounce with delay
if (currentMillis - previousPushTimer >= bounce_delay) { if (currentPushTimer - previousPushTimer >= bounce_delay) {
btn_pushed = false; btn_pushed = false;
} }
} }
if (btn_pushed) { if (btn_pushed) {
if (currentMillis - previousPushTimer >= adjust_interval) { if (currentPushTimer - previousPushTimer >= adjust_interval) {
previousPushTimer = currentMillis; previousPushTimer = currentPushTimer;
if (digitalRead(hrs_btn) == LOW) { if (digitalRead(hrs_btn) == LOW) {
myhour++; hours = clock.hour + 1;
(myhour > 23) ? myhour = 0 : myhour; (hours > 23) ? hours = 0 : hours;
clock.fillByHMS(myhour, myminute, 0); clock.fillByHMS(hours, clock.minute, 0);
clock.setTime(); clock.setTime();
} }
if (digitalRead(min_btn) == LOW) { if (digitalRead(min_btn) == LOW) {
myminute++; minutes = clock.minute + 1;
(myminute > 59) ? myminute = 0 : myminute; (minutes > 59) ? minutes = 0 : minutes;
clock.fillByHMS(myhour, myminute, 0); clock.fillByHMS(clock.hour, minutes, 0);
clock.setTime(); clock.setTime();
} }
} }
updateTimeStr(myhour, myminute);
} }
if ((currentMillis - previousLightTimer >= refresh_interval) or if (currentMillis - previousMillis >= interval) {
(previousLightTimer > currentMillis)) { // millis() reset every ~49 days previousMillis = currentMillis;
previousLightTimer = currentMillis;
ambLight = analogRead(photoPin);
/* Ambient light compensation if (dot)
* ambLight can be in range of 0..1023, if it 910+, it has point to use dot = false;
* fullbright. else
* Use table comparsion (not function of ambLight) because of non-linear dot = true;
* charachteristics of led indicator, that cannot be described via simple }
* formula.
/*
* Let's implement time compenstion for individual rtc module time
* charachteristics. In in my case quartz resonator as inaccurate as
* +/- about 5-8 seconds per 24 hours, maybe its require more EMI
* shielding?
*/ */
if (ambLight >= 910) {
Display.setBrightness(100); if ((clock.hour == 21) and (clock.minute == 21) and
} else if ((ambLight < 900) and (ambLight >= 860)) { (clock.second == 21) and (compflag)) {
Display.setBrightness(75); clock.fillByHMS(clock.hour, clock.minute, 14);
} else if ((ambLight < 850) and (ambLight >= 810)) { clock.setTime();
Display.setBrightness(45); compflag = false;
} else if ((ambLight < 800) and (ambLight >= 760)) { }
Display.setBrightness(25);
} else if ((ambLight < 750) and (ambLight >= 710)) { if ((clock.hour == 21) and (clock.minute == 21) and
Display.setBrightness(18); (clock.second == 23) and (!compflag)) {
} else if ((ambLight < 700) and (ambLight >= 660)) { compflag = true;
Display.setBrightness(12); }
} else if ((ambLight < 650) and (ambLight >= 610)) {
Display.setBrightness(10); // make blinking dot
} else if ((ambLight < 600) and (ambLight >= 560)) { if (clock.hour > 0) {
Display.setBrightness(7); if (dot) {
} else if ((ambLight < 550) and (ambLight >= 410)) { Display.setNumber((clock.hour * 100 + clock.minute), 2);
Display.setBrightness(4); } else {
} else if ((ambLight < 400) and (ambLight >= 360)) { Display.setNumber((clock.hour * 100 + clock.minute));
Display.setBrightness(0); }
} else if ((ambLight < 350) and (ambLight >= 310)) { } else {
Display.setBrightness(-3); /* 0 o'clock is an exception, we don't want to see "00.00", we
} else if ((ambLight < 300) and (ambLight >= 260)) { want see "0.00" or "0 00", so we have to use this "hack" */
Display.setBrightness(-6); if (dot) {
} else if ((ambLight < 250) and (ambLight >= 210)) { d = float(clock.minute) / 100;
Display.setBrightness(-10); Display.setNumber(d, 2);
} else if ((ambLight < 200) and (ambLight >= 160)) { } else {
Display.setBrightness(-14); sprintf(str, "%2d%02d", clock.hour, clock.minute);
} else if ((ambLight < 150) and (ambLight >= 110)) { Display.setChars(str);
Display.setBrightness(-18);
} else if (ambLight < 100) {
Display.setBrightness(-22);
} }
} }
Display.refreshDisplay(); Display.refreshDisplay();
} }
void updateTimeStr(uint8_t h, uint8_t m)
{
if (dot) {
char str[5];
sprintf(str, "%2d.%02d", h, m);
Display.setChars(str);
} else {
char str[4];
sprintf(str, "%2d%02d", h, m);
Display.setChars(str);
}
}
/* vim: set filetype=cpp: */ /* vim: set filetype=cpp: */