PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : CCPRO M128: DCF77 Decoder 1 (CompactC)



Dirk
06.06.2009, 15:46
Hallo Besitzer der Zusatzplatine RP6 CCPRO M128,

die mitgelieferte Library DCF_Lib.cc hat gerade so die basalen Funktionen eines DCF-Decoders. Mit dieser Bibliothek RP6DCFCCLib.cc wird das besser. Viel Spaß damit.

Demo (DCF_RTC.cc):
/************************************************** *****************************
* RP6 C-Control PRO M128 Erweiterungsmodul
* ----------------------------------------------------------------------------
* DCF_RTC Demoprogramm 2
* ----------------------------------------------------------------------------
* DCF_RTC: DCF Uhr
* DCF Empfänger erforderlich
* Mega128: DCF-Eingang PE5 (PortE.5, RP6: INT1)
* Der DCF-Eingang kann in RP6DCFCClib.cc geändert werden.
* erforderliche Library: IntFunc_Lib.cc und neue RP6DCFCClib.cc (v. 1.xx).
*
* Über den zusätzlich erforderlichen DCF Empfänger (Art-Nr. 641138) wird
* das DCF Signal empfangen.
* Auf dem LCD-Display werden die Zeit und das Datum angezeigt.
* Die LED1 blinkt im Sekundentakt.
*
* Hinweis:
* Für allgemeine Programmierhinweise zur CCPRO schauen Sie sich bitte die
* CCPRO Dokumentation und die zugehörigen Beispielprogramme an!
* Es sei auch nochmals darauf hingewiesen, dass die normalen Beispielprogramme
* für die CCPRO nur zum Teil direkt auf dem RP6-CCPRO Modul laufen.
* Die Anschlussbelegung ist natürlich komplett anders als auf dem
* C-Control Application Board. Auch die LCD Ansteuerung ist leicht anders,
* da hier noch zusätzliche LEDs mit an dem Schieberegister angeschlossen sind.
* --> Die C-Control Beispielprogramme müssen ein klein wenig angepasst
* werden bevor sie auf diesem Modul laufen können!
*
* ************************************************** ***************************
* Der Roboter bewegt sich in diesem Beispielprogramm NICHT und kann
* am Rechner angeschlossen bleiben!
************************************************** ****************************/

// WICHTIG: Immer die RP6CCLib mit einbinden:
#include "../../RP6CCLib/RP6CCLib.cc"

// Die neue RP6DCFCCLib einbinden:
#include "../../RP6CCLib/RP6DCFCClib.cc"

int irqcnt; // globale Variablendeklaration
byte cnt1, alte_sekunde;

void main(void)
{
// WICHTIG! Immer als erstes aufrufen:
RP6_CCPRO_Init(); // Auf Startsignal warten, LCD und andere Dinge initialisieren !

// ------------------------------------------------------

// Zwei Zeilen Text mit dem LCD anzeigen:
showScreenLCD("RP6 CCPRO M128", "DCF RTC Demo 2!");

// Zweimal piepsen:
beep(200, 300, 100); // Format: beep (<tonhöhe>, <dauer>, <pause>)
beep(100, 100, 100);

// Text über serielle Schnittstelle ausgeben:
newline(); // Neue Zeile
println(" ________________________");
println(" \\| RP6 ROBOT SYSTEM |/");
println(" \\_-_-_-_-_-_-_-_-_-_/ ");
newline();
println(" Let's go! ");
newline();

// 2 Sekunden Pause:
AbsDelay(2000);

// ------------------------------------------------------
// DCF-Hauptprogramm:

Port_WriteBit(PORT_LED1, PORT_OFF); // LED1 aus
clearLCD(); // Display löschen

Time_Init(); // Funktionsaufruf zur Festlegung
// von Startzeit und Startdatum.

initDCF(); // Initialisierung des DCF Modus

Irq_SetVect(INT_TIM2COMP, INT_10ms); // ISR definieren
// Timer2: 10ms Interrupt
while (1) // Endlosschleife
{
if (cnt1 == 50) Port_WriteBit(PORT_LED1, PORT_OFF); // LED1 aus

if (cnt1 == 100) { // Sekundentakt
Port_WriteBit(PORT_LED1, PORT_ON); // LED1 an
cnt1 = 0;
}
if (alte_sekunde != Sekunde) {
alte_sekunde = Sekunde;
#ifndef DEBUG
showCLOCK();
// showSTATUS();
#endif
#ifdef DEBUG
showDEBUGINFO();
#endif
}
}
}

