Nachdem mein "alter" Code nicht auf einem Pollin - ATmega32 - Board lief, habe ich diesen nun neu geschrieben ...
.. hier was fertiges inkl. Demoprogramm, Uhrzeit wird über Com1 ausgegeben.
Zur Info, hab noch Fehlerzähler implementiert ... und die Sekunden sind nun auch möglich. Uhrzeit dann fehlerfrei wenn Fehler == 0 && valid
Der Code ist absichtlich nicht auf Größe optimiert, verwendet also immer noch keine Bitfelder ... C für Beginners ist schon schwer genug, so bleibts lesbarer.
Viel Spaß beim Testen,
Vajk
Demo.c
Code:
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define __STDIO_FDEVOPEN_COMPAT_12 // fuer uart_putchar
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "basdef_h.h"
//-------------------------------------------------------
// Source-Modues
#include "dcf77_h.h"
//-------------------------------------------------------
// prototypes
static void avr_init(void);
// avrdude -P /dev/ttyS0 -p m32 -c ponyser -U f:w:demo2.hex:i -F
// ^^ avrdude-sequenz für Pollin Board, das über die serielle
// via avrdude programmiert wird, unter SIDUX / DEBIAN
// Quelle: http://www.mobile-roboter.org/content/view/13/43/
#define USEUART
//-------------------------------------------------------
byte flag_INT1 = 0;
byte old_std = 0;
byte old_min = 0;
byte old_sec = 0;
byte old_fehlcnt = 0;
byte old_rxdatafehl = 0;
#ifdef USEUART
// Gibt printf-daten auf die UART0 aus 9600 8 N1
// fdevopen(uart_putchar, NULL, 0); // 4 debugging -> use printf :-)
//-------------------------------------------------------
int uart_putchar(char c)
{
// if(c == '\n') uart_putchar('\r'); Zeilenvorschunb und Wagenrücklauf
loop_until_bit_is_set(UCSRA, UDRE);
UDR = c;
return 0;
}
#endif
//-------------------------------------------------------
int main(void)
{
avr_init();
#ifdef USEUART
fdevopen(uart_putchar, NULL, 0); // 4 debugging -> use printf :-)
printf("\nProgrammstart");
#endif
for(;;)
{
dcf_auswertung();
if(old_showdcf77sig != showdcf77sig)
{
old_showdcf77sig = showdcf77sig;
if(showdcf77sig)
PORTD |= (1 << PD5); // Licht an
else
PORTD &=~(1 << PD5); // Licht aus
}
if(DCF_time.valid) // sind die DCF - Daten überhaupt plausibel
{
if(DCF_time.valid_min && DCF_time.valid_std) // Stunden und Minuteninformation auch
{
// dann darf auch ausgewertet werden
// DCF_time.MESZ laß ich erstmal ausßen vor
// nur einmal ausgeben ...
if((DCF_time.std != old_std) || (DCF_time.min != old_min) || (DCF_time.sec != old_sec))
{
old_std = DCF_time.std;
old_min = DCF_time.min;
old_sec = DCF_time.sec;
#ifdef USEUART
printf("\n%02d:%02d:%02d %s", (int)DCF_time.std,
(int)DCF_time.min,
(int)DCF_time.sec,
DCF_time.MESZ ? "MESZ" : "MEZ");
if(DCF_time.valid_datum)
{
printf(" %02d.%02d.%04d", (int)DCF_time.tag, (int)DCF_time.mon, DCF_time.year);
}
// wota Mo=1 .. So=7 nicht berücksichtigt
if(DCF_time.fehlcnt || DCF_time.rxdatafehl)
printf(" Fehlbits: %02d / %02d", (int)DCF_time.fehlcnt, (int)DCF_time.rxdatafehl);
#endif
if((DCF_time.std >= 9) && (DCF_time.std <= 22))
PORTD |= (1 << PD6); // Licht an
else
PORTD &=~(1 << PD6); // Licht aus
}
}
}
#ifdef USEUART
else
{
if(DCF_time.fehlcnt || DCF_time.rxdatafehl)
{
if((DCF_time.fehlcnt != old_fehlcnt) || (DCF_time.rxdatafehl != old_rxdatafehl))
{
old_fehlcnt = DCF_time.fehlcnt;
old_rxdatafehl = DCF_time.rxdatafehl;
printf("\nFehlbits: %02d / %02d", (int)DCF_time.fehlcnt, (int)DCF_time.rxdatafehl);
}
}
}
#endif
if(flag_INT1 == 1)
{
flag_INT1 = 2; // durch diese "technik" ist beliebig lang Zeit, auf den Tastendruck zu reagieren
// ein einfaches ++ würde im Interrupt selbst stehen
#ifdef USEUART
printf("\n----- Taste2 ----- ");
// serielle Ausgabe dauert ja etwas .. 6 Byte = 48 Bit + 6 Bit = 5,6 ms bei 9600 BitspSec
#endif // außerdem ist die ser.Datenübertragung nicht synchron
flag_INT1 = 0;
}
}
return(0); // wird nie erreicht, da endlos for-schleife, aber weglassen führt zu compilerfehler
}
//-------------------------------------------------------
static void avr_init(void)
{
// Gedächtnisstütze :-) of 4 copy & paste
// DDRp [A,B,..] = Datenrichtungsregister Bit gesetzt = Ausgang, sonst Eingang
// PORTp = Datenregister Ausgänge setzen, wenn als Eingang definiert, dann int. Pullup mit 1 aktiviert
// PINp = Eingangsadresse - Abfrage der Eingänge
// Einzelne Bits mit (1 << x) mit x = [0..7]
// Port an mit PORTp |= (1 << x)
// Port aus mit PORTp &=~ (1 << x)
// first: alles als Eing�ge
DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0;
DDRB |= (1 << PB0) | (1 << PB1); // PB0,1 als Ausgänge
DDRD |= (1 << PD5) | (1 << PD6);
// Interrupts mega128: S. 87 mega32: S. 66
// INT0 = PD2
// DCF-INT0 Taster2 INT1
MCUCR = (1 << ISC00) | (1 << ISC11); // INT0 - DCF77, both edges
GICR = (1 << INT0) | (1 << INT1); // INT0 aktivieren
// Timer mega32: S. 80
// 8Bit - Timer bei 16 MHz
// für DCF overflowerkennung alle ~2,1ms
// 16 Mhz -> 2ms ist /1024 / 32
// also CTC0 und Teiler durch 1024
// TCCR0 = (1 << WGM01) | (1 << CS00) | (1 << CS02);
// OCR0 = 32;
// TIMSK |= (1 << OCIE0); // OutputCompareMatchInterrupt Enable TOIE0); // Timer Interrupt -> 8 Bit -> Overflow bei 256
// oder via Timer 2
// 1 / 16 Mhz * 256 * 128 = 2,048 ms
TCCR2 = (1 << CS22) | (1 << CS20);
TIMSK |= (1 << TOIE2);
dcf_Init();
// serielle Kommunikation aktiveren
#ifdef USEUART
// UCSRB |= (1 << RXEN) | (1 << RXCIE); // TXEN=TX an, RXEN=RX an, RXCIE=RXcomplete Int, TXCIE=TXdto.
UCSRB |= (1 << TXEN); // | (1 << TXCIE); // TXEN=TX an, RXEN=RX an, RXCIE=RXcomplete Int, TXCIE=TXdto.
UCSRC |= (1 << USBS) | (3 << UCSZ0); // asyncron 8N1
UBRRH = 0;
#define USART_BAUD_RATE 9600
#define USART_BAUD_SELECT (F_CPU/(USART_BAUD_RATE*16l)-1)
UBRRL = (unsigned char) USART_BAUD_SELECT;
// UBRRL = 51; // 103 fr 9600 || 51 fr 19200 || 25 fr 38400
// 16 fr 57,6k || 12 fr 76,8k || 8 fr 115,2k - alles bezogen auf 16 MHz
#endif
sei(); // enable interrupts -> Global enable interrupt
}
//-------------------------------------------------------
// // grmpf SIGNAL(SIG_OVERFLOW0) // derzeit mit Teiler 128 -> alle ~2,1ms
// SIGNAL(SIG_OUTPUT_COMPARE0)// Compare T=255 und Vort.256 -> alle 4,08 ms
SIGNAL(SIG_OVERFLOW2)
{
uint8_t tmp_sreg = SREG;
cli(); // Interrupts aus
dcf_timer_alle2ms048();
SREG = tmp_sreg; // besser als sei(); -> Interrupts an
}
//-------------------------------------------------------
SIGNAL(SIG_INTERRUPT0) // Impuls via DCF77
{
uint8_t tmp_sreg = SREG;
cli(); // Interrupts aus
dcf_interrupt();
SREG = tmp_sreg; // besser als sei(); -> Interrupts an
}
//-------------------------------------------------------
SIGNAL(SIG_INTERRUPT1) // Taster 2
{
if(!flag_INT1) // wenn semaphore noch nicht gesetzt
flag_INT1 = 1; // na dann setzen
}
dcf77.h
Code:
#ifndef _dcf77_h_
#define _dcf77_h_
#define INPORT_INT PIND
#define PIN_INT PD2
typedef struct
{
byte valid;
byte MESZ;
byte sec;
byte min;
byte valid_min;
byte std;
byte valid_std;
byte tag;
byte wota;
byte mon;
int year;
byte valid_datum;
byte fehlcnt;
byte rxdatafehl;
}DCF_TIME;
#ifdef __dcf77_h_intern_
byte dcf77modulaktiv = 0;
byte showsigdcf77aktiv = 0;
byte old_showdcf77sig = 255;
byte showdcf77sig = 0;
DCF_TIME DCF_time;
long lval_dcf_store;
void dcf_Init(void);
void dcf_timer_alle2ms048(void);
void dcf_interrupt(void);
void dcf_auswertung(void);
#else
extern byte dcf77modulaktiv;
extern byte showsigdcf77aktiv;
extern byte showdcf77sig;
extern byte old_showdcf77sig;
extern DCF_TIME DCF_time;
extern long lval_dcf_store;
extern void dcf_Init(void);
extern void dcf_timer_alle2ms048(void);
extern void dcf_interrupt(void);
extern void dcf_auswertung(void);
#endif
#endif
dcf77.c
Code:
#include <inttypes.h>
#include <avr/io.h>
//#include <avr/signal.h>
//#include <avr/interrupt.h>
//#include <avr/delay.h>
#include <stdio.h> // fr printf
//#include <stdlib.h>
#include <string.h>
//-------------------------------------------------------
#include "basdef_h.h"
#define __dcf77_h_intern_
#include "dcf77_h.h"
byte bitbuffer[60];
byte bitauswertung[60];
int flag_auswertung = -1; // auswertung läuft erst ab 0
int bitposition = 0;
int zeitzaehler = 0;
byte signalrx = 0;
byte datavalue = 0;
byte rxdatafehl = 0;
byte store_rxdatafehl = 0;
void dcf_Init(void)
{
lval_dcf_store = 0;
memset(&DCF_time, 0, sizeof(DCF_TIME));
}
void dcf_timer_alle2ms048(void) // alle 2.048ms
{
zeitzaehler++;
// zaehlwert zw. 50ms und 100 ms bei 2.048ms = 24 .. 48 --- gewaehlt 0x020 = ~ 65ms
// zaehlwert zw.100ms und 200 ms bei 2.048ms = 48 .. 96 --- gewaehlt 0x040 = ~ 131ms
// zaehlwert > 200ms bei 2.048ms = > 96 --- gewaehlt 0x064 = ~ 205ms
// zaehlwert ~ 1060ms bei 2.048ms = 520 --- gewaehlt 0x208 = ~1065ms
byte SigVal = INPORT_INT & (1 << PIN_INT); // INT - Port
if(zeitzaehler == 0x20) // also Abtastaung mitten im 0-Bit
{
if(SigVal) // hier muß immer ein Signal sein 1..58 sec-Datenzeitbereich
{
signalrx = 1;
datavalue = 1; // Logisch 0
}
else
rxdatafehl++;
}
if(zeitzaehler == 0x40) // also Abtastung mitten im 1-Bit-Datenzeitbereich
{
if(SigVal && signalrx)
datavalue = 2; // Logisch 1
}
if(zeitzaehler == 0x64) // also Abtastung nach dem Datenzeitbereich
{
if(!SigVal && signalrx && datavalue) // kein Signal mehr, empfang und dataval
{
if(bitposition < 59)
{
bitbuffer[bitposition] = datavalue;
bitposition++;
datavalue = 0;
signalrx = 0;
DCF_time.sec++;
DCF_time.sec = (DCF_time.sec < 60) ? DCF_time.sec : 60; // 60 nicht valid
}
}
}
if(zeitzaehler == 0x208) // wird nur erreicht, wenn 59 sec = leerübermittlung oder empfangsstörung
{
if(!SigVal) // kein Signal
{
store_rxdatafehl = rxdatafehl; // Empfangsfehlerzaehler
memcpy(bitauswertung, bitbuffer, 60); // Datenbereich uebertragen
flag_auswertung = 1; // Zeitsequenz empfangen - Auswertung freigeben
}
// Neustart des Puffer
memset(bitbuffer, 0, 60); // alle Felder ohne Empfangsinformation
bitposition = 0;
DCF_time.sec = 0;
rxdatafehl = 0;
}
// 8.4 sec kein Signal ... groesser muß der zaehler nicht werden, 0 abba auch nicht
zeitzaehler = (zeitzaehler > 0x1000) ? 0x1000 : zeitzaehler;
}
void dcf_interrupt(void) // via Interrupt beide Flanken
{
byte SigVal = INPORT_INT & (1 << PIN_INT); // INT - Port
if(SigVal) // also Beginn eines Datenbits
zeitzaehler = 0;
// für die Anzeige des DCF77-Signals
showdcf77sig = SigVal; // !showdcf77sig;
}
void dcf_auswertung()
{
if(flag_auswertung > 0)
{
int p, sum;
memset(&DCF_time, 0, sizeof(DCF_TIME));
DCF_time.rxdatafehl = store_rxdatafehl;
DCF_time.valid = 1;
DCF_time.fehlcnt = 0;
for(p = 20; p < 59; p++)
{
if(bitauswertung[p] == 0)
DCF_time.fehlcnt++;
}
if(DCF_time.valid && (bitauswertung[20] != 2)) // Startbit der Zeitinformation = immer Logisch 1
DCF_time.valid = 0; // Startbit fehlt
if(DCF_time.valid)
{
DCF_time.MESZ = ((bitauswertung[17] == 1) && (bitauswertung[18] == 0));
// 21-27: 7 Bits Minute 1,2,4,8,10,20,40
DCF_time.min = (bitauswertung[21] == 2) * 1 +
(bitauswertung[22] == 2) * 2 +
(bitauswertung[23] == 2) * 4 +
(bitauswertung[24] == 2) * 8 +
(bitauswertung[25] == 2) * 10 +
(bitauswertung[26] == 2) * 20 +
(bitauswertung[27] == 2) * 40;
// 28: 1 Bit Paritiy Minute - Bit 21-27
sum = 0;
for(p = 21; p <= 28; p++)
sum += (bitauswertung[p] == 2);
DCF_time.valid_min = !(sum % 2);
if(DCF_time.min > 59)
DCF_time.valid_min = 0;
// 29-34: 6 Bits Stunde 1,2,4,8,10,20
DCF_time.std = (bitauswertung[29] == 2) * 1 +
(bitauswertung[30] == 2) * 2 +
(bitauswertung[31] == 2) * 4 +
(bitauswertung[32] == 2) * 8 +
(bitauswertung[33] == 2) * 10 +
(bitauswertung[34] == 2) * 20;
// 35: 1 Bit Parity Stunde - Bit 29-34
sum = 0;
for(p = 29; p <= 35; p++)
sum += (bitauswertung[p] == 2);
DCF_time.valid_std = !(sum % 2);
if(DCF_time.std > 23)
DCF_time.valid_std = 0;
// 36-41: 6 Bits Tag 1,2,4,8,10,20
DCF_time.tag = (bitauswertung[36] == 2) * 1 +
(bitauswertung[37] == 2) * 2 +
(bitauswertung[38] == 2) * 4 +
(bitauswertung[39] == 2) * 8 +
(bitauswertung[40] == 2) * 10 +
(bitauswertung[41] == 2) * 20;
// 42-44: 3 Bits Wochentag 1,2,4 - 1=Mo .. 7=So
DCF_time.wota =(bitauswertung[42] == 2) * 1 +
(bitauswertung[43] == 2) * 2 +
(bitauswertung[44] == 2) * 4;
// 45-49: 5 Bits Monat 1,2,4,8,10
DCF_time.mon = (bitauswertung[45] == 2) * 1 +
(bitauswertung[46] == 2) * 2 +
(bitauswertung[47] == 2) * 4 +
(bitauswertung[48] == 2) * 8 +
(bitauswertung[49] == 2) * 10;
// 50-57: 8 Bits Jahr 2005+ 1,2,4,8,10,20,40,80
DCF_time.year = (bitauswertung[50] == 2) * 1 +
(bitauswertung[51] == 2) * 2 +
(bitauswertung[52] == 2) * 4 +
(bitauswertung[53] == 2) * 8 +
(bitauswertung[54] == 2) * 10 +
(bitauswertung[55] == 2) * 20 +
(bitauswertung[56] == 2) * 40 +
(bitauswertung[57] == 2) * 80 + 2000;
// 58: Paritiy Datum - Bit 35-57
sum = 0;
for(p = 36; p <= 58; p++)
sum += (bitauswertung[p] == 2);
DCF_time.valid_datum = !(sum % 2);
if((DCF_time.tag > 31) || (DCF_time.tag == 0) ||
(DCF_time.wota > 7) ||
(DCF_time.mon > 12) || (DCF_time.mon == 0))
{
DCF_time.valid_datum = 0;
}
/*
printf("\n%02d:%02d (%d/%d) - %02d.%02d.%04d (%d)", (int)DCF_time.std, (int)DCF_time.min, (int)DCF_time.valid_std,
(int)DCF_time.valid_min, (int)DCF_time.tag, (int)DCF_time.mon,
(int)DCF_time.year, (int)DCF_time.valid_datum);
23:44 (1/1) - 03.02.2006 (1)
*/
}
/*
else
{
printf("\n#");
for(int i = 0; i < 60; i++)
{
switch(bitauswertung[i])
{
case 1 : printf("0"); break;
case 2 : printf("1"); break;
default: printf("_"); break;
}
}
printf("#");
}
*/
flag_auswertung = 0;
}
}
Lesezeichen