Software Radio Clock for Windows
Decode and display the 60KHz time signal in MS windows.
Devices & Components
Arduino Uno Rev3
Led fixing ring to fit 5mm led
Dual in Line Socket 6 pin
resistor 1k ohm 0.5watt
3 wire headphone lead 5metres
Reel of kynar wire 30awg
3 pin stereo socket 3.5mm
Red Led 5mm
PP3 battery
Canaduino Atomic clock receiver module
3pin streo plug 3.5mm
H11 L1M optoisolator
single pole single throw miniture on/off switch
Box 130x68x44 mm
PP3 connector with two tail
stripboard 9x25 holes 25x64 mm
Hardware & Tools
soldering iron miniture tip
solder flux
2mm drill tip (for isolating the necessary copper strips on the strip boards)
miniture electrical pliers
miniture electrical cutters
Project description
Code
Arduino-Lazarus_MSF Clock
c_cpp
Arduino interrupt sketch
1//************************************************************************************************** 2// Serial MSF Test Clock (C) Copyright 2014 Phil Morris 3 4// a "Proof of Concept" sketch for the Arduino Uno Rev 3 and an MSF Clock module 5// No apologies given for the messy code as this is a sketch simply to show 6// some ideas around decoding MSF time signals. The code takes account of Leep 7// seconds and performs full parity checking. A simple output is provided to the 8// Serial port at 9600 baud. BST/GMT is decoded along with UTC & DUT difference. 9// even partial data reception can produce a valid output as long as seconds 17 thru 59 10// are received correctly. 11// 12// For diagnostic purposes, the minimum and maximum pulse lengths are also displayed in ms 13// 14// You may use, modify and/or distribute this sketch as long as you leave this text intact. 15 16//**************************************************************************************************** 17 // MSF 60KHz Interrupt driven decode program to feed Lazarus/Delphi(Pascal) high level decode program. 18 // John Garrett 2020. 19 // Modified from a part of sketch copyright of Phil Morris. 20 21 // the msf transmitter is switched off for brief intervals (on-off keying) near the beginning of each second 22 // to encode the current time and date. When carrier is low data is active. Every second the 23 // carrier goes low to signify data. Apart from the first second every second consists 24 // of a 100ms pulse. This is followed by no data when the carrier is high for 900ms or 25 // another 100ms pulse giving 200ms all together signifying an A data. Or an extra 100ms 26 // pulse making 300ms in all, giving an A and B data. For B data only the second pulse 27 // consists of the statuary 100ms low followed by 100ms high followed by another 100ms low 28 // beginning of every minute the first second consists of 500ms low followed by 500ms high. 29 // each second pulse apart from the minute marker should be up to 300ms low and up to 900ms high. 30 // the data during the current minute is for the following minute of time. 31 32const int CARRIER_OFF = LOW; // this constant is set for non-inverted MSF receiver output ie Carrier_Off equals a low. 33 // invert it if your output = HIGH for carrier off. 34 35const int MSFPIN = 3; // the Arduino pin for the MSF device (2 or 3). 36 37volatile long pulseStart = 0; // milliseconds when start of pulse occurred. 38volatile long pulseEnd = 0; // milliseconds when pulse ended. 39volatile long lastPulseStart = 0; // the previous pulse start value. 40volatile int pulseLength = 0; // length of pulse/100 as an integer. 41volatile bool bitBonly = false; // set if a 'B' only pulse detected. 42volatile bool printTime = false; 43volatile bool sync = false; //true if valid start pulse. 44volatile int counter = 0; // seconds counter. 45volatile int LED_PIN = 13; // pin LED is attached (optional). 46volatile int minMaxPulse = 0; // actual length in millis. 47 48void setup() { 49 Serial.begin(9600); // start the Serial port 50 attachInterrupt(MSFPIN - 2, MsfPulse, CHANGE); // set the interrupt 51 pinMode(LED_PIN,OUTPUT); // configue the LED pin 52} 53 54void loop() 55{ 56} 57 58void MsfPulse() // interrupt routine which is called every time the MSF receiver output changes state 59{ 60// This routine is called every time the selected Interrupt pin changes state. If it is the start of 61// a pulse, the millis count is stored in "pulseStart". If it is the end of a pulse the millis count 62// is stored in "pulseEnd". "pulseLength" is the result in millis/100. The data is processed to produce an 63// integer 1 - 5 representing 100 - 500 ms pulses (no "4" is decoded).If pulselength = 5 then the sync flag becomes true 64// counter is then = '0'. Once counter reaches == '59' the sync flag becomes false. 65// If the sequence was 100ms off + 100ms on + 100ms off, this is a 'B' only bit.So if this start pulse is less than 300ms 66// after the last start pulse it must be a double 100ms pulse second resulting a bitBonly flag being true. 67 68 69 bitBonly = false; // clear the bitOnly flag 70 bool pinState = digitalRead(MSFPIN); // get the state of the interrupt pin 71 72 // is this a pulse start? 73 74 if (pinState == CARRIER_OFF) // pulse or sub-pulse has started, carrier going low 75 { 76 pulseStart = millis(); // pulseStart = current millis everytime the MSFPIN goes low (carrier going low) 77 digitalWrite(LED_PIN,HIGH); // turn on LED 78 counter = counter +1; 79 if (printTime == true && counter == 60) 80 { 81 Serial.print('6'); // signify to Lazarus to display time scenario 82 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 83 Serial.print(counter); 84 Serial.print("."); 85 } 86 return; // until there's a another interrupt change 87 } 88 89 90 // is it a pulse end? 91 92 if(pinState != CARRIER_OFF) // pulse end, MSFPIN goes high (carrier going high) 93 { 94 pulseEnd = millis(); // set the pulse end ms,the MSFPIN goes high 95 minMaxPulse = pulseEnd - pulseStart; // actual length in millis 96 pulseLength = abs((minMaxPulse) / 100); // get the pulse length in ms/100 97 pulseStart = millis(); // set the pulseStart to current millis 98 if (minMaxPulse < 90) return; // the pulse is too short ("noise"), return 99 if (counter == 59 && sync) pulseLength = 4; // 59th second 100 101// if the sequence was 100ms off + 100ms on + 100ms off, this is a 'B' only bit 102// so, if this start pulse is less than 300ms after the last start pulse it must be 103// a double 100ms pulse second 104 105 if(pulseStart - lastPulseStart < 300) bitBonly = true; // this is a 'B' bit 106 lastPulseStart = pulseStart; // keep the last pulse start ms count 107 digitalWrite(LED_PIN,LOW); // turn off the LED 108 } 109 110 switch(pulseLength) // start processing the valid pulse 111 { 112 case 5: // check for start pulse i.e. 500ms (11111) 113 { 114 if(minMaxPulse > 490 && minMaxPulse < 550) 115 { 116 sync = true; 117 printTime = false; 118 counter = 0; 119 Serial.print('5'); // signify to Lazarus a sync scenario 120 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 121 Serial.print(counter); 122 Serial.print("."); 123 } 124 break; 125 } 126 127 case 4: // 59th second tell Lazarus to compute time (100) 128 { 129 sync = false; 130 Serial.print('4'); // signify to Lazarus to compute time 131 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 132 Serial.print(counter); 133 Serial.print("."); 134 printTime = true; 135 break; 136 } 137 138 case 3: // check for 300ms pulse, this is an 'A' + 'B' bit case (111) 139 { 140 if(minMaxPulse > 290 && minMaxPulse < 350 && sync) 141 { 142 Serial.print('3'); // signify to Lazarus a 'A + B' data scenario 143 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 144 Serial.print(counter); 145 Serial.print("."); 146 } 147 break; 148 } 149 150 case 2: // check for 200ms pulse, this is an 'A' bit case (110) 151 { 152 if(minMaxPulse > 190 && minMaxPulse < 250 && sync) 153 { 154 Serial.print('2'); // signify to Lazarus a 'A' data scenario 155 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 156 Serial.print(counter); 157 Serial.print("."); 158 } 159 break; 160 } 161 162 case 1: // check for 100ms pulse (101 or 100) 163 { 164 if(minMaxPulse > 90 && minMaxPulse < 150 && sync) 165 { 166 if(bitBonly) 167 { 168 counter = counter-1; // to prevent a double count 'B' data only 169 Serial.print('1'); // signify to Lazarus a 'B' data scenario 170 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 171 Serial.print(counter); 172 Serial.print("."); 173 } 174 else 175 { 176 Serial.print('0'); // signify to Lazarus a 'No' data scenario 177 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 178 Serial.print(counter); 179 Serial.print('.'); 180 } 181 } 182 break; 183 } 184 185 } 186 187} 188
Lazarus Pascal source file
pascal
Pascal source file
1unit mfs60; 2 3{$mode objfpc}{$H+} 4 5interface 6 7uses 8 Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, 9 StrUtils,Controls.SegmentDisplay, Controls.Blinker, CPort; 10 11 12type 13 14 { TForm1 } 15 16 TForm1 = class(TForm) 17 BlinkerBlue: TBlinker; 18 BlinkerGreen: TBlinker; 19 BlinkerPurple: TBlinker; 20 BlinkerRed: TBlinker; 21 BlinkerWhite: TBlinker; 22 BlinkerYellow: TBlinker; 23 ComPort4: TComPort; 24 ImageList1: TImageList; 25 LabelBST: TLabel; 26 LabelBstImm: TLabel; 27 LabelPEBits: TLabel; 28 LabelSync: TLabel; 29 LabelParity: TLabel; 30 LabelComPort: TLabel; 31 LabelDay: TLabel; 32 LabelDayName: TLabel; 33 LabelDow: TLabel; 34 LabelDut: TLabel; 35 LabelDutms: TLabel; 36 LabelMonth: TLabel; 37 LabelSeconds: TLabel; 38 LabelTime: TLabel; 39 LabelYear: TLabel; 40 RadioButtonDutMinus: TRadioButton; 41 RadioButtonDutPlus: TRadioButton; 42 SegmentDisplayDay: TSegmentDisplay; 43 SegmentDisplayDow: TSegmentDisplay; 44 SegmentDisplayDut: TSegmentDisplay; 45 SegmentDisplayMonth: TSegmentDisplay; 46 SegmentDisplaySeconds: TSegmentDisplay; 47 SegmentDisplayTime: TSegmentDisplay; 48 SegmentDisplayYear: TSegmentDisplay; 49 50 procedure Setup(Sender: TObject); 51 procedure Close(Sender: TObject; var CloseAction: TCloseAction); 52 procedure DataInput(Sender: TObject; Count: Integer); 53 54 private 55 procedure DataSort; 56 function Dut1(start,finish:integer):string; 57 function Year:string; 58 function Month:string; 59 function Day: string; 60 function DOW: string; 61 function Time:string; 62 function BcdToStr(bit,count:integer):string; 63 function ParityCheck(Sbit,count,Pbit:integer):boolean; 64 public 65 66 end; 67 68var 69 Form1: TForm1; 70 bufferA, bufferB: array[0..59] of integer; 71 Strbuff: string; 72 Sync: Boolean; 73 Bst: Integer; 74 75implementation 76 77{$R *.lfm} 78 79{ TForm1 } 80 81procedure TForm1.Setup(Sender: TObject); //Form create event 82begin 83 SegmentDisplayDay.Text:= ''; 84 SegmentDisplayMonth.Text:= ''; 85 SegmentDisplayYear.Text:= ''; 86 SegmentDisplayDow.Text:= ''; 87 SegmentDisplayTime.Text:= ''; 88 SegmentDisplaySeconds.Text:= ''; 89 SegmentDisplayDut.Text:= ''; 90 LabelDayName.Caption:=''; 91 BlinkerYellow.IsOn:= false; 92 BlinkerPurple.IsOn:= false; 93 BlinkerGreen.IsOn:= false; 94 BlinkerRed.Ison:= false; 95 BlinkerBlue.Ison:= false; 96 LabelPEBits.Visible:= false; 97 RadioButtonDutPlus.Checked:= false; 98 RadioButtonDutMinus.Checked:= false; 99 Strbuff:=''; 100 Sync:= false; 101 Bst:= 0; 102 103 ComPort4.LoadSettings(stIniFile,'C:\\ComPortSettings.ini'); 104 105 if not ComPort4.Connected then 106 begin 107 try 108 ComPort4.Open; 109 except 110 ShowMessage('Unable to open COM port.'); 111 end; 112 end; 113 if ComPort4.Connected then 114 BlinkerBlue.IsOn:= true 115 else 116 BlinkerBlue.IsOn:= false; 117 118end; 119 120 121procedure TForm1.Close(Sender: TObject; var CloseAction: TCloseAction); 122begin 123 ComPort4.Close; 124 CloseAction:= caFree; 125end; 126 127procedure TForm1.DataInput(Sender: TObject; Count: Integer); 128var 129 Str, s: String; 130begin 131 // Receives msf data from Arduino. 132 Str:= ''; 133 ComPort4.ReadStr(Str, Count); 134 Strbuff:= Strbuff + Str; //Save in Global Buffer 135 s:= RightStr(Str,1); 136 if s = '.' then DataSort; 137end; 138 139procedure TForm1.DataSort; 140var 141 secpointer,counter,error: string; 142 i,j,n: integer; 143 144begin 145 secpointer:= LeftStr(Strbuff,1); 146 counter:= MidStr(Strbuff,2,2); 147 if counter = '60' then counter := '00'; 148 j:= StrToInt(secpointer); 149 n:= StrToInt(counter); 150 SegmentDisplaySeconds.Text:= counter; 151 152 if odd(n) then BlinkerWhite.IsOn:= true //switch secs indicator on/off 153 else 154 BlinkerWhite.IsOn:= false; 155 156 157 Case j of 158 6: begin //show time at 00 159 SegmentDisplayDut.Text:= Dut1(1,8); 160 SegmentDisplayDut.Text:= Dut1(9,16); 161 SegmentDisplayYear.Text:= Year; 162 SegmentDisplayMonth.Text:= Month; 163 SegmentDisplayDay.Text:= Day; 164 SegmentDisplayDow.Text:= LeftStr(DOW,1); 165 LabelDayName.Caption:= MidStr(DOW,2,(Length(DOW)-1)); 166 SegmentDisplayTime.Text:= Time; 167 168 if Bst = 0 then //GMT Time 169 begin 170 BlinkerYellow.IsOn:= false; 171 BlinkerPurple.IsOn:= false; 172 end; 173 174 if Bst = 1 then //BST imminent 175 begin 176 BlinkerYellow.IsOn:= false; 177 BlinkerPurple.IsOn:= true; 178 end; 179 180 if Bst = 2 then 181 begin //BST Time 182 BlinkerYellow.IsOn:= true; 183 BlinkerPurple.IsOn:= false; 184 end; 185 186 for i:= 0 to 59 do // Clear time Buffers 187 begin 188 bufferA[i]:= 0; 189 bufferB[i]:= 0; 190 end; 191 192 end; 193 194 5: begin 195 Sync:= true; 196 BlinkerGreen.IsOn:= true; 197 bufferA[n]:= 5; 198 bufferB[n]:= 5; 199 end; 200 201 4: begin // 59 seconds 202 if Sync then 203 begin 204 Sync:= false; 205 BlinkerGreen.IsOn:= false; 206 207 Bst:= 0; // Reset to GMT flag 208 if bufferB[53] = 1 then Bst:= 1; //BST imminent flag 209 if bufferB[58] = 1 then Bst:= 2; // BST flag 210 211 error:= ''; 212 213 if not ParityCheck(17,8,54) then error:= '17 to 24, '; 214 if not ParityCheck(25,11,55)then error:= error + '25 to 35, '; 215 if not ParityCheck(36,3,56) then error:= error + '36 to 38, '; 216 if not ParityCheck(39,13,57)then error:= error + '39 to 51'; 217 218 If Length(error) = 0 then 219 begin 220 BlinkerRed.IsON:= false; 221 LabelPEBits.Visible:= false; 222 LabelPEBits.Caption:= ''; 223 end 224 else 225 begin 226 BlinkerRed.IsON:= true; 227 LabelPEBits.Visible:= true; 228 LabelPEBits.Caption:= 'Bits '+ error; 229 end; 230 231 232 bufferA[n]:= 4; 233 bufferB[n]:= 4; 234 235 end; 236 237 end; 238 239 3: begin //A & B pulse 240 if Sync then 241 begin 242 bufferA[n]:= 1; 243 bufferB[n]:= 1; 244 end; 245 end; 246 2: begin //A pulse only 247 if Sync then 248 begin 249 bufferA[n]:= 1; 250 bufferB[n]:= 0; 251 end; 252 end; 253 1: begin //B pulse only 254 if Sync then 255 begin 256 bufferA[n]:= 0; 257 bufferB[n]:= 1; 258 end; 259 end; 260 0: begin //No A or B pulse 261 if Sync then 262 begin 263 bufferA[n]:= 0; 264 bufferB[n]:= 0; 265 end; 266 end; 267 268 end; 269 If RightStr(Strbuff,1)= '.' then Strbuff:= ''; 270end; 271 272 273function TForm1.Dut1(start,finish:integer):string; 274var 275 j,n:integer; 276begin 277 RadioButtonDutPlus.Checked:= false; 278 RadioButtonDutMinus.Checked:= false; 279 280 j:= 0; 281 for n := start to finish do 282 begin 283 if bufferB[n] = 1 then j := j+1; 284 end; 285 286 if (finish = 8) and (j > 0) then RadioButtonDutPlus.Checked:= True; 287 if (finish = 16) and (j > 0) then RadioButtonDutMinus.Checked:= True; 288 289 j:= j*100; 290 Result:= IntToStr(j); 291end; 292 293function TForm1.Year:string; 294var 295 s,t: string; 296begin 297 s:= BcdToStr(20,4); 298 t:= BcdToStr(24,4); 299 Result:= s + t; 300end; 301 302function TForm1.Month:string; 303var 304 s,t: string; 305begin 306 s:= BcdToStr(25,1); 307 t:= BcdToStr(29,4); 308 Result:= s + t; 309end; 310 311function TForm1.Day:string; 312var 313 s,t: string; 314begin 315 s:= BcdToStr(31,2); 316 t:= BcdToStr(35,4); 317 Result:= s + t; 318end; 319 320function TForm1.DOW:string; 321var 322 i: integer; 323 s: string; 324begin 325 s:= BcdToStr(38,3); 326 i:= StrToInt(s); 327 Case i of 328 0: Result:= s + 'Sunday'; 329 1: Result:= s + 'Monday'; 330 2: Result:= s + 'Tuesday'; 331 3: Result:= s + 'Wednesday'; 332 4: Result:= s + 'Thursday'; 333 5: Result:= s + 'Friday'; 334 6: Result:= s + 'Saturday'; 335 end; 336end; 337 338function TForm1.Time:string; 339var 340 s,t,u,v: string; 341begin 342 s:= BcdToStr(40,2); 343 t:= BcdToStr(44,4); 344 u:= BcdToStr(47,3); 345 v:= BcdToStr(51,4); 346 Result := s + t + u + v; 347end; 348 349function TForm1.BcdToStr(bit,count:integer):string; 350var 351 total: integer; 352begin 353 total:= 0; 354 while count > 0 do 355 begin 356 if bufferA[bit] = 1 then total:= 1; 357 count:= count-1; 358 if count = 0 then break; 359 if bufferA[bit-1] = 1 then total:= total + 2; 360 count:= count-1; 361 if count = 0 then break; 362 if bufferA[bit-2] = 1 then total:= total + 4; 363 count:= count-1; 364 if count = 0 then break; 365 if bufferA[bit-3] = 1 then total:= total + 8; 366 count:= count-1; 367 end; 368 Result:= IntToStr(total); 369end; 370 371function TForm1.ParityCheck(Sbit,count,Pbit:integer):boolean; 372var 373 total,n: integer; 374begin 375 total:= 0; 376 for n:= 0 to count -1 do 377 if bufferA[Sbit + n] = 1 then total := total + 1; 378 379 total:= total + bufferB[Pbit]; 380 381 if odd(total) then Result:= true 382 else 383 Result:= false; 384end; 385 386end. 387 388
Arduino-Lazarus_MSF Clock
c_cpp
Arduino interrupt sketch
1//************************************************************************************************** 2// Serial MSF Test Clock (C) Copyright 2014 Phil Morris 3 4// a "Proof of Concept" sketch for the Arduino Uno Rev 3 and an MSF Clock module 5// No apologies given for the messy code as this is a sketch simply to show 6// some ideas around decoding MSF time signals. The code takes account of Leep 7// seconds and performs full parity checking. A simple output is provided to the 8// Serial port at 9600 baud. BST/GMT is decoded along with UTC & DUT difference. 9// even partial data reception can produce a valid output as long as seconds 17 thru 59 10// are received correctly. 11// 12// For diagnostic purposes, the minimum and maximum pulse lengths are also displayed in ms 13// 14// You may use, modify and/or distribute this sketch as long as you leave this text intact. 15 16//**************************************************************************************************** 17 // MSF 60KHz Interrupt driven decode program to feed Lazarus/Delphi(Pascal) high level decode program. 18 // John Garrett 2020. 19 // Modified from a part of sketch copyright of Phil Morris. 20 21 // the msf transmitter is switched off for brief intervals (on-off keying) near the beginning of each second 22 // to encode the current time and date. When carrier is low data is active. Every second the 23 // carrier goes low to signify data. Apart from the first second every second consists 24 // of a 100ms pulse. This is followed by no data when the carrier is high for 900ms or 25 // another 100ms pulse giving 200ms all together signifying an A data. Or an extra 100ms 26 // pulse making 300ms in all, giving an A and B data. For B data only the second pulse 27 // consists of the statuary 100ms low followed by 100ms high followed by another 100ms low 28 // beginning of every minute the first second consists of 500ms low followed by 500ms high. 29 // each second pulse apart from the minute marker should be up to 300ms low and up to 900ms high. 30 // the data during the current minute is for the following minute of time. 31 32const int CARRIER_OFF = LOW; // this constant is set for non-inverted MSF receiver output ie Carrier_Off equals a low. 33 // invert it if your output = HIGH for carrier off. 34 35const int MSFPIN = 3; // the Arduino pin for the MSF device (2 or 3). 36 37volatile long pulseStart = 0; // milliseconds when start of pulse occurred. 38volatile long pulseEnd = 0; // milliseconds when pulse ended. 39volatile long lastPulseStart = 0; // the previous pulse start value. 40volatile int pulseLength = 0; // length of pulse/100 as an integer. 41volatile bool bitBonly = false; // set if a 'B' only pulse detected. 42volatile bool printTime = false; 43volatile bool sync = false; //true if valid start pulse. 44volatile int counter = 0; // seconds counter. 45volatile int LED_PIN = 13; // pin LED is attached (optional). 46volatile int minMaxPulse = 0; // actual length in millis. 47 48void setup() { 49 Serial.begin(9600); // start the Serial port 50 attachInterrupt(MSFPIN - 2, MsfPulse, CHANGE); // set the interrupt 51 pinMode(LED_PIN,OUTPUT); // configue the LED pin 52} 53 54void loop() 55{ 56} 57 58void MsfPulse() // interrupt routine which is called every time the MSF receiver output changes state 59{ 60// This routine is called every time the selected Interrupt pin changes state. If it is the start of 61// a pulse, the millis count is stored in "pulseStart". If it is the end of a pulse the millis count 62// is stored in "pulseEnd". "pulseLength" is the result in millis/100. The data is processed to produce an 63// integer 1 - 5 representing 100 - 500 ms pulses (no "4" is decoded).If pulselength = 5 then the sync flag becomes true 64// counter is then = '0'. Once counter reaches == '59' the sync flag becomes false. 65// If the sequence was 100ms off + 100ms on + 100ms off, this is a 'B' only bit.So if this start pulse is less than 300ms 66// after the last start pulse it must be a double 100ms pulse second resulting a bitBonly flag being true. 67 68 69 bitBonly = false; // clear the bitOnly flag 70 bool pinState = digitalRead(MSFPIN); // get the state of the interrupt pin 71 72 // is this a pulse start? 73 74 if (pinState == CARRIER_OFF) // pulse or sub-pulse has started, carrier going low 75 { 76 pulseStart = millis(); // pulseStart = current millis everytime the MSFPIN goes low (carrier going low) 77 digitalWrite(LED_PIN,HIGH); // turn on LED 78 counter = counter +1; 79 if (printTime == true && counter == 60) 80 { 81 Serial.print('6'); // signify to Lazarus to display time scenario 82 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 83 Serial.print(counter); 84 Serial.print("."); 85 } 86 return; // until there's a another interrupt change 87 } 88 89 90 // is it a pulse end? 91 92 if(pinState != CARRIER_OFF) // pulse end, MSFPIN goes high (carrier going high) 93 { 94 pulseEnd = millis(); // set the pulse end ms,the MSFPIN goes high 95 minMaxPulse = pulseEnd - pulseStart; // actual length in millis 96 pulseLength = abs((minMaxPulse) / 100); // get the pulse length in ms/100 97 pulseStart = millis(); // set the pulseStart to current millis 98 if (minMaxPulse < 90) return; // the pulse is too short ("noise"), return 99 if (counter == 59 && sync) pulseLength = 4; // 59th second 100 101// if the sequence was 100ms off + 100ms on + 100ms off, this is a 'B' only bit 102// so, if this start pulse is less than 300ms after the last start pulse it must be 103// a double 100ms pulse second 104 105 if(pulseStart - lastPulseStart < 300) bitBonly = true; // this is a 'B' bit 106 lastPulseStart = pulseStart; // keep the last pulse start ms count 107 digitalWrite(LED_PIN,LOW); // turn off the LED 108 } 109 110 switch(pulseLength) // start processing the valid pulse 111 { 112 case 5: // check for start pulse i.e. 500ms (11111) 113 { 114 if(minMaxPulse > 490 && minMaxPulse < 550) 115 { 116 sync = true; 117 printTime = false; 118 counter = 0; 119 Serial.print('5'); // signify to Lazarus a sync scenario 120 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 121 Serial.print(counter); 122 Serial.print("."); 123 } 124 break; 125 } 126 127 case 4: // 59th second tell Lazarus to compute time (100) 128 { 129 sync = false; 130 Serial.print('4'); // signify to Lazarus to compute time 131 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 132 Serial.print(counter); 133 Serial.print("."); 134 printTime = true; 135 break; 136 } 137 138 case 3: // check for 300ms pulse, this is an 'A' + 'B' bit case (111) 139 { 140 if(minMaxPulse > 290 && minMaxPulse < 350 && sync) 141 { 142 Serial.print('3'); // signify to Lazarus a 'A + B' data scenario 143 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 144 Serial.print(counter); 145 Serial.print("."); 146 } 147 break; 148 } 149 150 case 2: // check for 200ms pulse, this is an 'A' bit case (110) 151 { 152 if(minMaxPulse > 190 && minMaxPulse < 250 && sync) 153 { 154 Serial.print('2'); // signify to Lazarus a 'A' data scenario 155 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 156 Serial.print(counter); 157 Serial.print("."); 158 } 159 break; 160 } 161 162 case 1: // check for 100ms pulse (101 or 100) 163 { 164 if(minMaxPulse > 90 && minMaxPulse < 150 && sync) 165 { 166 if(bitBonly) 167 { 168 counter = counter-1; // to prevent a double count 'B' data only 169 Serial.print('1'); // signify to Lazarus a 'B' data scenario 170 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 171 Serial.print(counter); 172 Serial.print("."); 173 } 174 else 175 { 176 Serial.print('0'); // signify to Lazarus a 'No' data scenario 177 if (counter <= 9) Serial.print('0'); //too satisfy Lazarus program 178 Serial.print(counter); 179 Serial.print('.'); 180 } 181 } 182 break; 183 } 184 185 } 186 187} 188
Comments
Only logged in users can leave comments