//------------------------------------------------------------------------------
// Festlegung von Startzeit und Startdatum
//
void Time_Init(void)
{
Sekunde = 0; // Uhr Startzeit: 12:00:00
Minute = 0;
Stunde = 12;
Wochentag = 7;
Tag = 31; // Uhr Startdatum: 31.05.2009
Monat = 5;
Jahr = 9;
}

//------------------------------------------------------------------------------
// Interrupt Routine
//
void INT_10ms(void)
{
cnt1++; // Zähler für Blinken der LED1

decodeDCF(); // DCF77 Decoder

irqcnt = Irq_GetCount(INT_TIM2COMP); // Interrupt Request Counter
}

//------------------------------------------------------------------------------

Bibliothek (RP6DCFCClib.cc), Teil 1:
/* ************************************************** **************************
* _______________________
* \| RP6 ROBOT SYSTEM |/
* \_-_-_-_-_-_-_-_-_-_/ >>> CCPRO M128
* ----------------------------------------------------------------------------
* ----------------------- [c]2009 - Dirk -------------------------------------
* ************************************************** **************************
* File: RP6DCFCClib.cc
* Version: 1.0 - CompactC
* Target: RP6 CCPRO M128 - C-Control PRO M128 @14.7456MHz
* mit optionalem LC-Display 16x2 Zeichen (CONRAD 190911)
* [oder OLED Textdisplay 16x2 Zeichen (CONRAD 197622)]
* und einem DCF77 Empfänger Modul (z.B. CONRAD 641138)
* Author(s): Dirk
* ************************************************** **************************
* Beschreibung:
* Dies ist meine DCF77 Bibliothek für die RP6 CCPRO M128.
* Der DCF-Empfänger wird an PE5 (XBUS INT1, SPI_I/O: Pin 7) der CCPRO M128
* angeschlossen.
*
* ANMERKUNG: Ein 10 kOhm Pulldown-Widerstand (R34) ist auf dem RP6 Mainboard
* mit E_INT1 verbunden und damit auch mit INT1 auf der CCPRO M128.
* Normalerweise haben DCF Empfänger einen open-collector Ausgang
* und benötigen einen PULLUP Widerstand zur korrekten Funktion.
* Der interne Pullup-Widerstand des ATMEGA128 kann den Pulldown-
* Widerstand auf dem RP6 Mainboard nicht kompensieren.
* Deshalb muss man einen PULLUP-Widerstand zwischen +5V und den
* DCF Empfängerausgang legen. Bei meinem DCF Empfänger klappt es
* gut mit einem 2,2 kOhm Widerstand.
*
* ************************************************** **************************
* CHANGELOG FINDEN SIE AM ENDE DIESER DATEI!
* ************************************************** **************************
*/

// Alles nur EINMAL einbinden!
#ifndef __RP6DCFCCLIB__
#define __RP6DCFCCLIB__


/************************************************** ****************************/
// Defines:

// RP6 CCPRO M128 DCF Empfänger Anschluß:
#define DCF_IN 37 // DCF Eingangs Signale an PortE.5 (RP6: INT1)
// #define DCF_IN 13 // DCF Eingangs Signal an PortB.5 (SERVO_1 PB5)

#define BIT_0 0x00 // 0b00000000
#define BIT_1 0x80 // 0b10000000
#define LETZTESBIT_0 0x40 // 0b01000000
#define LETZTESBIT_1 0xc0 // 0b11000000
#define BIT_FEHLER 0x01 // 0b00000001

/************************************************** ************/
// AUFBAU DES DCF77 TELEGRAMMS:
// Bit 0: DCF Bit 0 (immer 0)
// Bits 1..14: Codierte Wetter Infos (Meteo Time GmbH)
// Bits 15..20 (DCF Flags):
// Flag R: Ruf Bit 15 für PTB Angestellte
// Flag A1: Ankündigung eines Zeitzonenwechsels
// Flag Z1: Zeitzone 1 [0 = MEZ, 1 = MESZ] (Z1 != Z2)
// Flag Z2: Zeitzone 2 [1 = MEZ, 0 = MESZ] (Z2 != Z1)
// Flag A2: Ankündigung einer Schaltsekunde
// Flag S: Start Bit 20 (immer 1)
// Bits 21..27: Minute (BCD)
// Bit 28 [P1]: Minutenparität
// Bits 29..34: Stunde (BCD)
// Bit 35 [P2]: Stundenparität
// Bits 36..41: Tag (BCD)
// Bits 42..44: Wochentag
// Bits 45..49: Monat (BCD)
// Bits 50..57: Jahr (BCD)
// Bit 58 [P3]: Datumsparität
// [Bit 59: Schaltsekundenbit (immer 0)]
/************************************************** ************/

