arduino/libraries/RTC_DCF/RealTimeClock_DCF.cpp

802 lines
22 KiB
C++

#include "RealTimeClock_DCF.h"
/**********************************************************
Konstruktor
**********************************************************/
#if RTC_DCF_COMMUNICATION == 0x00
RealTimeClock_DCF::RealTimeClock_DCF() : softSerial(2, 3)
{}
#else
RealTimeClock_DCF::RealTimeClock_DCF()
{}
#endif
/**********************************************************
öffentliche Methoden
**********************************************************/
/*---------------------------------------------------------
Name: begin
Beschreibung: initialisiert den gewählten Kommunikations-
weg
Eingänge: RTCCommunication_t rtcCommunication
Kommunikationsweg zum RTC-DCF
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::begin(void)
{
#if RTC_DCF_COMMUNICATION == 0x00
softSerial.begin(RTC_DCF_UART_BAUDRATE);
#endif
#if RTC_DCF_COMMUNICATION == 0x01
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV32);
SPI.setDataMode(SPI_MODE1);
#endif
#if RTC_DCF_COMMUNICATION == 0x02
Wire.begin();
#endif
}
/*---------------------------------------------------------
Name: setTime
Beschreibung: setzt die Uhrzeit des RTC-DCF
Eingänge: DateTime *dateTime
Struktur mit Datum und Uhrzeit, die im
RTC-DCF gesetzt werden soll.
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::setDateTime(DateTime *dateTime)
{
uint8_t dateTimeBCD[7];
dateTimeBCD[0] = decimalToBCD(dateTime->getSecond());
dateTimeBCD[1] = decimalToBCD(dateTime->getMinute());
dateTimeBCD[2] = decimalToBCD(dateTime->getHour());
dateTimeBCD[3] = decimalToBCD(dateTime->getWeekday() + 1);
dateTimeBCD[4] = decimalToBCD(dateTime->getDay());
dateTimeBCD[5] = decimalToBCD(dateTime->getMonth());
dateTimeBCD[6] = decimalToBCD(dateTime->getYear());
writeRegister(RTC_DCF_REG_SECOND, dateTimeBCD, 7);
}
/*---------------------------------------------------------
Name: getTime
Beschreibung: liest die Uhrzeit des RTC-DCF
Eingänge: DateTime *dateTime
Struktur mit Datum und Uhrzeit, in die Daten
aus dem RTC-DCF gespeichert werden
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::getDateTime(DateTime *dateTime)
{
uint8_t dateTimeBCD[7];
readRegister(RTC_DCF_REG_SECOND, 7, dateTimeBCD);
dateTime->setSecond(BCDToDecimal(dateTimeBCD[0]));
dateTime->setMinute(BCDToDecimal(dateTimeBCD[1]));
dateTime->setHour(BCDToDecimal(dateTimeBCD[2]));
dateTime->setWeekday(BCDToDecimal(dateTimeBCD[3]) - 1);
dateTime->setDay(BCDToDecimal(dateTimeBCD[4]));
dateTime->setMonth(BCDToDecimal(dateTimeBCD[5]));
dateTime->setYear(BCDToDecimal(dateTimeBCD[6]));
}
/*---------------------------------------------------------
Name: setAlarmTime
Beschreibung: setzt einen der beiden Alarmuhrzeiten im RTC-Chip
Eingänge: RTCAlarmWeekdays_t weekdays
Wochentage für den der Alarm gelten soll
mögliche Werte:
RTC_ALARM_WEEKDAYS_NONE,
RTC_ALARM_WEEKDAYS_MON,
RTC_ALARM_WEEKDAYS_TUE,
RTC_ALARM_WEEKDAYS_WED,
RTC_ALARM_WEEKDAYS_THU,
RTC_ALARM_WEEKDAYS_FRI,
RTC_ALARM_WEEKDAYS_SAT,
RTC_ALARM_WEEKDAYS_SUN,
RTC_ALARM_WEEKDAYS_MON_TO_FRI,
RTC_ALARM_WEEKDAYS_SAT_TO_SUN,
RTC_ALARM_WEEKDAYS_ALL
die Wochentage sind über das bitweise Oder (|)
verknüpfbar.
Beispiel: Für einen Alarm an den Wochentagen
Montag und Donnerstag wird der Funktion folgendes
übergeben:
(RTC_ALARM_WEEKDAYS_MON | RTC_ALARM_WEEKDAYS_THU)
uint8_t hour
Stunde zu der der Alarm auslösen soll
uint8_t minute
Minute zu der der Alarm auslösen soll
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::setAlarmTime(RTCAlarmWeekdays_t weekdays, uint8_t hour, uint8_t minute)
{
uint8_t alarmTimeBCD[] = { decimalToBCD(minute),
decimalToBCD(hour),
(uint8_t)weekdays };
writeRegister(RTC_DCF_REG_ALARM_MINUTE, alarmTimeBCD, 3);
}
/*---------------------------------------------------------
Name: getAlarmTime
Beschreibung: liest einen der beiden Alarmuhrzeiten aus dem RTC-Chip
Eingänge: RTCAlarmWeekdays_t *weekdays
ausgelesener Wochentag an dem Alarm aktiv ist
(Bitkodierung siehe setAlarmTime)
uint8_t *hour
ausgelesene Stunde des Alarms
uint8_t *minute
ausgelesene Minute des Alarms
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::getAlarmTime(RTCAlarmWeekdays_t *weekdays, uint8_t *hour, uint8_t *minute)
{
uint8_t alarmTimeBCD[3];
readRegister(RTC_DCF_REG_ALARM_MINUTE, 7, alarmTimeBCD);
*minute = BCDToDecimal(alarmTimeBCD[0]);
*hour = BCDToDecimal(alarmTimeBCD[1]);
*weekdays = (RTCAlarmWeekdays_t)alarmTimeBCD[2];
}
/*---------------------------------------------------------
Name: enableAlarmInterrupt
Beschreibung: aktiviert den eingestellten Alarm
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::enableAlarmInterrupt(void)
{
uint8_t alarmRegister;
readRegister(RTC_DCF_REG_ALARM_CONFIG, 1, &alarmRegister);
alarmRegister |= RTC_ALARM_CONFIG_REGISTER_AIE;
writeRegister(RTC_DCF_REG_ALARM_CONFIG, &alarmRegister, 1);
}
/*---------------------------------------------------------
Name: disableAlarmInterrupt
Beschreibung: deaktiviert den eingestellten Alarm
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::disableAlarmInterrupt(void)
{
uint8_t alarmRegister;
readRegister(RTC_DCF_REG_ALARM_CONFIG, 1, &alarmRegister);
alarmRegister &= ~RTC_ALARM_CONFIG_REGISTER_AIE;
writeRegister(RTC_DCF_REG_ALARM_CONFIG, &alarmRegister, 1);
}
/*---------------------------------------------------------
Name: resetAlarmInterrupt
Beschreibung: schaltet den Alarm wieder scharf
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::resetAlarmInterrupt(void)
{
uint8_t statusRegister = RTC_STATUS_AIF;
writeRegister(RTC_DCF_REG_STATUS, &statusRegister, 1);
}
/*---------------------------------------------------------
Name: enableAlarmLED
Beschreibung: aktiviert, dass die LED bei einem Alarm ein- bzw.
nach ausschalten des Alarms wieder ausgeschaltet
wird.
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::enableAlarmLED(void)
{
uint8_t alarmRegister;
readRegister(RTC_DCF_REG_ALARM_CONFIG, 1, &alarmRegister);
alarmRegister |= RTC_ALARM_CONFIG_REGISTER_AILED;
writeRegister(RTC_DCF_REG_ALARM_CONFIG, &alarmRegister, 1);
}
/*---------------------------------------------------------
Name: disableAlarmLED
Beschreibung: deaktiviert, dass die LED bei einem Alarm ein- bzw.
nach ausschalten des Alarms wieder ausgeschaltet
wird.
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::disableAlarmLED(void)
{
uint8_t alarmRegister;
readRegister(RTC_DCF_REG_ALARM_CONFIG, 1, &alarmRegister);
alarmRegister &= ~RTC_ALARM_CONFIG_REGISTER_AILED;
writeRegister(RTC_DCF_REG_ALARM_CONFIG, &alarmRegister, 1);
}
/*---------------------------------------------------------
Name: setPeriodicInterruptMode
Beschreibung: stellt den periodischen Interruptbetrieb ein
Eingänge: PeriodicInterruptSelection_t periodicInterruptSelection
Art des periodischen Betriebs:
RTC_PERIODIC_INT_PULSE_1_HZ
Pulsmodus mit 1 Hz
RTC_PERIODIC_INT_PULSE_2_HZ
Pulsmodus mit 2 Hz
RTC_PERIODIC_INT_LEVEL_EVERY_SECOND
Interrupt jede Sekunde (synchron mit Sekundenzähler)
RTC_PERIODIC_INT_LEVEL_EVERY_MINUTE
Interrupt jede Minute (bei Sekunde = 0)
RTC_PERIODIC_INT_LEVEL_EVERY_HOUR
Interrupt jede Stunde (bei Minute und Sekunde = 0)
RTC_PERIODIC_INT_LEVEL_EVERY_DAY
Interrupt jeden Tag (bei Stunde, Minute und Sekunde = 0)
RTC_PERIODIC_INT_LEVEL_EVERY_MONTH
Interrupt jeden Monat (jeweils am 1. um 0:00:00)
Hinweis:
Die Interrupts mit der Bezeichnung LEVEL werden
nicht automatisch zurückgesetzt, sondern müssen durch
den Aufruf der Methode resetPeriodicInterrupt wieder
scharf geschaltet werden.
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::setPeriodicInterruptMode(RTCPeriodicInterruptMode_t periodicInterruptMode)
{
uint8_t mode = (uint8_t)periodicInterruptMode;
writeRegister(RTC_DCF_REG_PERIODIC_INTERRUPT, &mode, 1);
}
/*---------------------------------------------------------
Name: enablePeriodicInterrupt
Beschreibung: aktiviert den eingestellten periodischen
Interrupt
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::enablePeriodicInterrupt(void)
{
uint8_t perIntRegister;
readRegister(RTC_DCF_REG_PER_INT_CONFIG, 1, &perIntRegister);
perIntRegister |= RTC_PER_INT_CONFIG_REGISTER_PIE;
writeRegister(RTC_DCF_REG_PER_INT_CONFIG, &perIntRegister, 1);
}
/*---------------------------------------------------------
Name: disablePeriodicInterrupt
Beschreibung: deaktiviert den eingestellten periodischen
Interrupt
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::disablePeriodicInterrupt(void)
{
uint8_t perIntRegister;
readRegister(RTC_DCF_REG_PER_INT_CONFIG, 1, &perIntRegister);
perIntRegister &= ~RTC_PER_INT_CONFIG_REGISTER_PIE;
writeRegister(RTC_DCF_REG_PER_INT_CONFIG, &perIntRegister, 1);
}
/*---------------------------------------------------------
Name: resetPeriodicInterrupt
Beschreibung: schaltet den periodischen Interrupt bei
Auswahl eines der Level-Modi wieder scharf
(siehe setPeriodicInterrupt)
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::resetPeriodicInterrupt(void)
{
uint8_t statusRegister = RTC_STATUS_PIF;
writeRegister(RTC_DCF_REG_STATUS, &statusRegister, 1);
}
/*---------------------------------------------------------
Name: enablePeriodicInterruptLED
Beschreibung: aktiviert, dass die LED bei einem periodischen Interrupt
ein- bzw. nach ausschalten des Interrupts wieder ausgeschaltet
wird.
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::enablePeriodicInterruptLED(void)
{
uint8_t perIntRegister;
readRegister(RTC_DCF_REG_PER_INT_CONFIG, 1, &perIntRegister);
perIntRegister |= RTC_PER_INT_CONFIG_REGISTER_PILED;
writeRegister(RTC_DCF_REG_PER_INT_CONFIG, &perIntRegister, 1);
}
/*---------------------------------------------------------
Name: disablePeriodicInterruptLED
Beschreibung: deaktiviert, dass die LED bei einem periodischen Interrupt
ein- bzw. nach ausschalten des Interrupts wieder ausgeschaltet
wird.
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::disablePeriodicInterruptLED(void)
{
uint8_t perIntRegister;
readRegister(RTC_DCF_REG_PER_INT_CONFIG, 1, &perIntRegister);
perIntRegister &= ~RTC_PER_INT_CONFIG_REGISTER_PILED;
writeRegister(RTC_DCF_REG_PER_INT_CONFIG, &perIntRegister, 1);
}
/*---------------------------------------------------------
Name: enableDCF77Reception
Beschreibung: aktiviert den DCF77-Empfang
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::enableDCF77Reception(void)
{
uint8_t dcf77Register;
readRegister(RTC_DCF_REG_DCF77_CONFIG, 1, &dcf77Register);
dcf77Register |= RTC_DCF77_CONFIG_REGISTER_DCFE;
writeRegister(RTC_DCF_REG_DCF77_CONFIG, &dcf77Register, 1);
}
/*---------------------------------------------------------
Name: disableDCF77Reception
Beschreibung: deaktiviert den DCF77-Empfang
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::disableDCF77Reception(void)
{
uint8_t dcf77Register;
readRegister(RTC_DCF_REG_DCF77_CONFIG, 1, &dcf77Register);
dcf77Register &= ~RTC_DCF77_CONFIG_REGISTER_DCFE;
writeRegister(RTC_DCF_REG_DCF77_CONFIG, &dcf77Register, 1);
}
/*---------------------------------------------------------
Name: enableDCF77Interrupt
Beschreibung: aktiviert den Interrupt bei DCF77-Empfang
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::enableDCF77Interrupt(void)
{
uint8_t dcf77Register;
readRegister(RTC_DCF_REG_DCF77_CONFIG, 1, &dcf77Register);
dcf77Register |= RTC_DCF77_CONFIG_REGISTER_DCFIE;
writeRegister(RTC_DCF_REG_DCF77_CONFIG, &dcf77Register, 1);
}
/*---------------------------------------------------------
Name: disableDCF77Interrupt
Beschreibung: deaktiviert den Interrupt bei DCF77-Empfang
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::disableDCF77Interrupt(void)
{
uint8_t dcf77Register;
readRegister(RTC_DCF_REG_DCF77_CONFIG, 1, &dcf77Register);
dcf77Register &= ~RTC_DCF77_CONFIG_REGISTER_DCFIE;
writeRegister(RTC_DCF_REG_DCF77_CONFIG, &dcf77Register, 1);
}
/*---------------------------------------------------------
Name: resetAlarmInterrupt
Beschreibung: schaltet den Interrupt bei DCF77-Empfang
wieder scharf
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::resetDCF77Interrupt(void)
{
uint8_t statusRegister = RTC_STATUS_DCFIF;
writeRegister(RTC_DCF_REG_STATUS, &statusRegister, 1);
}
/*---------------------------------------------------------
Name: enableDCF77LED
Beschreibung: aktiviert, dass die LED bei einem DCF77-Empfangs-Interrupt
ein- bzw. nach ausschalten des Interrupts wieder ausgeschaltet
wird.
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::enableDCF77LED(void)
{
uint8_t dcf77Register;
readRegister(RTC_DCF_REG_DCF77_CONFIG, 1, &dcf77Register);
dcf77Register |= RTC_DCF77_CONFIG_REGISTER_DCFLED;
writeRegister(RTC_DCF_REG_DCF77_CONFIG, &dcf77Register, 1);
}
/*---------------------------------------------------------
Name: disableDCF77LED
Beschreibung: deaktiviert, dass die LED bei einem DCF77-Empfangs-Interrupt
ein- bzw. nach ausschalten des Interrupts wieder ausgeschaltet
wird.
Eingänge: void
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::disableDCF77LED(void)
{
uint8_t dcf77Register;
readRegister(RTC_DCF_REG_DCF77_CONFIG, 1, &dcf77Register);
dcf77Register &= ~RTC_DCF77_CONFIG_REGISTER_DCFLED;
writeRegister(RTC_DCF_REG_DCF77_CONFIG, &dcf77Register, 1);
}
/**********************************************************
private Methoden
**********************************************************/
/*---------------------------------------------------------
Name: writeRegister
Beschreibung: schreibt eine vorgegebene Anzahl Register des
des RTC-DCF
Eingänge: unsigned char regAddress
Registeradresse ab der die Daten geschrieben
werden sollen
unsigned char *data
zu schreibende Daten
unsigned char datalength
Anzahl der zu schreibenden Daten
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::writeRegister(RTCRegister_t regAddress, uint8_t *data, uint8_t datalength)
{
#if RTC_DCF_COMMUNICATION == 0x00
/* start byte */
softSerial.write(0x02);
/* write direction */
softSerial.write((uint8_t)0x00);
/* start address */
softSerial.write(regAddress);
/* data */
while(datalength--)
{
/* use bytestuffing at data bytes equal to STX, ETX and DLE */
if( (*data == 0x02) ||
(*data == 0x03) ||
(*data == 0x10) )
{
softSerial.write(0x10);
softSerial.write(*data | 0x80);
}
else
{
softSerial.write(*data);
}
data++;
}
/* end byte */
softSerial.write(0x03);
#endif
#if RTC_DCF_COMMUNICATION == 0x01
digitalWrite(SPI_SLAVE_SELECT_PIN, LOW);
delayMicroseconds(50);
SPI.transfer(regAddress | SPI_BURST_WRITE);
while(datalength--)
{
delayMicroseconds(50);
SPI.transfer(*data);
data++;
}
digitalWrite(SPI_SLAVE_SELECT_PIN, HIGH);
delayMicroseconds(300);
#endif
#if RTC_DCF_COMMUNICATION == 0x02
Wire.beginTransmission(RTC_DCF_I2C_ADDRESS);
Wire.write(regAddress);
while(datalength--)
{
Wire.write(*data);
data++;
}
Wire.endTransmission();
#endif
}
/*---------------------------------------------------------
Name: readRegister
Beschreibung: liest eine vorgegebene Anzahl Register des
des RTC-DCF
Eingänge: unsigned char regAddress
Registeradresse ab der die Daten gelesen
werden sollen
unsigned char length
Anzahl der zu lesenden Daten
unsigned char *data
gelesene Daten
Ausgang: void
---------------------------------------------------------*/
void RealTimeClock_DCF::readRegister(RTCRegister_t regAddress, uint8_t length, uint8_t *data)
{
#if RTC_DCF_COMMUNICATION == 0x00
uint8_t receivedByte;
uint8_t nextByteStuffed;
/* start byte */
softSerial.write(0x02);
/* write direction */
softSerial.write(0x01);
/* start address */
softSerial.write(regAddress);
/* count of read register */
softSerial.write(length);
/* end byte */
softSerial.write(0x03);
/* wait for start byte of slave */
while(softSerial.read() != 0x02)
{}
/* receive data until length is reached */
while(length != 0)
{
/* wait until there are data to receive */
while(softSerial.available() == 0)
{}
receivedByte = softSerial.read();
/* check for stuffed bytes */
if(receivedByte == 0x10)
{
nextByteStuffed = 1;
}
else
{
if(nextByteStuffed == 1)
{
receivedByte &= 0x7f;
nextByteStuffed = 0;
}
*data = receivedByte;
data++;
length--;
}
}
#endif
#if RTC_DCF_COMMUNICATION == 0x01
digitalWrite(SPI_SLAVE_SELECT_PIN, LOW);
delayMicroseconds(50);
SPI.transfer(regAddress | SPI_BURST_READ);
while(length--)
{
delayMicroseconds(50);
*data = SPI.transfer(0xff);
data++;
}
digitalWrite(SPI_SLAVE_SELECT_PIN, HIGH);
delayMicroseconds(300);
#endif
#if RTC_DCF_COMMUNICATION == 0x02
// set the register pointer to the given position, but do not stop the communication
// after writing the pointer
Wire.beginTransmission(RTC_DCF_I2C_ADDRESS);
Wire.write(regAddress);
Wire.endTransmission(false);
// read out the given amount of data from the registers
Wire.requestFrom((uint8_t)RTC_DCF_I2C_ADDRESS, length);
while( Wire.available() )
{
*data = Wire.read();
data++;
}
#endif
}
/*---------------------------------------------------------
Name: decimalToBCD
Beschreibung: rechnet Dezimalwerte in das BCD-System um
(der RTC-DCF arbeitet intern mit BCD-Daten)
Eingänge: unsigned char decimal
umzurechnender Dezimalwert
Ausgang: unsigned char
BCD-Wert der übergebenen Dezimalzahl
---------------------------------------------------------*/
uint8_t RealTimeClock_DCF::decimalToBCD(uint8_t decimal)
{
return (((decimal / 10) << 4) | (decimal % 10));
}
/*---------------------------------------------------------
Name: BCDToDecimal
Beschreibung: rechnet BCD-Werte in das Dezimal-System um
(der RTC-DCF arbeitet intern mit BCD-Daten)
Eingänge: unsigned char bcd
umzurechnender BCD-Wert
Ausgang: unsigned char
Dezimalwert der übergebenen BCD-Zahl
---------------------------------------------------------*/
uint8_t RealTimeClock_DCF::BCDToDecimal(uint8_t bcd)
{
return (((((bcd)>>4) & 0x0F) * 10) + ((bcd) & 0x0F));
}
/**********************************************************
Vorinstantiiertes Objekt
**********************************************************/
RealTimeClock_DCF RTC_DCF = RealTimeClock_DCF();