Software Radio Clock for Windows
Decode and display the 60KHz time signal in MS windows.
Components and supplies
Arduino UNO
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
Tools and machines
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