// #define DEBUG // Debug Modus
// Der Debug Modus dient zum Abgleich der Pausenlängen (PAUSE_xxxMS).
// Das LCD zeigt die vom Decoder erkannten Pausenlängen an. Wenn es
// eine deutliche Abweichung gibt, können die Pausenlängen angepaßt
// werden.

// #define REPARATUR // Reparatur Modus
// Im Reparatur Modus wird in dieser Programm Version nur eine Er-
// kennung von Spikes ermöglicht. Damit sinkt die Störanfälligkeit.
// In weiteren Programmversionen kann hier ggf. noch eine "echte"
// Reparatur von fehlerhaften DCF Telegrammen erfolgen.

// #define WETTER // Wetter Infos decodieren
// Wenn man die in den DCF Bits 1..14 enthaltenen Wetter Informationen
// einsehen möchte, muss man das Programm mit definiertem "WETTER"
// kompilieren. Da die Infos verschlüsselt sind, wird man in der Regel
// diese Bits nicht sinnvoll verwenden können.

#define UHRABGLEICH 100 // Uhr Abgleich (100 x 10ms = 1s)
// Mit "UHRABGLEICH" kann man die Ganggenauigkeit der Software-Uhr beein-
// flussen.

#define PAUSE_800MS 80 // Bit 1 Pausenlänge
#define PAUSE_900MS 90 // Bit 0 Pausenlänge
#define PAUSE_1800MS 180 // Letztes Bit 1 Pausenlänge
#define PAUSE_1900MS 190 // Letztes Bit 0 Pausenlänge
#define PAUSE_ABWEICHUNG 5 // Pausenlänge Abweichung
// Das DCF77 Telegramm wird in einer ganzen Minute für die Folgeminute
// übertragen. In jeder Sekunde wird ein DCF Bit codiert. Senderseitig
// wird dazu die Sendeleistung 100ms lang für ein 0-Bit oder 200ms lang
// für ein 1-Bit auf 25% abgesenkt. Danach ist für den Rest der Sekunde
// (900ms bzw. 800ms) Pause, also 100% Sendeleistung. Für einen DCF De-
// coder ist das Ende des Telegramms dadurch erkennbar, dass das letzte
// Bit (DCF Bit 58) eine Pause von 1900ms bzw. 1800ms besitzt. Damit
// können die o.g. 4 Pausendauern (PAUSE_XXXMS) unterschieden werden.
// Da der DCF Decoder alle 10ms aufgerufen wird, wird er etwa 80-mal den
// selben Pegel am Eingang feststellen, wenn die Pause nach einem 1-Bit
// gesendet wird.
// Durch "PAUSE_ABWEICHUNG" wird festgelegt, welche Abweichung vom Soll
// zugelassen wird. Beim Wert 5 erkennt der Decoder ein 1-Bit, wenn er
// zwischen 75- und 84-mal (= 750..840ms) den selben Pegel feststellt.

#define VALIDITAETSSTANDARD 1 // Validitätszähler Grenze
// (1: Jedes DCF Telegramm nutzen!)
// Als INTAKT gilt ein Telegramm, wenn folgende Bedingungen erfüllt sind:
// 1. DCF Bit 0 ist 0
// 2. DCF Bits 17 und 18 sind ungleich
// 3. DCF Bit 20 ist 1
// 4. Die Paritätsbits 28, 35, 58 enthalten eine korrekte gerade Parität
// 5. Es wurden genau 58 DCF Bits decodiert
// 6. Fall Schaltsekunde: DCF Bit 59 ist 0 und DCF Bit 19 ist 1
// Nicht PLAUSIBEL ist ein Telegramm, wenn Werte außerhalb des möglichen
// Bereichs liegen. Ein Wert von 9 für den Wochentag ist z.B. nicht
// plausibel. Allgemeiner könnte man sagen, dass ein DCF Telegramm nicht
// plausibel ist, wenn es nicht die Folgeminute der aktuellen Minute ab-
// bildet.
// Ein Telegramm ist VALIDE (= gültig), wenn es intakt UND plausibel ist.
// Jedes valide DCF Telegramm wird gezählt. Ist VALIDITAETSSTANDARD 1,
// dann wird jedes valide Telegramm zum Stellen der Uhr verwendet. Man
// kann den Wert erhöhen, wenn man ein Stellen der Uhr nur bei sehr guten
// Empfangsbedingungen erlauben will. Setzt man VALIDITAETSSTANDARD z.B.
// auf 3, dann wird ein Telegramm nur dann zum Stellen der Uhr verwendet,
// wenn es das dritte valide Telegramm in Folge ist.

