Freescale KL25Z DCF77 Atomic clock using 4D Systems uOLED160 OLED display. Displays a graphical display of DCF time signal bit build and sets the local clock time. The main signal timing is achieved by using a Ticker ISR that looks at the DCF signal input every 50mS this also produces the seconds on the local clock incase of signal errors or no signal. Many thanks to Lynton Towler for the idea of this part of the code and Wim who helped me convert it from an Arduino program. The Parity code was from Hans program that works. This dsiplay is considerably better that the nokia LCD.

Dependencies:   mbed

/media/uploads/star297/20130308_220041.jpg

Added RTC clock to top of display that is synchronised to the DCF clock on the middle right of display. Both clocks will continue to run with no signal and will synchronise to DCF when signal returns. The RTC clock is set to the DCF time less 3600 seconds that gives UK (GMT) time. Any multiples of 3600 seconds (1 hour) can be added or subtracted to give the correct RTC time depending on european location (see code line 349). The DCF clock will reset on power down however if the back up cell is fitted the RTC clock should continue to keep time and will display correct time when powered up again, I have not checked this yet. The DCF clock will reset and will synchronise within 2 minutes when power is supplied.

/media/uploads/star297/20130308_220102.jpg

The DCF signal is sampled every 50mS each second that is called by the Interrupt Sub Routine (myISR). All code must be able to complete within 50mS otherwise it may cause the processor to 'hang' particularly durring Oled print functions that tend to be slow (even at 256k baud). So the trck here is to run parts of the code at different 50mS segments of the interrupt counter.

The program starts by looking for the 59th second pulse that is not transmitted, sample50 and sample150 will be zero at this point. When this arrives the interrupt counter is synchonised and the sample150 pulses are counted as '1's and '0's. The time and DCF bit map start on the 21st pulse with the last pulse counted at 58 seconds when partity is checked. If the parity is correct and the time variables are within limits as set in the partity_check subroutine, the DCF clock is set and then the RTC the process then repeats continuously alternating the bit map colour every DCF frame. If there is an error in the signal caused by a high level of noise or missing 'bits' the counters will restart looking for the 59th pulse.

This method of sampling has proved to be far more stable against noise in the DCF signal and will continue to run where as pulse width measuring method I have tried from other program examples requires an almost noise free signal.

I'm affraid the code is pretty poor and sure it could be much improved but it does work rather well.

I have made further checks on this board and have found that unlike the Mbed LPC1768 the coin cell is not for RTC back up. This battery is to run the CPU, RGB led and accelerometer and consumes around 15mA.

The other issue becomes apparent when the board is run from the coin cell and without power from the USB connector. In this case the SDA CPU is in 'sleep' mode that means the RTC clock signal is not generated and fed to the main CPU that results in the RTC freezing.

In conclusion the KL25Z would not be viable for general low power RTC clock functions that require the RTC to keep time when shut down.

Committer:
star297
Date:
Fri Mar 08 21:11:11 2013 +0000
Revision:
1:4f254cca2bac
Parent:
0:e3f7b0fd072e
RTC function added + corrected Leap year code

Who changed what in which revision?

