Hier hab ich meine RTC Funktionen bzw die Statemachine.
Das ist die Komplette Schrittkette.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
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 erlaubenAuch habe ich hier ganz klar den Schwerpunkt auf Trennung der Anwendungslogik von der TWI logik getrennt. Wiederverwendung und Wartbarkeit!







Zitieren

Lesezeichen