Skip to content

Instantly share code, notes, and snippets.

@nagubal
Last active March 14, 2016 22:12
Show Gist options
  • Select an option

  • Save nagubal/2065722 to your computer and use it in GitHub Desktop.

Select an option

Save nagubal/2065722 to your computer and use it in GitHub Desktop.
The file that is currently on an Arduino Uno with a serial number of 64935343333351F04132
enum DisplayMode {
CLOCK_MODE = 0, // display clock only
TEMPERATURE_MODE = 1, // display temperature only
CLOCK_TEMP_MODE = 2, // display clock and temperature every 25 seconds for 5 seconds
SET_CLOCK_MODE = 3
};
enum SettingsMode {
SETTINGS_OFF = 0,
SET_HOURS_MODE = 1,
SET_MINUTES_MODE = 2,
SET_SECONDS_MODE = 3
};
/**
* The DATA_IN pin
*/
#define DATA_PIN 8
/**
* The DIMM_IN pin should be pulled to LOW to enable display,
* also used for brightness with PWM (using analogWrite())
*/
#define DIMM_PIN 9
//11
/**
* The CLK_IN pin
*/
#define CLK_PIN 10
/**
* DS18B20 data wire is plugged into port 7 on the Arduino
*/
#define ONE_WIRE_BUS 7
#define ENC_PORT3 3
#define ENC_PORT6 6
/**
* DS18B20 Power pin is connected on pin A3
*/
#define ONE_WIRE_POWER A3
/**
* Brightness potientiometer pin is connected on pin A1
*/
#define BRIGHTNESS_POT_PIN A1
#define SQW_INTERRUPT_PIN 2
#define PIN_CLOCK_ONLY 4
#define PIN_TEMP_ONLY 5
#define PB4 4 //D12
/**
* 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>
#define ENCODER_USE_INTERRUPTS 1
// http://www.pjrc.com/teensy/td_libs_Encoder.html
#include "Encoder.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
/**
* the debounce time, increase if the output flickers
*/
#define DEBOUNCE 5
/**
* Default brightness
*/
#define DEFAULT_BRIGHTNESS 7
#define CHRONODOT_ID 0x68
/**
* The current display mode
*/
DisplayMode displayMode = CLOCK_TEMP_MODE;
SettingsMode settingsMode = SETTINGS_OFF;
WireRtcLib::tm* settingsTime;
/**
* segments to be switched on for digits on 7-segments display
*/
byte segments[] = {
B11111100,
B01100000,
B11011010,
B11110010,
B01100110,
B10110110,
B10111110,
B11100000,
B11111110,
B11110110
};
static unsigned int brightness_pwm;
static unsigned int previousBrightness;
boolean brightnessHasChanged = false;
/**
* used by the 1Hz interrupt
*/
volatile boolean displayNow = false;
/**
* the prevEncoderButton encoderButton from the input pin
*/
static uint8_t prevEncoderButton = 16;
unsigned long millisEncButton = 0; // the last time the output pin was toggled
// Change these two numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
Encoder myEnc(ENC_PORT3, ENC_PORT6);
long oldPosition = -999;
/**
* 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);
void setup() {
brightness_pwm = DEFAULT_BRIGHTNESS;
previousBrightness = DEFAULT_BRIGHTNESS;
pinMode(DATA_PIN, OUTPUT);
pinMode(CLK_PIN, OUTPUT);
pinMode(DIMM_PIN, OUTPUT);
digitalWrite(CLK_PIN, LOW);
clearDisplay();
// handles the push button on the rotary encoder
DDRB &= ~(1 << PB4); // set PB4 as an input
PORTB = (1 << PB4); // Turn on the internal pull-up resistor for PB4
// set PIN_TEMP_ONLY & PIN_CLOCK_ONLY & SQW_INTERRUPT_PIN as an input
//DDRD &= ~( (1 << PIN_TEMP_ONLY) | (1 << PIN_CLOCK_ONLY) | (1 << SQW_INTERRUPT_PIN) );
DDRD = DDRD | B00000000;
//pinMode(PIN_TEMP_ONLY,INPUT);
//pinMode(PIN_CLOCK_ONLY,INPUT);
//pinMode(SQW_INTERRUPT_PIN,INPUT);
// Turn on the internal pull-up resistor for PIN_CLOCK_ONLY & PIN_TEMP_ONLY & SQW_INTERRUPT_PIN
//PORTD = ((1 << PIN_CLOCK_ONLY) | (1 << PIN_TEMP_ONLY) | (1 << SQW_INTERRUPT_PIN));
PORTD = PORTD | B00110100;
// gestion du potentiomètre de luminosité
pinMode(BRIGHTNESS_POT_PIN, INPUT);
Serial.begin(57600);
// set power pin for DS18B20 to output
pinMode(ONE_WIRE_POWER, OUTPUT);
//DDRC |= (1 << ONE_WIRE_POWER);
// Initialisation du DS1307
Wire.begin();
rtc.begin();
sensors.begin();
if(sensors.getDeviceCount() > 0) {
sensors.setResolution(DS18B20_RESOLUTION);
}
// enable SQW, 1Hz
enableSQW();
// register interrupt function to 1Hz line
attachInterrupt(SQW_INTERRUPT_PIN - 2, oneHzInterruptHandler, FALLING); // 1 = digital pin 3, 0 = digital pin 2
WireRtcLib::tm* now = rtc.getTime();
//Serial << "date: " << now->wday << " " << now->mday << "/" << now->mon << "/" << now->year << endl;
Serial << "arduino up and running..." << endl;
}
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");
// Affichage de l'heure toutes les minutes, sauf si la luminosité vient d'être modifiée via l'encodeur
if(!brightnessHasChanged) {
displayNow = true;
}
brightnessHasChanged = false;
}
/**
* Désactive l'affichage pour mise à jour
*/
void disableDisplay() {
digitalWrite(DIMM_PIN, HIGH);
}
/**
* Active l'affichage suite à mise à jour
*/
void enableDisplay() {
analogWrite(DIMM_PIN, brightness_pwm * 16);
}
/**
* Efface l'affichage: toutes LEDs éteintes
*/
void clearDisplay() {
disableDisplay();
for (int i = 0; i < 4; ++i)
shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,B00000000);
enableDisplay();
}
void displayTime(WireRtcLib::tm* time) {
byte digitvalue, bitfield;
disableDisplay();
if(settingsMode != SET_SECONDS_MODE) {
// segment minutes basses
digitvalue = time->min % 10;
bitfield = segments[digitvalue];
if(displayMode == SET_CLOCK_MODE) {
bitfield |= 1;
}
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
if(displayMode == SET_CLOCK_MODE) {
bitfield |= 1;
}
else {
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);
}
else {
// segment minutes basses
digitvalue = time->sec % 10;
bitfield = segments[digitvalue];
if(displayMode == SET_CLOCK_MODE) {
bitfield |= 1;
}
shiftOut(DATA_PIN,CLK_PIN,LSBFIRST,bitfield);
// segment minutes hautes
digitvalue = time->sec / 10;
bitfield = segments[digitvalue];
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();
}
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, set HIGH
//PORTC |= (1 << ONE_WIRE_POWER);
digitalWrite(ONE_WIRE_POWER, HIGH);
//Serial << "Requesting temperature from DS18B20... ";
sensors.requestTemperatures();
float temp = sensors.getTempCByIndex(0);
// turn DS18B20 off, set LOW
//PORTC &= ~(1 << ONE_WIRE_POWER);
digitalWrite(ONE_WIRE_POWER, LOW);
//Serial << temp << endl;
return temp;
}
DisplayMode getCurrentDisplayMode () {
//uint8_t switchPin = (PIND & ((1<<PIN_CLOCK_ONLY) | (1<<PIN_TEMP_ONLY)));
//Serial << "switchPin: " << switchPin << endl;
//return SET_CLOCK_MODE;
switch ((PIND & ((1<<PIN_CLOCK_ONLY) | (1<<PIN_TEMP_ONLY)))) {
case 0x10:
return TEMPERATURE_MODE;
case 0x20:
return CLOCK_MODE;
/*case 0x30:
return CLOCK_TEMP_MODE;
break;*/
default:
return CLOCK_TEMP_MODE;
}
}
boolean setBrightness() {
// let's read the encoder position to set the brightness
int encoderValue = readEncoder();
if (encoderValue != 0) {
if (previousBrightness == 15 && encoderValue == -1)
brightness_pwm = 15;
else if (previousBrightness == 0 && encoderValue == 1)
brightness_pwm = 0;
else
brightness_pwm = previousBrightness - encoderValue;
// display the selected brightness level: 1 - lowest, 16 highest
unsigned int level = 16 - brightness_pwm;
//Serial << "level: " << level << endl;
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;
brightnessHasChanged = true;
}
return brightnessHasChanged;
}
void handleButtonStateChanged() {
uint8_t encoderButton = PINB & (1 << PB4); // reads pin 4 of port B, i.e. D12 which is the rotary encoder switch
unsigned long currentMillis = millis();
if ((unsigned long)(currentMillis - millisEncButton) >= DEBOUNCE) {
// We're not in the debounce period.
if(encoderButton != prevEncoderButton) {
//Serial << "handleButtonStateChanged" << endl;
// Button state changed
// Start debounce period after processing the button
millisEncButton = millis();
prevEncoderButton = encoderButton;
// Do the processing
if (encoderButton) {
//Serial << "handleButtonStateChanged" << endl;
switch (displayMode) {
case SET_CLOCK_MODE :
if(settingsMode == SET_HOURS_MODE) {
settingsMode = SET_MINUTES_MODE;
}
else if (settingsMode == SET_MINUTES_MODE) {
settingsMode = SET_SECONDS_MODE;
displayTime(settingsTime);
}
else if (settingsMode == SET_SECONDS_MODE) {
// let's set the time on the chronodot
//Serial << "setting time: " << settingsTime->hour << ":" << settingsTime->min << ":" << settingsTime->sec << endl;
rtc.setTime(settingsTime);
settingsMode = SETTINGS_OFF;
displayMode = CLOCK_MODE;
}
break;
default:
displayMode = SET_CLOCK_MODE;
settingsMode = SET_HOURS_MODE;
settingsTime = rtc.getTime();
displayTime(settingsTime);
break;
}
}
/*
else {
// Do the low stuff. We don't care about that one as
// we're interested just in the button being pressed
}
*/
}
}
}
long readEncoder() {
long retValue = 0;
long newPosition = myEnc.read();
if (newPosition != oldPosition) {
if (newPosition < oldPosition) {
retValue += 1;
oldPosition = newPosition;
}
else if(newPosition >= oldPosition) {
retValue -= 1;
//value = value == 60 ? 0 : value;
oldPosition = newPosition;
}
Serial << "readEncoder: " << retValue << endl;
}
return retValue;
}
void loop() {
handleButtonStateChanged();
if(displayMode != SET_CLOCK_MODE) {
DisplayMode currentDisplayMode = getCurrentDisplayMode();
setBrightness();
if(!brightnessHasChanged) {
if (displayMode != currentDisplayMode) {
// the display mode has changed! let's reset the timer...
displayNow = true;
displayMode = currentDisplayMode;
//Serial << " =======> display mode has changed: " << displayMode << endl;
}
if(displayNow) {
WireRtcLib::tm* now = rtc.getTime();
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);
}
}
displayNow = false;
}
} // if(!brightnessHasChanged)
}
else {
// SET_CLOCK_MODE
//Serial << "SET_CLOCK_MODE : " << settingsMode << endl;
int encoderValue = readEncoder();
if (encoderValue != 0) {
switch (settingsMode) {
case SET_HOURS_MODE:
if (settingsTime->hour == 0 && encoderValue == -1)
settingsTime->hour = 23;
else if (settingsTime->hour == 23 && encoderValue == 1)
settingsTime->hour = 0;
else
settingsTime->hour += encoderValue;
break;
case SET_MINUTES_MODE:
if (settingsTime->min == 0 && encoderValue == -1)
settingsTime->min = 59;
else if (settingsTime->min == 59 && encoderValue == 1)
settingsTime->min = 0;
else
settingsTime->min += encoderValue;
break;
case SET_SECONDS_MODE:
if (settingsTime->sec == 0 && encoderValue == -1)
settingsTime->sec = 59;
else if (settingsTime->sec == 59 && encoderValue == 1)
settingsTime->sec = 0;
else
settingsTime->sec += encoderValue;
break;
}
displayTime(settingsTime);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment