/* Radio Clock David Johnson-Davies - www.technoblogy.com - 23rd July 2014 CC BY 4.0 Licensed under a Creative Commons Attribution 4.0 International license: http://creativecommons.org/licenses/by/4.0/ */ //Create global variables volatile unsigned long milliseconds; volatile int BitCount; unsigned char BitBuffer; boolean Parity; boolean BitB; char digit; int RadioHours, RadioMins, Hours, Mins; // Digit connections const int ndigits = 4; int Digits[] = {PIN_A4, PIN_B0, PIN_B1, PIN_A5}; // Segments must all go to port A // This specifies which bit in port A goes to each segment // g f e d c b a dp int Segments[] = {1, 4, 6, 7, 3, 0, 2, 5}; const int RadioPin = PIN_B2; // Display update const int Space = 10; const int Dash = 12; char Buffer[4] = { Dash, Dash, Dash, Dash}; const int charArrayLen = 13; char charArray[13] = { // abcdefg Segments 0b1111110, // 0 0b0110000, // 1 0b1101101, // 2 0b1111001, // 3 0b0110011, // 4 0b1011011, // 5 0b1011111, // 6 0b1110000, // 7 0b1111111, // 8 0b1111011, // 9 0b0000000, // 10 Space 0b1001110, // 11 'C' 0b0000001 // 12 '-' }; // Count the population or number of '1's in x as binary int pop(unsigned char x) { x = (x & 0x55) + ((x>>1) & 0x55); x = (x & 0x33) + ((x>>2) & 0x33); return (x & 0x0f) + (x>>4); } // Reorder the bits in charArray to match wiring void ReorderBits() { int segs, newsegs; for (int i=0; i> 1; } charArray[i]=newsegs; } } // Display update routine - Gets called every 2 msec void DisplayNextDigit() { int Segs, Char; // Turn display off pinMode(Digits[digit], INPUT); digit = (digit+1) % ndigits; Char = min(Buffer[digit],charArrayLen-1); Segs = charArray[Char & 0x7F]; // Display colon? if ((Char & 0x80) && (digit==3)) { pinMode(Digits[2], OUTPUT); digitalWrite(Digits[2], LOW); } // Equalise brightness OCR0B = (pop(Segs) + 4) * 16; // Max 198 DDRA = 0; // All inputs PORTA = Segs ^ 0xFF; // 1 = high DDRA = Segs; // 1 = output } // Timer 0 interrupt A - turns on display ISR(TIM0_COMPA_vect) { pinMode(Digits[digit], OUTPUT); digitalWrite(Digits[digit], HIGH); } // Timer 0 interrupt B - turns off and sets up display ISR(TIM0_COMPB_vect) { DisplayNextDigit(); milliseconds += 2; Average(); } // My millisecond timer unsigned long MyMillis() { unsigned long m; uint8_t oldSREG = SREG; cli(); m = milliseconds; SREG = oldSREG; return m; } // My millisecond delay routine void MyDelay(unsigned long ms) { unsigned long Start; Start = MyMillis(); while ((MyMillis() - Start) < ms); } void setup() { ReorderBits(); // Set up Timer0 to multiplex the display TCCR0A = 3<> 7) + Bit; BitBuffer = (BitBuffer<<1) | Bit; } // Returns true if averaged radio input is high boolean Radio() { boolean b; uint8_t oldSREG = SREG; cli(); b = BitCount >= 4; SREG = oldSREG; return b; } // Wait for next carrier off pulse (HIGH) and time it int HighPulse() { unsigned long Start; while (!Radio()); // Low - carrier on Start = MyMillis(); while (Radio()); // High - carrier off return MyMillis() - Start; } // Reads a bit from the timecode; assumes you started in inter-bit gap boolean GetBit() { boolean result; while (!Radio()); MyDelay(200); // End of bit A result = (Radio()); Parity = Parity ^ result; MyDelay(100); // Middle of bit B BitB = BitB + (Radio()); MyDelay(100); // Get into gap return result; } void loop() { int bitbs, timeparity, LastHours, LastMins; // Wait for minute marker while (HighPulse() < 450); // Skip seconds 1 to 38 for (int i=1; i<=38; i++) GetBit(); // Read time LastHours = RadioHours; LastMins = RadioMins; Parity = 0; BitB = 0; int TenHours = GetBit() * 2 + GetBit(); int UnitHours = GetBit() * 8 + GetBit() * 4 + GetBit() * 2 + GetBit(); RadioHours = TenHours*10 + UnitHours; int TenMins = GetBit() * 4 + GetBit() * 2 + GetBit(); int UnitMins = GetBit() * 8 + GetBit() * 4 + GetBit() * 2 + GetBit(); RadioMins = TenMins*10 + UnitMins; timeparity = Parity; bitbs = BitB; // Should be zero // Skip next 5 bits for (int i=1; i<=5; i++) GetBit(); BitB = 0; GetBit(); // Parity boolean TimeValid = (bitbs == 0) && (BitB != timeparity) && (RadioHours-LastHours==0) && (RadioMins-LastMins==1); if (TimeValid) { Hours = RadioHours; Mins = RadioMins; } else { Mins = Mins + 1; Hours = (Hours + Mins/60) % 24; Mins = Mins % 60; } // Display time in 12-hour clock int TwelveHour = Hours%12; if (TwelveHour==0) TwelveHour = 12; if (TwelveHour<10) Buffer[0] = Space; else Buffer[0] = TwelveHour/10; Buffer[1] = TwelveHour%10; Buffer[2] = Mins/10; Buffer[3] = Mins%10; if (TimeValid) Buffer[3] = Buffer[3]+128; // Show colon }