Čeština / English
Login

Aplikace / Hodiny pomocí časovače

Autor: Josef Strnadel ()

Abstrakt: Ukázka implementace přesných hodiny reálného času (RTC, real-time clock) pomocí mikrokontroleru.

Update: 20090415

1. Popis aplikace

clock_app.png

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
}

2. Práce s časovačem

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.

3. Aktualizace času

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.

4. Zprovoznění aplikace

  1. přeložte aplikaci

  2. naprogramujte MCU a FPGA a spusťte terminálový program.

  3. 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.

Zobrazeno: 1795x Naposledy: 20.9.2017 15:43:58