DCF77 fixes
This commit is contained in:
		
							parent
							
								
									82489524d3
								
							
						
					
					
						commit
						3c913095a2
					
				| @ -7,10 +7,15 @@ extern TaskHandle_t DCF77Task; | ||||
| extern hw_timer_t *dcfCycle; | ||||
| 
 | ||||
| enum dcf_pulses { dcf_off, dcf_zero, dcf_one }; | ||||
| enum dcf_pinstate { dcf_low, dcf_high }; | ||||
| 
 | ||||
| void IRAM_ATTR DCF77IRQ(void); | ||||
| int dcf77_init(void); | ||||
| void dcf77_loop(void *pvParameters); | ||||
| void IRAM_ATTR DCF77IRQ(void); | ||||
| void sendDCF77(void); | ||||
| void DCF_Out(uint8_t startsec); | ||||
| void generateTimeframe(time_t t); | ||||
| void set_DCF77_pin(dcf_pinstate state); | ||||
| uint8_t dec2bcd(uint8_t dec, uint8_t startpos, uint8_t endpos, uint8_t pArray[]); | ||||
| 
 | ||||
| #endif | ||||
| @ -2,9 +2,11 @@ | ||||
| // Emulate a DCF77 radio receiver
 | ||||
| //
 | ||||
| // parts of this code werde adapted from source:
 | ||||
| //
 | ||||
| https://www.elektormagazine.com/labs/dcf77-emulator-with-esp8266-elektor-labs-version-150713
 | ||||
| //
 | ||||
| // a nice & free logic test program for DCF77 can be found here:
 | ||||
| https://www-user.tu-chemnitz.de/~heha/viewzip.cgi/hs/Funkuhr.zip/
 | ||||
| //
 | ||||
| */ | ||||
| 
 | ||||
| #if defined HAS_DCF77 | ||||
| @ -25,10 +27,11 @@ uint8_t DCFtimeframe[DCF77_FRAME_SIZE]; | ||||
| // initialize and configure DCF77 output
 | ||||
