arduino/DCF77/LCD4Bit.pde

327 lines
8.2 KiB
Text

#include <LCD4Bit.h>
#include <avr/io.h>
//create object to control an LCD.
//number of lines in display=2
LCD4Bit lcd = LCD4Bit(2);
/**
* Where is the DCF receiver connected?
*/
#define DCF77PIN 6
/**
* Where is the LED connected?
*/
#define BLINKPIN 13
/**
* Turn debugging on or off
*/
//#define DCF_DEBUG 1
/**
* Number of milliseconds to elapse before we assume a "1",
* if we receive a falling flank before - its a 0.
*/
#define DCF_split_millis 140
/**
* There is no signal in second 59 - detect the beginning of
* a new minute.
*/
#define DCF_sync_millis 1200
/**
* Definitions for the timer interrupt 2 handler:
* The Arduino runs at 16 Mhz, we use a prescaler of 64 -> We need to
* initialize the counter with 6. This way, we have 1000 interrupts per second.
* We use tick_counter to count the interrupts.
*/
#define INIT_TIMER_COUNT 6
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT
int tick_counter = 0;
/**
* DCF time format struct
*/
struct DCF77Buffer {
unsigned long long prefix :21;
unsigned long long Min :7; // minutes
unsigned long long P1 :1; // parity minutes
unsigned long long Hour :6; // hours
unsigned long long P2 :1; // parity hours
unsigned long long Day :6; // day
unsigned long long Weekday :3; // day of week
unsigned long long Month :5; // month
unsigned long long Year :8; // year (5 -> 2005)
unsigned long long P3 :1; // parity
};
struct {
unsigned char parity_flag :1;
unsigned char parity_min :1;
unsigned char parity_hour :1;
unsigned char parity_date :1;
} flags;
/**
* Clock variables
*/
volatile unsigned char DCFSignalState = 0;
unsigned char previousSignalState;
int previousFlankTime;
int bufferPosition;
unsigned long long dcf_rx_buffer;
/**
* time vars: the time is stored here!
*/
volatile unsigned char ss;
volatile unsigned char mm;
volatile unsigned char hh;
volatile unsigned char day;
volatile unsigned char mon;
volatile unsigned int year;
/**
* used in main loop: detect a new second...
*/
unsigned char previousSecond;
/**
* Initialize the DCF77 routines: initialize the variables,
* configure the interrupt behaviour.
*/
void DCF77Init() {
previousSignalState=0;
previousFlankTime=0;
bufferPosition=0;
dcf_rx_buffer=0;
ss=mm=hh=day=mon=year=0;
#ifdef DCF_DEBUG
Serial.println("Initializing DCF77 routines");
Serial.print("Using DCF77 pin #");
Serial.println(DCF77PIN);
pinMode(BLINKPIN, OUTPUT);
pinMode(DCF77PIN, INPUT);
#endif
pinMode(DCF77PIN, INPUT);
#ifdef DCF_DEBUG
Serial.println("Initializing timerinterrupt");
#endif
//Timer2 Settings: Timer Prescaler /64,
TCCR2 |= (1<<CS22); // turn on CS22 bit
TCCR2 &= ~((1<<CS21) | (1<<CS20)); // turn off CS21 and CS20 bits
// Use normal mode
TCCR2 &= ~((1<<WGM21) | (1<<WGM20)); // turn off WGM21 and WGM20 bits
// Use internal clock - external clock not used in Arduino
ASSR |= (0<<AS2);
TIMSK |= (1<<TOIE2) | (0<<OCIE2); //Timer2 Overflow Interrupt Enable
RESET_TIMER2;
#ifdef DCF_DEBUG
Serial.println("Initializing DCF77 signal listener interrupt");
#endif
attachInterrupt(0, int0handler, CHANGE);
}
/**
* Append a signal to the dcf_rx_buffer. Argument can be 1 or 0. An internal
* counter shifts the writing position within the buffer. If position > 59,
* a new minute begins -> time to call finalizeBuffer().
*/
void appendSignal(unsigned char signal) {
#ifdef DCF_DEBUG
Serial.print(", appending value ");
Serial.print(signal, DEC);
Serial.print(" at position ");
Serial.println(bufferPosition);
#endif
dcf_rx_buffer = dcf_rx_buffer | ((unsigned long long) signal << bufferPosition);
// Update the parity bits. First: Reset when minute, hour or date starts.
if (bufferPosition == 21 || bufferPosition == 29 || bufferPosition == 36) {
flags.parity_flag = 0;
}
// save the parity when the corresponding segment ends
if (bufferPosition == 28) {flags.parity_min = flags.parity_flag;};
if (bufferPosition == 35) {flags.parity_hour = flags.parity_flag;};
if (bufferPosition == 58) {flags.parity_date = flags.parity_flag;};
// When we received a 1, toggle the parity flag
if (signal == 1) {
flags.parity_flag = flags.parity_flag ^ 1;
}
bufferPosition++;
if (bufferPosition > 59) {
finalizeBuffer();
}
}
/**
* Evaluates the information stored in the buffer. This is where the DCF77
* signal is decoded and the internal clock is updated.
*/
void finalizeBuffer(void) {
if (bufferPosition == 59) {
#ifdef DCF_DEBUG
Serial.println("Finalizing Buffer");
#endif
struct DCF77Buffer *rx_buffer;
rx_buffer = (struct DCF77Buffer *)(unsigned long long)&dcf_rx_buffer;
if (flags.parity_min == rx_buffer->P1 &&
flags.parity_hour == rx_buffer->P2 &&
flags.parity_date == rx_buffer->P3)
{
#ifdef DCF_DEBUG
Serial.println("Parity check OK - updating time.");
#endif
//convert the received bits from BCD
mm = rx_buffer->Min-((rx_buffer->Min/16)*6);
hh = rx_buffer->Hour-((rx_buffer->Hour/16)*6);
day= rx_buffer->Day-((rx_buffer->Day/16)*6);
mon= rx_buffer->Month-((rx_buffer->Month/16)*6);
year= 2000 + rx_buffer->Year-((rx_buffer->Year/16)*6);
}
#ifdef DCF_DEBUG
else {
Serial.println("Parity check NOK - running on internal clock.");
}
#endif
}
// reset stuff
ss = 0;
bufferPosition = 0;
dcf_rx_buffer=0;
}
/**
* Dump the time to the serial line.
*/
void serialDumpTime(void){
Serial.print("Time: ");
Serial.print(hh, DEC);
Serial.print(":");
Serial.print(mm, DEC);
Serial.print(":");
Serial.print(ss, DEC);
Serial.print(" Date: ");
Serial.print(day, DEC);
Serial.print(".");
Serial.print(mon, DEC);
Serial.print(".");
Serial.println(year, DEC);
}
/**
* Evaluates the signal as it is received. Decides whether we received
* a "1" or a "0" based on the
*/
void scanSignal(void){
if (DCFSignalState == 1) {
int thisFlankTime=millis();
if (thisFlankTime - previousFlankTime > DCF_sync_millis) {
#ifdef DCF_DEBUG
Serial.println("####");
Serial.println("#### Begin of new Minute!!!");
Serial.println("####");
#endif
finalizeBuffer();
}
previousFlankTime=thisFlankTime;
#ifdef DCF_DEBUG
Serial.print(previousFlankTime);
Serial.print(": DCF77 Signal detected, ");
#endif
}
else {
/* or a falling flank */
int difference=millis() - previousFlankTime;
#ifdef DCF_DEBUG
Serial.print("duration: ");
Serial.print(difference);
#endif
if (difference < DCF_split_millis) {
appendSignal(0);
}
else {
appendSignal(1);
}
}
}
/**
* The interrupt routine for counting seconds - increment hh:mm:ss.
*/
ISR(TIMER2_OVF_vect) {
RESET_TIMER2;
tick_counter += 1;
if (tick_counter == 1000) {
ss++;
if (ss==60) {
ss=0;
mm++;
if (mm==60) {
mm=0;
hh++;
if (hh==24)
hh=0;
}
}
tick_counter = 0;
}
};
/**
* Interrupthandler for INT0 - called when the signal on Pin 2 changes.
*/
void int0handler() {
// check the value again - since it takes some time to
// activate the interrupt routine, we get a clear signal.
DCFSignalState = digitalRead(DCF77PIN);
}
/**
* Standard Arduino methods below.
*/
void setup(void) {
//pinMode(13, OUTPUT); //we'll use the debug LED to output a heartbeat
//lcd.init();
// We need to start serial here again,
// for Arduino 007 (new serial code)
Serial.begin(9600);
DCF77Init();
}
void loop(void) {
if (ss != previousSecond) {
serialDumpTime();
previousSecond = ss;
}
if (DCFSignalState != previousSignalState) {
scanSignal();
if (DCFSignalState) {
digitalWrite(BLINKPIN, HIGH);
} else {
digitalWrite(BLINKPIN, LOW);
}
previousSignalState = DCFSignalState;
}
//delay(20);
}
void loop22() {
lcd.clear(); // Clear display
lcd.printIn("hallo welt!"); // Dislay text on first line
lcd.leftScroll(32, 200);
//lcd.cursorTo(2,0); // Move cursor to second line, position 0
//lcd.printIn("fuck off!"); // Display text on second line
/*
while(1) // Endless loop flashing the LED
{
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);
}
*/
}