UserRevisionLine numberNew contents of line
star297 0:e3f7b0fd072e 1 #include "mbed.h"
star297 0:e3f7b0fd072e 2 #include "OLED160G1.h"
star297 0:e3f7b0fd072e 3
star297 0:e3f7b0fd072e 4
star297 0:e3f7b0fd072e 5 OLED160G1::OLED160G1(PinName serialTx, PinName serialRx, PinName resetPin) : s(serialTx, serialRx), reset(resetPin) {
star297 0:e3f7b0fd072e 6 s.baud(OLED_BAUDRATE);
star297 0:e3f7b0fd072e 7
star297 0:e3f7b0fd072e 8 while (s.readable()) {
star297 0:e3f7b0fd072e 9 s.getc();
star297 0:e3f7b0fd072e 10 }
star297 0:e3f7b0fd072e 11
star297 0:e3f7b0fd072e 12 locate(0, 0);
star297 0:e3f7b0fd072e 13 setFontColor(0xFFFF);
star297 0:e3f7b0fd072e 14 _fontSize = OLED_FONT5X7;
star297 0:e3f7b0fd072e 15 }
star297 0:e3f7b0fd072e 16
star297 0:e3f7b0fd072e 17 void OLED160G1::resetDisplay() {
star297 0:e3f7b0fd072e 18 reset = 0;
star297 0:e3f7b0fd072e 19 wait_ms(100);
star297 0:e3f7b0fd072e 20 reset = 1;
star297 0:e3f7b0fd072e 21 wait_ms(200);
star297 0:e3f7b0fd072e 22 }
star297 0:e3f7b0fd072e 23
star297 0:e3f7b0fd072e 24 void OLED160G1::getResponse() {
star297 0:e3f7b0fd072e 25 char response = OLED_NAK;
star297 0:e3f7b0fd072e 26 lastCount = 0;
star297 0:e3f7b0fd072e 27 NAKCount = 0;
star297 0:e3f7b0fd072e 28
star297 0:e3f7b0fd072e 29 while (!s.readable() || response == OLED_NAK) {
star297 0:e3f7b0fd072e 30 wait_ms(1);
star297 0:e3f7b0fd072e 31 lastCount++;
star297 0:e3f7b0fd072e 32 if (s.readable()) {
star297 0:e3f7b0fd072e 33 response = s.getc(); // Read response
star297 0:e3f7b0fd072e 34 if (response == OLED_ACK) {
star297 0:e3f7b0fd072e 35 return;
star297 0:e3f7b0fd072e 36 }
star297 0:e3f7b0fd072e 37 else if (response == OLED_NAK) {
star297 0:e3f7b0fd072e 38 NAKCount++;
star297 0:e3f7b0fd072e 39 }
star297 0:e3f7b0fd072e 40 }
star297 0:e3f7b0fd072e 41 }
star297 0:e3f7b0fd072e 42 }
star297 0:e3f7b0fd072e 43
star297 0:e3f7b0fd072e 44 // Initialise OLED display. You must first activate serial comunication!
star297 0:e3f7b0fd072e 45 void OLED160G1::init() {
star297 0:e3f7b0fd072e 46 resetDisplay();
star297 0:e3f7b0fd072e 47
star297 0:e3f7b0fd072e 48 wait_ms(OLED_INIT_DELAY); // wait for initialisation
star297 0:e3f7b0fd072e 49
star297 0:e3f7b0fd072e 50 s.putc(OLED_DETECT_BAUDRATE); // send byte for OLED to autodetect baudrate
star297 0:e3f7b0fd072e 51
star297 0:e3f7b0fd072e 52 getResponse();
star297 0:e3f7b0fd072e 53 }
star297 0:e3f7b0fd072e 54
star297 0:e3f7b0fd072e 55 int OLED160G1::toRGB(int red, int green, int blue) {
star297 0:e3f7b0fd072e 56 int outR = ((red * 31) / 255);
star297 0:e3f7b0fd072e 57 int outG = ((green * 63) / 255);
star297 0:e3f7b0fd072e 58 int outB = ((blue * 31) / 255);
star297 0:e3f7b0fd072e 59
star297 0:e3f7b0fd072e 60 return (outR << 11) | (outG << 5) | outB;
star297 0:e3f7b0fd072e 61 }
star297 0:e3f7b0fd072e 62
star297 0:e3f7b0fd072e 63 void OLED160G1::eraseScreen() {
star297 0:e3f7b0fd072e 64 s.putc(OLED_CLEAR);
star297 0:e3f7b0fd072e 65
star297 0:e3f7b0fd072e 66 wait(1); // TODO: why needed?
star297 0:e3f7b0fd072e 67
star297 0:e3f7b0fd072e 68 getResponse();
star297 0:e3f7b0fd072e 69
star297 0:e3f7b0fd072e 70 _row = 0;
star297 0:e3f7b0fd072e 71 _column = 0;
star297 0:e3f7b0fd072e 72 }
star297 0:e3f7b0fd072e 73
star297 0:e3f7b0fd072e 74 void OLED160G1::drawPixel(char x, char y, int color) {
star297 0:e3f7b0fd072e 75 s.putc(OLED_PUTPIXEL);
star297 0:e3f7b0fd072e 76 s.putc(x);
star297 0:e3f7b0fd072e 77 s.putc(y);
star297 0:e3f7b0fd072e 78
star297 0:e3f7b0fd072e 79 s.putc(color >> 8); // MSB
star297 0:e3f7b0fd072e 80 s.putc(color & 0xFF); // LSB
star297 0:e3f7b0fd072e 81
star297 0:e3f7b0fd072e 82 getResponse();
star297 0:e3f7b0fd072e 83 }
star297 0:e3f7b0fd072e 84
star297 0:e3f7b0fd072e 85 void OLED160G1::drawLine(char x1, char y1, char x2, char y2, int color) {
star297 0:e3f7b0fd072e 86 s.putc(OLED_LINE); // Line
star297 0:e3f7b0fd072e 87
star297 0:e3f7b0fd072e 88 s.putc(x1);
star297 0:e3f7b0fd072e 89 s.putc(y1);
star297 0:e3f7b0fd072e 90 s.putc(x2);
star297 0:e3f7b0fd072e 91 s.putc(y2);
star297 0:e3f7b0fd072e 92
star297 0:e3f7b0fd072e 93 s.putc(color >> 8); // MSB
star297 0:e3f7b0fd072e 94 s.putc(color & 0xFF); // LSB
star297 0:e3f7b0fd072e 95
star297 0:e3f7b0fd072e 96 getResponse();
star297 0:e3f7b0fd072e 97 }
star297 0:e3f7b0fd072e 98
star297 0:e3f7b0fd072e 99 void OLED160G1::drawRectangle(char x, char y, char width, char height, int color) {
star297 0:e3f7b0fd072e 100 s.putc(OLED_RECTANGLE);
star297 0:e3f7b0fd072e 101
star297 0:e3f7b0fd072e 102 s.putc(x);
star297 0:e3f7b0fd072e 103 s.putc(y);
star297 0:e3f7b0fd072e 104
star297 0:e3f7b0fd072e 105 s.putc(x+width);
star297 0:e3f7b0fd072e 106 s.putc(y+height);
star297 0:e3f7b0fd072e 107
star297 0:e3f7b0fd072e 108 s.putc(color >> 8); // MSB
star297 0:e3f7b0fd072e 109 s.putc(color & 0xFF); // LSB
star297 0:e3f7b0fd072e 110
star297 0:e3f7b0fd072e 111 //
star297 0:e3f7b0fd072e 112 // if (filled == 1) { printByte(0x01); } // Filled
star297 0:e3f7b0fd072e 113 //else { printByte(0x00); } // Outline
star297 0:e3f7b0fd072e 114 //
star297 0:e3f7b0fd072e 115 getResponse();
star297 0:e3f7b0fd072e 116 }
star297 0:e3f7b0fd072e 117
star297 0:e3f7b0fd072e 118 void OLED160G1::drawCircle(char x, char y, char radius, int color) {
star297 0:e3f7b0fd072e 119 s.putc(OLED_CIRCLE);
star297 0:e3f7b0fd072e 120
star297 0:e3f7b0fd072e 121 s.putc(x);
star297 0:e3f7b0fd072e 122 s.putc(y);
star297 0:e3f7b0fd072e 123 s.putc(radius);
star297 0:e3f7b0fd072e 124
star297 0:e3f7b0fd072e 125 s.putc(color >> 8); // MSB
star297 0:e3f7b0fd072e 126 s.putc(color & 0xFF); // LSB
star297 0:e3f7b0fd072e 127
star297 0:e3f7b0fd072e 128 getResponse();
star297 0:e3f7b0fd072e 129 }
star297 0:e3f7b0fd072e 130
star297 0:e3f7b0fd072e 131 void OLED160G1::setFontSize(char fontSize) {
star297 0:e3f7b0fd072e 132 s.putc(OLED_SETFONTSIZE);
star297 0:e3f7b0fd072e 133 s.putc(fontSize);
star297 0:e3f7b0fd072e 134 _fontSize = fontSize;
star297 0:e3f7b0fd072e 135
star297 0:e3f7b0fd072e 136 getResponse();
star297 0:e3f7b0fd072e 137 }
star297 0:e3f7b0fd072e 138
star297 0:e3f7b0fd072e 139 void OLED160G1::setFontColor(int fontColor) {
star297 0:e3f7b0fd072e 140 _fontColor = fontColor;
star297 0:e3f7b0fd072e 141 }
star297 0:e3f7b0fd072e 142
star297 0:e3f7b0fd072e 143 void OLED160G1::setPenSize(char penSize) {
star297 0:e3f7b0fd072e 144 s.putc(OLED_PEN_SIZE);
star297 0:e3f7b0fd072e 145
star297 0:e3f7b0fd072e 146 s.putc(penSize);
star297 0:e3f7b0fd072e 147
star297 0:e3f7b0fd072e 148 _penSize = penSize;
star297 0:e3f7b0fd072e 149
star297 0:e3f7b0fd072e 150 getResponse();
star297 0:e3f7b0fd072e 151 }
star297 0:e3f7b0fd072e 152
star297 0:e3f7b0fd072e 153 void OLED160G1::setTextBackgroundType(char textBackgroundType) {
star297 0:e3f7b0fd072e 154 s.putc(OLED_SET_TEXT_BACKGROUND_TYPE);
star297 0:e3f7b0fd072e 155 s.putc(textBackgroundType);
star297 0:e3f7b0fd072e 156
star297 0:e3f7b0fd072e 157 getResponse();
star297 0:e3f7b0fd072e 158 }
star297 0:e3f7b0fd072e 159
star297 0:e3f7b0fd072e 160 void OLED160G1::setBackgroundColor(int color) {
star297 0:e3f7b0fd072e 161 s.putc(OLED_SET_BACKGROUND_COLOR);
star297 0:e3f7b0fd072e 162
star297 0:e3f7b0fd072e 163 s.putc(color >> 8); // MSB
star297 0:e3f7b0fd072e 164 s.putc(color & 0xFF); // LSB
star297 0:e3f7b0fd072e 165
star297 0:e3f7b0fd072e 166 getResponse();
star297 0:e3f7b0fd072e 167 }
star297 0:e3f7b0fd072e 168
star297 0:e3f7b0fd072e 169 void OLED160G1::drawText(char column, char row, char font_size, char *mytext, int color) {
star297 0:e3f7b0fd072e 170 s.putc(OLED_TEXT);
star297 0:e3f7b0fd072e 171
star297 0:e3f7b0fd072e 172 // Adjust to center of the screen (26 Columns at font size 0)
star297 0:e3f7b0fd072e 173 //int newCol = 13 - (strlen(mytext)/2);
star297 0:e3f7b0fd072e 174 //printByte(newCol); // column
star297 0:e3f7b0fd072e 175 s.putc(column); // column
star297 0:e3f7b0fd072e 176
star297 0:e3f7b0fd072e 177 s.putc(row); // row
star297 0:e3f7b0fd072e 178 s.putc(font_size); // font size (0 = 5x7 font, 1 = 8x8 font, 2 = 8x12 font)
star297 0:e3f7b0fd072e 179
star297 0:e3f7b0fd072e 180 s.putc(color >> 8); // MSB
star297 0:e3f7b0fd072e 181 s.putc(color & 0xFF); // LSB
star297 0:e3f7b0fd072e 182
star297 0:e3f7b0fd072e 183 for (int i = 0; i < strlen(mytext); i++) {
star297 0:e3f7b0fd072e 184 s.putc(mytext[i]); // character to write
star297 0:e3f7b0fd072e 185 }
star297 0:e3f7b0fd072e 186 s.putc(0x00); // string terminator (always 0x00)
star297 0:e3f7b0fd072e 187
star297 0:e3f7b0fd072e 188 getResponse();
star297 0:e3f7b0fd072e 189 }
star297 0:e3f7b0fd072e 190
star297 0:e3f7b0fd072e 191 void OLED160G1::drawSingleChar(char column, char row, char theChar, int color) {
star297 0:e3f7b0fd072e 192 s.putc(OLED_TEXTFORMATED);
star297 0:e3f7b0fd072e 193
star297 0:e3f7b0fd072e 194 s.putc(theChar);
star297 0:e3f7b0fd072e 195 s.putc(column);
star297 0:e3f7b0fd072e 196 s.putc(row);
star297 0:e3f7b0fd072e 197
star297 0:e3f7b0fd072e 198 s.putc(color >> 8); // MSB
star297 0:e3f7b0fd072e 199 s.putc(color & 0xFF); // LSB
star297 0:e3f7b0fd072e 200
star297 0:e3f7b0fd072e 201 getResponse();
star297 0:e3f7b0fd072e 202 }
star297 0:e3f7b0fd072e 203
star297 0:e3f7b0fd072e 204 void OLED160G1::displayControl(char mode, char value) {
star297 0:e3f7b0fd072e 205 s.putc(OLED_COMMAND_CONTROL);
star297 0:e3f7b0fd072e 206
star297 0:e3f7b0fd072e 207 s.putc(mode);
star297 0:e3f7b0fd072e 208 s.putc(value);
star297 0:e3f7b0fd072e 209
star297 0:e3f7b0fd072e 210 getResponse();
star297 0:e3f7b0fd072e 211 }
star297 0:e3f7b0fd072e 212
star297 0:e3f7b0fd072e 213 char OLED160G1::getPenSize() {
star297 0:e3f7b0fd072e 214 return _penSize;
star297 0:e3f7b0fd072e 215 }
star297 0:e3f7b0fd072e 216
star297 0:e3f7b0fd072e 217 int OLED160G1::_putc(int value) {
star297 0:e3f7b0fd072e 218 if (value == '\n') {
star297 0:e3f7b0fd072e 219 _column = 0;
star297 0:e3f7b0fd072e 220 _row++;
star297 0:e3f7b0fd072e 221 if(_row >= rows()) {
star297 0:e3f7b0fd072e 222 _row = 0;
star297 0:e3f7b0fd072e 223 }
star297 0:e3f7b0fd072e 224 } else {
star297 0:e3f7b0fd072e 225 drawSingleChar(_column, _row, value, _fontColor);
star297 0:e3f7b0fd072e 226
star297 0:e3f7b0fd072e 227 wait_ms(1); //TODO: why is this needed?
star297 0:e3f7b0fd072e 228
star297 0:e3f7b0fd072e 229 _column++;
star297 0:e3f7b0fd072e 230 if (_column >= columns()) {
star297 0:e3f7b0fd072e 231 _column = 0;
star297 0:e3f7b0fd072e 232 _row++;
star297 0:e3f7b0fd072e 233 if(_row >= rows()) {
star297 0:e3f7b0fd072e 234 _row = 0;
star297 0:e3f7b0fd072e 235 }
star297 0:e3f7b0fd072e 236 }
star297 0:e3f7b0fd072e 237 }
star297 0:e3f7b0fd072e 238 return value;
star297 0:e3f7b0fd072e 239 }
star297 0:e3f7b0fd072e 240
star297 0:e3f7b0fd072e 241 int OLED160G1::_getc() {
star297 0:e3f7b0fd072e 242 return -1;
star297 0:e3f7b0fd072e 243 }
star297 0:e3f7b0fd072e 244
star297 0:e3f7b0fd072e 245 void OLED160G1::locate(int column, int row) {
star297 0:e3f7b0fd072e 246 _column = column;
star297 0:e3f7b0fd072e 247 _row = row;
star297 0:e3f7b0fd072e 248 }
star297 0:e3f7b0fd072e 249
star297 0:e3f7b0fd072e 250 int OLED160G1::rows() {
star297 0:e3f7b0fd072e 251 return 16;
star297 0:e3f7b0fd072e 252 }
star297 0:e3f7b0fd072e 253
star297 0:e3f7b0fd072e 254 int OLED160G1::columns() {
star297 0:e3f7b0fd072e 255 return 26;
star297 0:e3f7b0fd072e 256 }