| int dcf77_init(void) { | ||||
| 
 | ||||
|   time_t t, tt; | ||||
|   BitsPending = false; | ||||
| 
 | ||||
|   pinMode(HAS_DCF77, OUTPUT); | ||||
|   digitalWrite(HAS_DCF77, HIGH); | ||||
|   set_DCF77_pin(dcf_low); | ||||
| 
 | ||||
|   xTaskCreatePinnedToCore(dcf77_loop,  // task function
 | ||||
|                           "dcf77loop", // name of task
 | ||||
| @ -46,34 +49,25 @@ int dcf77_init(void) { | ||||
|   timerAttachInterrupt(dcfCycle, &DCF77IRQ, true); | ||||
|   timerAlarmWrite(dcfCycle, 1000, true); // 100ms cycle
 | ||||
| 
 | ||||
|   // wait until beginning of next minute, then start DCF pulse
 | ||||
|   // wait until beginning of next second, then kick off first DCF pulse and
 | ||||
|   // start timer interrupt
 | ||||
| 
 | ||||
|   t = tt = now(); | ||||
|   do { | ||||
|     delay(2); | ||||
|   } while (second()); | ||||
|     tt = now(); | ||||
|   } while (t == tt); | ||||
| 
 | ||||
|   DCF_Out(second(tt)); | ||||
|   timerAlarmEnable(dcfCycle); | ||||
| 
 | ||||
|   return 1; // success
 | ||||
| 
 | ||||
| } // ifdcf77_init
 | ||||
| 
 | ||||
| uint8_t dec2bcd(uint8_t dec, uint8_t startpos, uint8_t endpos, | ||||
|                 uint8_t pArray[]) { | ||||
| 
 | ||||
|   uint8_t data = (dec < 10) ? dec : ((dec / 10) << 4) + (dec % 10); | ||||
|   uint8_t parity = 0; | ||||
| 
 | ||||
|   for (uint8_t n = startpos; n <= endpos; n++) { | ||||
|     pArray[n] = (data & 1) ? dcf_one : dcf_zero; | ||||
|     parity += (data & 1); | ||||
|     data >>= 1; | ||||
|   } | ||||
| 
 | ||||
|   return parity; | ||||
| } | ||||
| 
 | ||||
| void generateTimeframe(time_t t) { | ||||
| void generateTimeframe(time_t tt) { | ||||
| 
 | ||||
|   uint8_t ParityCount; | ||||
|   time_t t = myTZ.toLocal(tt); // convert to local time
 | ||||
| 
 | ||||
|   // ENCODE HEAD
 | ||||
|   // bits 0..19 initialized with zeros
 | ||||
| @ -118,24 +112,15 @@ void generateTimeframe(time_t t) { | ||||
|   */ | ||||
| } | ||||
| 
 | ||||
| // helper function to convert gps date/time into time_t
 | ||||
| time_t nextMinute(time_t t) { | ||||
|   tmElements_t tm; | ||||
|   breakTime(t, tm); | ||||
|   tm.Minute++; | ||||
|   tm.Second = 0; | ||||
|   return makeTime(tm); | ||||
| } | ||||
| 
 | ||||
| // called every 100msec by hardware timer to pulse out DCF signal
 | ||||
| void DCF_Out() { | ||||
| void DCF_Out(uint8_t startsec) { | ||||
| 
 | ||||
|   static uint8_t bit = 0; | ||||
|   static uint8_t bit = startsec; | ||||
|   static uint8_t pulse = 0; | ||||
| 
 | ||||
|   if (!BitsPending) { | ||||
|     // prepare frame for next minute to send
 | ||||
|     generateTimeframe(nextMinute(now())); | ||||
|     // prepare frame to send for next minute
 | ||||
|     generateTimeframe(now() + 61); | ||||
|     // start blinking symbol on display and kick off timer
 | ||||
|     BitsPending = true; | ||||
|   } | ||||
| @ -146,16 +131,16 @@ void DCF_Out() { | ||||
| 
 | ||||
|     case 0: // start of second -> start of timeframe for logic signal
 | ||||
|       if (DCFtimeframe[bit] != dcf_off) | ||||
|         digitalWrite(HAS_DCF77, LOW); | ||||
|         set_DCF77_pin(dcf_low); | ||||
|       break; | ||||
| 
 | ||||
|     case 1: // 100ms after start of second -> end of timeframe for logic 0
 | ||||
|       if (DCFtimeframe[bit] == dcf_zero) | ||||
|         digitalWrite(HAS_DCF77, HIGH); | ||||
|         set_DCF77_pin(dcf_high); | ||||
|       break; | ||||
| 
 | ||||
|     case 2: // 200ms after start of second -> end of timeframe for logic 1
 | ||||
|       digitalWrite(HAS_DCF77, HIGH); | ||||
|       set_DCF77_pin(dcf_high); | ||||
|       break; | ||||
| 
 | ||||
|     case 9: // last pulse before next second starts
 | ||||
| @ -190,10 +175,46 @@ void dcf77_loop(void *pvParameters) { | ||||
|         NULL, | ||||
|         portMAX_DELAY); // wait forever (missing error handling here...)
 | ||||
| 
 | ||||
|     DCF_Out(); | ||||
|     DCF_Out(0); | ||||
|   } | ||||
|   BitsPending = false; // stop blink in display, should never be reached
 | ||||
|   vTaskDelete(DCF77Task); | ||||
| } // dcf77_loop()
 | ||||
| 
 | ||||
| // helper function to convert decimal to bcd digit
 | ||||
| uint8_t dec2bcd(uint8_t dec, uint8_t startpos, uint8_t endpos, | ||||
|                 uint8_t pArray[]) { | ||||
| 
 | ||||
|   uint8_t data = (dec < 10) ? dec : ((dec / 10) << 4) + (dec % 10); | ||||
|   uint8_t parity = 0; | ||||
| 
 | ||||
|   for (uint8_t n = startpos; n <= endpos; n++) { | ||||
|     pArray[n] = (data & 1) ? dcf_one : dcf_zero; | ||||
|     parity += (data & 1); | ||||
|     data >>= 1; | ||||
|   } | ||||
| 
 | ||||
|   return parity; | ||||
| } | ||||
| 
 | ||||
| // helper function to switch GPIO line with DCF77 signal
 | ||||
| void set_DCF77_pin(dcf_pinstate state) { | ||||
|   switch (state) { | ||||
|   case dcf_low: | ||||
| #ifdef DCF77_ACTIVE_LOW | ||||
|     digitalWrite(HAS_DCF77, HIGH); | ||||
| #else | ||||
|     digitalWrite(HAS_DCF77, LOW); | ||||
| #endif | ||||
|     break; | ||||
|   case dcf_high: | ||||
| #ifdef DCF77_ACTIVE_LOW | ||||
|     digitalWrite(HAS_DCF77, LOW); | ||||
| #else | ||||
|     digitalWrite(HAS_DCF77, HIGH); | ||||
| #endif | ||||
|     break; | ||||
|   } // switch
 | ||||
| } // DCF77_pulse
 | ||||
| 
 | ||||
| #endif // HAS_DCF77
 | ||||
| @ -56,7 +56,8 @@ | ||||
| #define HAS_IF482 9600, SERIAL_7E1, GPIO_NUM_12, GPIO_NUM_14 // IF482 serial port parameters
 | ||||
| 
 | ||||
| // Settings for DCF77 interface
 | ||||
| #define HAS_DCF77 GPIO_NUM_13 | ||||
| #define HAS_DCF77 GPIO_NUM_1 | ||||
| //#define DCF77_ACTIVE_LOW 1
 | ||||
| 
 | ||||
| // Pins for LORA chip SPI interface, reset line and interrupt lines
 | ||||
| #define LORA_SCK  (5)  | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user