- /**
- * USE_GITHUB_USERNAME=nagubal
- * 2.3" 4 digits 7-segment clock, using the DE-DP003 from Sure Electronics
- * http://www.sure-electronics.net/mcu,display/DE-DP003.pdf
- *
- * The DE-DP003 is a common anode 7-segment LED display.
- * The LED driver chips are composed of 4pcs of 74HC595 and 5pcs of ULN2003.
- * Data should be clocked in from CLK_IN and DATA_IN in J1, and DIMM_IN pin should be pull to low to enable display.
- * PWM signal can be applied on the DIMM_IN pin to control brightness.
- */
- #include <EEPROM.h>
- #include <Streaming.h>
- #include <Wire.h>
- //https://github.com/akafugu/ds_rtc_lib
- #include <WireRtcLib.h>
- // http://www.pjrc.com/teensy/td_libs_OneWire.html
- #include <OneWire.h>
- // http://www.milesburton.com/?title=Dallas_Temperature_Control_Library
- #include <DallasTemperature.h>
- #include "pinConstants.h"
- // the DisplayMode enum declaration
- #include "displayMode.h"
- /**
- * La résolution du DS18B20; http://datasheets.maxim-ic.com/en/ds/DS18B20.pdf
- */
- #define DS18B20_RESOLUTION 11
- /**
- * Default brightness
- */
- #define DEFAULT_BRIGHTNESS 127
- #define CHRONODOT_ID 0x68
- /**
- * Refresh display every TIME_REFRESH seconds
- */
- #define TIME_REFRESH 1000
- /**
- * The current display mode
- */
- DisplayMode displayMode = CLOCK_TEMP_MODE;
- /**
- * segments to be switched on for digits on 7-segments display
- */
- byte segments[] = {
- B11111100,
- B01100000,
- B11011010,
- B11110010,
- B01100110,
- B10110110,
- B10111110,
- B11100000,
- B11111110,
- B11110110
- };
- /** Timing Rollover
- * http://www.arduino.cc/playground/Code/TimingRollover
- */
- //static unsigned long waitMillis;
- static unsigned int brightness_pwm;
- static unsigned int previousBrightness;
- // used by the 1Hz interrupt
- volatile boolean displayNow = false;
- /**
- * RTC based on the DS1307/DS3231SN chip connected via I2C and the Wire library
- */
- WireRtcLib rtc;
- /**
- * Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
- */
- OneWire oneWire(ONE_WIRE_BUS);
- /**
- * Pass our oneWire reference to Dallas Temperature.
- */
- DallasTemperature sensors(&oneWire);
- /**
- * DS18B20 address
- */
- DeviceAddress dsAddr = {
- 0x28, 0x72, 0xA4, 0x93, 0x03, 0x00, 0x00, 0x49};
- void setup() {
- // set power pin for DS18B20 to output
- pinMode(ONE_WIRE_POWER, OUTPUT);
- // Initialisation du DS1307
- Wire.begin();
- rtc.begin();
- sensors.begin();
- brightness_pwm = DEFAULT_BRIGHTNESS;
- previousBrightness = DEFAULT_BRIGHTNESS;
- pinMode(DATA_PIN,OUTPUT);
- pinMode(CLK_PIN,OUTPUT);
- pinMode(DIMM_PIN,OUTPUT);
- digitalWrite(CLK_PIN,LOW);
- clearDisplay();
- // gestion du switch on-off-on
- pinMode(PIN_TEMP_ONLY, INPUT);
- // Turn on the internal pull-up resistor, default state is HIGH
- digitalWrite(PIN_TEMP_ONLY, HIGH);
- // Turn on the internal pull-up resistor, default state is HIGH
- pinMode(PIN_CLOCK_ONLY, INPUT);
- digitalWrite(PIN_CLOCK_ONLY, HIGH);
- // gestion du potentiomètre de luminosité
- pinMode(BRIGHTNESS_POT_PIN, INPUT);
- Serial.begin(57600);
- if(sensors.getDeviceCount() > 0) {
- sensors.setResolution(DS18B20_RESOLUTION);
- }
- // enable SQW, 1Hz
- enableSQW();
- // register interrupt function to 1Hz line
- pinMode(SQW_INTERRUPT_PIN, INPUT);
- // Turn on the internal pull-up resistor, default state is HIGH
- digitalWrite(SQW_INTERRUPT_PIN, HIGH);
- attachInterrupt(SQW_INTERRUPT_PIN - 2, oneHzInterruptHandler, FALLING); // 1 = digital pin 3, 0 = digital pin 2
- Serial.println("arduino up and running...");
- }
- byte enableSQW(void) {
- Wire.beginTransmission(CHRONODOT_ID);
- Wire.write(0x0E); // control register
- Wire.endTransmission();
- Wire.requestFrom(CHRONODOT_ID, 1);
- byte ctrl;
- if(Wire.available()) {
- ctrl = Wire.read();
- }
- Wire.beginTransmission(CHRONODOT_ID);
- Wire.write(0x0E); // control register
- Wire.write(ctrl & B11100011); // all bits 0;
- Wire.endTransmission();
- Serial << "ctrl: " << ctrl << endl;
- return ctrl;
- }
- void oneHzInterruptHandler(void) {
- //Serial.println(" TOP");
- displayNow = true;
- }
- void disableDisplay() {
- digitalWrite(DIMM_PIN, HIGH);
- }
- void enableDisplay() {
- //digitalWrite(DIMM_PIN, LOW);
- analogWrite(DIMM_PIN, brightness_pwm);
- }
- void clearDisplay() {
- disableDisplay();
- for (int i = 0; i < 4; ++i)
- shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,B00000000);
- //digitalWrite(DIMM_PIN,LOW);
- enableDisplay();
- }
- void displayTime(WireRtcLib::tm* time) {
- byte digitvalue, bitfield;
- disableDisplay();
- // segment minutes basses
- digitvalue = time->min % 10;
- bitfield = segments[digitvalue];
- shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,bitfield);
- // segment minutes hautes
- digitvalue = time->min / 10;
- bitfield = segments[digitvalue];
- shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,bitfield);
- // segment heures basses
- digitvalue = time->hour % 10;
- bitfield = segments[digitvalue];
- // on fait clignoter le décimal point
- bitfield |= time->sec & 1;
- //Serial.println(time->sec & 1);
- shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,bitfield);
- // segment heures hautes
- digitvalue = time->hour / 10;
- // si l'heure est comprise entre 1h et 9h, on n'affiche pas le 0.
- bitfield = digitvalue ? segments[digitvalue] : 0;
- shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,bitfield);
- // Les données sont envoyées, on les affiche...
- enableDisplay();
- }
- void displayTemp() {
- float temp = getTemp();
- unsigned int digits [3];
- // partie entière
- double iValue;
- // partie décimale
- double fValue = modf(temp,&iValue);
- unsigned int integerValue = (unsigned int) iValue;
- // On tient le dernier digit à afficher
- unsigned int fractionValue = (unsigned int) (round(fValue * 10));
- digits[2] = fractionValue;
- //Serial << "temp: " << temp << " => " << "integerValue: " << integerValue << " , fractionValue : " << fractionValue << endl;
- if(integerValue >= 10 ) {
- digits[1] = integerValue % 10;
- digits[0] = integerValue / 10;
- }
- else {
- digits[0] = 0;
- digits[1] = integerValue;
- }
- //Serial << digits[0] << digits[1] << "." << digits[2] << endl;
- // on se prépare à envoyer les données
- disableDisplay();
- // le signe degré...
- shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,B11000110);
- byte bitfield = segments[digits[2]];
- shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,bitfield);
- bitfield = segments[digits[1]];
- bitfield |= 1;
- shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,bitfield);
- bitfield = digits[0] ? segments[digits[0]] : 0;
- shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,bitfield);
- // Les données sont envoyées, on les affiche...
- enableDisplay();
- }
- float getTemp() {
- // turn DS18B20 sensor on
- digitalWrite(ONE_WIRE_POWER, HIGH);
- Serial << "Requesting temperature from DS18B20... ";
- sensors.requestTemperaturesByAddress(dsAddr);
- float temp = sensors.getTempC(dsAddr);
- // sensors.requestTemperatures();
- // float temp = sensors.getTempCByIndex(0);
- // turn DS18B20 off
- digitalWrite(ONE_WIRE_POWER, LOW);
- Serial << temp << endl;
- return temp;
- }
- DisplayMode getCurrentDisplayMode () {
- int pinTempOnly = digitalRead(PIN_TEMP_ONLY);
- int pinClockOnly = digitalRead(PIN_CLOCK_ONLY);
- //Serial << "digitalRead(PIN_TEMP_ONLY) : " << pinTempOnly << endl;
- //Serial << "digitalRead(PIN_CLOCK_ONLY) : " << pinClockOnly << endl;
- if(pinTempOnly != LOW && pinClockOnly != LOW) {
- return CLOCK_TEMP_MODE;
- }
- else if(pinTempOnly == LOW) {
- return TEMPERATURE_MODE;
- }
- else if(pinClockOnly == LOW) {
- return CLOCK_MODE;
- }
- }
- void dst(WireRtcLib::tm* date) {
- // ++++++++++ Daylight saving cycle for Netherlands for next ten years ++++++++++
- // START 2010 october
- // In Netherlands/France DST only changes at the last weekend on Sunday 02:00 in MARCH and OCTOBER,
- // so days between 25 and 31 is covered by this code (it is tested and seems OK)
- if (date->wday == 7 && date->mon == 3 || date->mon == 10 && date->hour >1 && date->hour <4) {
- // DST schedule for next ten years to october 2019 condition start in march or october
- // read Previous DST status,
- int DST = EEPROM.read(1060);
- //Serial << "DST (EEPROM.read(1060)): " << DST << endl;
- if (date->wday == 7 && date->mon == 3 && date->mday >= 25 && date->mday <=31 && date->hour == 2 && DST==0) {
- // time forward from 02:00 to 03:00 in march if DST status ==0 else don't change time!
- //set the hours to 03:00
- // when status was ZERO (0) then change time from 02:00 to 03:00 hr
- rtc.setTime_s(3, date->min, date->sec);
- Serial << " il est maintenant 3 heures" << endl;
- // daylight saving flag
- // Write DST statusflag to ONE(1) to prevent multiple changes in hours, only once in March
- EEPROM.write(1060, 1);
- }
- if (date->wday == 7 && date->mon == 10 && date->mday >= 25 && date->mday <=31 && date->hour == 3 && DST==1) {
- // time backwards from 3:00 to 02:00 in october if DST status ==1 else don't change time!
- //set the hours to 02:00
- rtc.setTime_s(2, date->min, date->sec);
- Serial << " il est maintenant 2 heures" << endl;
- // daylight saving flag
- // Write DST statusflag to ZERO to prevent multiple changes in hours, only once in October
- EEPROM.write(1060, 0);
- }
- }
- }
- boolean setBrightness() {
- static unsigned long brightMillis;
- // let's read the brightness potientiometer, and map the readings for the 16 brightness levels
- int valPot = analogRead(BRIGHTNESS_POT_PIN);
- unsigned int mappedPot = map(valPot, 0, 1023, 0, 15);
- brightness_pwm = mappedPot == 0 ? 0 : mappedPot * 16 - 1;
- Serial << "valPot: " << valPot << ", mappedPot: " << mappedPot << ", brightness_pwm: " << brightness_pwm << endl;
- boolean hasChanged = previousBrightness != brightness_pwm;
- if (hasChanged) {
- // show the selected brightness level for one second
- brightMillis = millis() + TIME_REFRESH;
- // display the selected brightness level: 1 - lowest, 16 highest
- unsigned int level = 16 - mappedPot;
- unsigned int digits [3];
- if(level >= 10 ) {
- digits[1] = level % 10;
- digits[0] = level / 10;
- }
- else {
- digits[0] = 0;
- digits[1] = level;
- }
- // on se prépare à envoyer les données
- disableDisplay();
- byte bitfield = segments[digits[1]];
- shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,bitfield);
- bitfield = segments[digits[0]];
- shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,bitfield);
- shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,B00000000);
- shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,B00000000);
- // Les données sont envoyées, on les affiche...
- enableDisplay();
- previousBrightness = brightness_pwm;
- }
- return ((long)( millis() - brightMillis ) < 0);
- }
- void loop() {
- boolean brightnessHasChanged = setBrightness();
- if(!brightnessHasChanged) {
- DisplayMode newDisplayMode = getCurrentDisplayMode();
- if (displayMode != newDisplayMode) {
- // the display mode has changed! let's reset the timer...
- //waitMillis = millis();
- displayNow = true;
- displayMode = newDisplayMode;
- Serial << " =======> display mode has changed: " << displayMode << endl;
- }
- //displayNow = (long)( millis() - waitMillis ) >= 0;
- if(displayNow) {
- WireRtcLib::tm* now = rtc.getTime();
- dst(now);
- switch (displayMode) {
- case TEMPERATURE_MODE:
- displayTemp();
- break;
- case CLOCK_MODE:
- displayTime(now);
- break;
- case CLOCK_TEMP_MODE:
- uint8_t seconds = now->sec;
- if(seconds <= 5 || seconds >= 30 && seconds <= 35) {
- displayTemp();
- }
- else {
- displayTime(now);
- }
- }
- //waitMillis += TIME_REFRESH;
- displayNow = false;
- }
- }
- }