Abstrakt: Ukázka implementace přesných hodiny reálného času (RTC, real-time clock) pomocí mikrokontroleru.
Aplikace demonstruje implementaci hodin reálného času (RTC, real-time clock) na platformě FITkit. Pro měření času je využit časovač pracující v režimu výstupní komparace. Čas na LCD je aktualizován v obsluze přerušení časovače. Aktualizace je prováděna s periodou 1 s a je signalizována změnou stavu LED D5. Výhodou použití časovače je, že CPU mikrokontroléru nemusí kvůli odměřování času aktivně čekat ve smyčce; měření času přenechá časovači a věnuje se jiným užitečným činnostem. Aplikaci je možno snadno doplnit o funkce kalendáře, organizéru, budíku či o funkce pro řízení událostí závislých na čase (zavlažování ve skleníku, řízení režimu činnosti nemovitosti atp.).
Principy související s řízením svitu D5 je možné nalézt např. v aplikaci Blikání LED pomocí časovače. Tento text bude věnován pouze implementaci RTC a aktualizaci času na LCD.
Po spuštění aplikace se na LCD objeví úvodní text, který tam zůstane až do okamžiku první aktualizace času vyvolané prvním přerušením od časovače. Od tohoto okamžiku bude s periodou 1 s jednak na LCD aktualizován čas ajednak bude docházet ke změně stavu D5.
Úvodní text se na LCD objeví hned po naprogramování FPGA. Zajistí to funkce
void fpga_initialized() { ... LCD_init(); // inicializuj LCD LCD_append_string("FITkit: clock"); // posli text na LCD LCD_send_cmd(LCD_DISPLAY_ON_OFF | LCD_DISPLAY_ON | LCD_CURSOR_OFF, 0); // zapni LCD, vypni kurzor }
Konfigurace časovače A0
Jelikož chceme vyvolávat přerušení s periodou 1 s
, bude nejvýhodnější zvolit za zdroj hodin časovače hodinový signál ACLK
, který má kmitočet 32768 Hz
:
TACTL = TASSEL_1 + MC_2; // ACLK (f_tiku = 32768 Hz = 0x8000 Hz), nepretrzity rezim
Aby bylo možné využít přerušení od časovače, je nutno nejprve povolit přerušení pro časovač:
CCTL0 = CCIE; // povol preruseni pro casovac (rezim vystupni komparace)
a nastavit, po kolika ticích (hodin ACLK s kmitočtem 32768 Hz) má být vyvoláno přerušení. Jelikož chceme vyvolat přerušení po uplynutí 1 s, pak necháme časovač čítat do hodnoty 32768
. Poté, co časovač dosáhne této hodnoty, uplyne právě 1 s:
CCR0 = 0x8000; // nastav po kolika ticich (32768 dekadicky = 0x8000 hexa, // tj. za 1 s) ma dojit k preruseni
Dále si ukážeme, jak je možné napsat obsluhu přerušení pro časovač a co bude v jejím těle.
Obsluha přerušení časovače A0
Napsat obsluhu přerušení pro časovač A0 znamená napsat tělo funkce interrupt (TIMERA0_VECTOR) Timer_A (void)
V případě naší aplikace by obsluha přerušení (vyvolávaná každou 1 s za účelem aktualizace času) časovače A0 mohla vypadat např. takto:
interrupt (TIMERA0_VECTOR) Timer_A (void) { P1OUT ^= 0x01; // invertuj bit P1.0 (kazdou 1/2 s) CCR0 += 0x8000; // nastav po kolika ticich (32768 = 0x8000, tj. za 1 s) ma dojit k dalsimu preruseni clk_s++; if(clk_s==60) { clk_m++; clk_s=0; } // kazdou 60. sekundu inkrementuj minuty if(clk_m==60) { clk_h++; clk_m=0; } // kazdou 60. minutu inkrementuj hodiny if(clk_h==24) // kazdych 24 hodin nuluj h,m,s { clk_h = clk_m = clk_s = 0; } flag_timer += 1; }
V těle obsluhy přerušení se nastaví příznak flag_timer
indikující, že nastalo přerušení. Tento příznak je dále testován v hlavní smyčče programu a způsobí aktualizaci LCD displeje. Aktualizace by sice mohla být v těle přerušení, ale tím bychom každou sekundu blokovali SPI kanál mezi MCU a FPGA a nebylo by možné např. naprogramovat FPGA apod.
Pro zobrazování času na LCD slouží funkce display_clock()
. Jejím úkolem je zobrazit na LCD čas ve formátu FITkit: HH:MM:SS
:
void display_clock() { LCD_send_cmd(LCD_SET_DDRAM_ADDR | LCD_SECOND_HALF_OFS, 0); // kurzor na druhou polovinu delay_ms(2); LCD_send_cmd((unsigned char)(clk_h / 10) + 48, 1); delay_ms(2); // zobraz hh LCD_send_cmd((unsigned char)(clk_h % 10) + 48, 1); delay_ms(2); LCD_send_cmd(0x3A, 1); delay_ms(2); // : LCD_send_cmd((unsigned char)(clk_m / 10) + 48, 1); delay_ms(2); // zobraz mm LCD_send_cmd((unsigned char)(clk_m % 10) + 48, 1); delay_ms(2); LCD_send_cmd(0x3A, 1); delay_ms(2); // : LCD_send_cmd((unsigned char)(clk_s / 10) + 48, 1); delay_ms(2); // zobraz ss LCD_send_cmd((unsigned char)(clk_s % 10) + 48, 1); delay_ms(2); }
Funkce je volána v hlavní programové smyčce:
int main(void) { flag_timer = 0; ... clk_h = 0; // inicializuj hodiny clk_m = 0; // inicializuj minuty clk_s = 0; // inicializuj sekundy while (1) { ... if (flag_timer > 0) { // doslo k aktualizaci casu casovacem? display_clock(); // zobraz aktualizovane hh:mm:ss flag_timer--; } } }
Kompletní zdrojové kódy je možné nalézt v souboru mcu/main.c.
přeložte aplikaci
naprogramujte MCU a FPGA a spusťte terminálový program.
Pomocí příkazu SET
zadaného v okně terminálu je možno změnit čas běžící v aplikaci, např.
SET 13:40:56
Aplikace nevyžaduje ke své činnosti nastavit kromě propojek umožňujících programování další propojky.