/************************************************** ****************************/
// Variablen:

byte Jahr; // Jahr [0..99]
byte Monat; // Monat [1..12]
byte Wochentag; // Wochentag [1..7 = MO..SO]
byte Tag; // Tag [1..31]
byte Sommerzeit; // Zeitzone [0 / 1 = MEZ / MESZ]
byte Stunde; // Stunde [0..23]
byte Minute; // Minute [0..59]
byte Sekunde; // Sekunde [0..59]

#ifdef WETTER
unsigned int Wetter; // Codierte Wetter Informationen
#endif // (DCF Bits 1..14; Bit 0 immer 0)

byte dcfflags; // DCF Flags (DCF Bits 15..20):
#define FLAG_R 1 // R: Ruf Bit 15 für PTB Angestellte
#define FLAG_A1 2 // A1: Ankündigung eines Zeitzonenwechsels
#define FLAG_Z1 4 // Z1: Zeitzone 1 [0 = MEZ, 1 = MESZ]
#define FLAG_Z2 8 // Z2: Zeitzone 2 [1 = MEZ, 0 = MESZ]
#define FLAG_A2 16 // A2: Ankündigung einer Schaltsekunde
#define FLAG_S 32 // S: Start Bit 20 (immer 1)

byte dcfstatus; // Status Flags (Bits 0..5 nur lesen!):
#define STATUS_FEHLER 1 // Telegramm Fehler
#define STATUS_MINPARITAET 2 // Minutenparität ok
#define STATUS_STDPARITAET 4 // Stundenparität ok
#define STATUS_DATPARITAET 8 // Datumsparität ok
#define STATUS_DCFBIT58 16 // 58 (oder 59) DCF Bits decodiert
#define STATUS_TELEGRAMMINTAKT 32 // Telegramm intakt
#define STATUS_UHRGESTELLT 64 // Uhr einmal gestellt
#define STATUS_DCF_AN 128 // DCF77 Decoder AN

byte validitaetszaehler; // Zähler für intakte und
// plausible DCF Telegramme
byte validitaetsgrenze; // Grenze Validitäts Zähler

#ifdef DEBUG
byte pause_1_laenge;
byte pause_0_laenge;
byte letztepause_1_laenge;
byte letztepause_0_laenge;
#endif

/************************************************** ****************************/
// Funktionen:

/**
* INIT DCF
*
* Unbedingt einmal aufrufen, bevor die DCF77 Funktion benutzt wird!
*
*/
void initDCF(void)
{
Port_DataDirBit(DCF_IN, 0); // Port = Eingang
Port_WriteBit(DCF_IN, 1); // Pullup Widerstand ein
validitaetszaehler = 0; // Validitätszähler zurücksetzen
validitaetsgrenze = VALIDITAETSSTANDARD; // Grenze setzen
dcfstatus = STATUS_DCF_AN; // DCF77 Decoder AN
}

/**
* DCF DECODER AN
*
* Der DCF77 Decoder wird eingeschaltet.
* Immer wenn ein intaktes DCF Telegramm decodiert wurde, kann die
* Uhr mit den aktuellen DCF Informationen gestellt werden.
*
*/
void DCFon(void)
{
dcfstatus = dcfstatus | STATUS_DCF_AN; // Status Bit 7 setzen
}

/**
* DCF DECODER AUS
*
* Der DCF77 Decoder wird ausgeschaltet.
* Die Uhr wird durch die interne Referenz (Timer) betrieben.
*
*/
void DCFoff(void)
{
// Alle Status Bits löschen, nur Status Bit 6 bleibt unverändert:
dcfstatus = dcfstatus & STATUS_UHRGESTELLT;
}

/**
* BCD to DEC
*
* Diese Funktion wandelt einen BCD- in einen Dezimalwert um.
*
*/
byte BCDtoDEC(byte bcd)
{
return ((bcd >> 4) * 10 + (bcd & 0x0f));
}


Gruß Dirk

P.S.: Teil 2 der Bibliothek folgt!