Hier hab ich meine RTC Funktionen bzw die Statemachine.
Code:
// -----------------------------------------------------
// RTC
// -----------------------------------------------------
#include "rtc.h"
#include "util.h"
#include "project.h"
#include "i2c.h"
extern avr::project sys;
extern avr::i2c twi;
extern bool check_twi(unsigned char& state);
namespace rtc {
unsigned char state = 0;
avr::util::timeout rtc_timeout;
bool
handle()
{
using namespace avr::util;
switch (state)
{
// step 0 to 9 are init. >= 10 are regular stuff
case 0:
// try to read from the rtc
twi.read_from_slave(avr::rtc_address,nullptr,0, 1);
state++;
return false;
case 1:
if (check_twi(state))
{
unsigned char i = 0;
while (twi.rx_size() > 0)
{
twi >> g_buffer[i];
++i;
}
// is the Clock Halt bit active?
if (g_buffer[0] & 0x80)
{
// bit is set. We need to enable the clock
sys.LED_141.toggle();
}
else
{
// bis is cleared. Clock is running
state = 4;
}
return true;
}
return false;
case 2:
// enable the clock
g_buffer[0] = 0x00;
g_buffer[1] = to_bcd(sys.dt.sec);
g_buffer[2] = to_bcd(sys.dt.min);
g_buffer[3] = to_bcd(sys.dt.hour);
g_buffer[4] = sys.dt.dow;
g_buffer[5] = to_bcd(sys.dt.day);
g_buffer[6] = to_bcd(sys.dt.month);
g_buffer[7] = to_bcd(sys.dt.year);
g_buffer[8] = 0;
twi.write_to_slave(avr::rtc_address, g_buffer, 8);
state++;
return false;
case 3:
return check_twi(state);
case 4:
// clock is running. poll it only every second
rtc_timeout.start(1000);
state++;
return true;
case 5:
if (rtc_timeout.elapsed())
{
if (sys.rtc_change_in_progress)
{
state = 10;
}
else
{
state++;
}
}
return true;
case 6:
// try to read from the rtc
g_buffer[0] = 0x00;
twi.read_from_slave(avr::rtc_address,g_buffer,1, 8);
state++;
return false;
case 7:
if (check_twi(state))
{
unsigned char i = 0;
while (twi.rx_size() > 0)
{
twi >> g_buffer[i];
++i;
}
if (i == 8)
{
sys.LED_142.toggle();
// update the sys variables from the RTC values
sys.dt.sec = from_bcd(g_buffer[0] & 0x7F);
sys.dt.min = from_bcd(g_buffer[1] & 0x7F);
sys.dt.hour = from_bcd(g_buffer[2] & 0x3F);
sys.dt.dow = g_buffer[3] & 0x07;
sys.dt.day = from_bcd(g_buffer[4] & 0x7F);
sys.dt.month = from_bcd(g_buffer[5] & 0x1F);
sys.dt.year = from_bcd(g_buffer[6] & 0xFF);
}
// jump back to timeout
state = 4;
return true;
}
break;
case 10:
// wait unti user is done
if (!sys.rtc_change_in_progress)
{
state = 2;
}
return true;
default:
break;
}
return true;
}
}; // namespace rtc
Das ist die Komplette Schrittkette.
0-> Init und Check ob die Uhr passt
2->5 Ist das setzen der Uhr
6-10: Ist das pollen der Uhr
Das ganze wird Zyklisch aus einem Scheduler aufgerufen.
EDIT: In meinem Fall läuft das alles in einem Timer IRQ. Damit kann ich Laufzeiten wie bei einer SPS garantieren. Ich darf mir aber keine Zeitscheibenverletzungen erlauben
Auch habe ich hier ganz klar den Schwerpunkt auf Trennung der Anwendungslogik von der TWI logik getrennt. Wiederverwendung und Wartbarkeit!
Lesezeichen