Asistent

Osnove
mikroprocesorskih
sistemov


Računalniško
načrtovanje vezij II


Mikroprocesorji
v elektroniki
  Laboratorijske vaje
    Programiranje v zbirniku
Zbirniška funkcija
Zapis s plavajočo vejico
Digitalna ura
Generator vlaka
impulzov

Gonilnik
prikazovalnika LCD

Gonilnik asinhronih
zaporednih vrat

Uporaba operacijskega
sistema v realnem času

English

Realizacija digitalne ure z operacijskim sistemom v realnem času

Besedilo vaje: V danem preprostem operacijskem sistemu, ki teče v realnem času, sprogramirajte digitalno uro. Trenuten čas (ure:minute:sekunde) naj se izpisuje na prikazovalniku LCD. Za nastavljanje uporabite tipke T0 do T3. Pritisk na tipko T0 naj poveča število ur, na tipko T1 pa število minut. Tipka T2 naj uro ustavi, medtem ko tipka T3 postavi čas ni nič (00:00:00).

Razlaga: Program napišete v razvojnem okolju, ki teče na osebnem računalniku. Pripravljen delovni prostor (angl. workspace) z vsemi pripadajočimi datotekami najdete tukaj. V njem se poleg nastavitev projekta nahajajo tudi datoteke s spremljajočo izvorno kodo. Poleg že znanih datotek, sta dodani še datoteki rtos.c in pripadajoča rtos.h, kjer se nahaja koda preprostega operacijskega sistema, ki teče v realnem času.

Po končanem zagonu pristanemo v prazni funkciji start_up(), ki se nahaja v datoteki startup.c. Tu boste mikrokrmilnik inicializirali, kar naredite s klicem funkcije init(). Za njeno uporabo morate vključiti datoteko init.h. Nato boste s klicem funkcije sch_on() dvignili operacijski sistem, čemur bomo več besed namenili na koncu te razlage. Razlago delovanja in opis izvorne kode operacijskega sistema najdete v skripti.

Vajo bomo realizirali s pomočjo opravil, ki jih bo ob vnaprej določenih trenutkih klical mehanizem operacijskega sistema. Nalogo razdelimo na manjše dele. Za izvedbo digitalne ure moramo izmeriti, oziroma določiti trenuten čas, nato izmerjeno vrednost preoblikovati v primeren niz za prikaz in nazadnje pripravljen niz še prikazati na prikazovalniku LCD. Pri določanju trenutnega časa upoštevamo tudi pritisnjene tipke T0 do T3, ki služijo nastavljanju ure. Glede na povedano lahko nalogo naredimo s tremi opravili, ki jih poimenujmo:

   - tim() ... opravilo za nastavljanje in merjenje, oziroma štetje časa,
- string() ... opravilo, ki vrednost časa preoblikuje v niz za prikaz, in
- lcd_driver_1() ... opravilo, ki pripravljen niz prikaže na prikazovalniku LCD.

Opravilo tim() meri in nastavlja trenutni čas. Čas izrazimo z globalno spremenljivko time, ki podaja število sekund. Primer: ob 08:14:59 je time = 8 * 60 * 60 + 14 * 60 + 59 = 29699. Katerokoli drugo opravilo, ali glavni program lahko v vsakem trenutku "pogleda", koliko je ura. Da bo ura točna, mora biti opravilo tim() klicano v ekvidistantnih časovnih intervalih, za kar poskrbi operacijski sistem. Ker naše opravilo šteje sekunde, je najprimerneje, če je klicano enkrat na sekundo. Algoritem opravila tim() podaja slika spodaj.

Ob vsakem klicu (enkrat na sekundo) se vrednost spremenljivke time poveča za ena. Hkrati odčitamo stanje tipk T0 do T3, kar se ustrezno odrazi v vrednosti spremenljivke time. T0 poveča število ur, oziroma poveča time za 3600. Podobno T1 poveča število minut, oziroma poveča time za 60. Tipka T2 spremenljivko time zmanjša za ena, kar pomeni, da se njena vrednost pravzaprav ne spremeni. Čas stoji. Tipka T3 postavi time = 0. Opravilo tim() skrbi tudi za prehod opolnoči iz 23:59:59 (= 86399 sekund) na 00:00:00.

Naslednje opravilo string() prebere vrednost spremenljivke time in to pretvori v niz tipa "hh:mm:ss". Pravzaprav opravilo string() z dodajanjem presledkov pripravi 32-znakovni niz za prikaz na prikazovalniku LCD, na katerega kaže globalni kazalec lcd_string. Opravili tim() in string() sta med seboj neodvisni. Prvo skrbi, da je v spremenljivki time vedno pravi čas, drugo pa ta podatek uporablja. Algoritem opravila string() je enostaven in ga prikazuje slika spodaj. Število ur, minut in sekund dobimo iz spremenljivke time s celoštevilskim deljenjem in z deljenjem po modulu.

Zadnje opravilo, oziroma funkcijo za izpis na prikazovalnik LCD, lcd_driver_1() že poznamo iz laboratorijskih vaj pri predmetu Računalniško načrtovanje vezij II. Funkcijo sedaj uvrstimo med opravila. To pomeni, da je ne kličemo več eksplicitno, ampak za to poskrbi operacijski sistem. Funkcija tako predstavlja gonilnik za prikazovalnik LCD, ki nenehno prikazuje trenutno vsebino niza, na katerega kaže globalni kazalec lcd_string. Frekvenca osveževanja prikazovalnika je podana s pogostnostjo klicanja funkcije lcd_driver_1(), kar določimo z nastavitvami operacijskega sistema. Če hočemo spremeniti vsebino na prikazovalniku LCD, moramo le spremeniti niz, na katerega kaže kazalec lcd_string. To v naši vaji počne opravilo string().

Ker smo vse postorili s pomočjo opisanih treh opravil, je glavni program le prazna neskončna zanka.

V našem preprostem operacijskem sistemu so opravila funkcije, ki ne vzamejo nobenega argumenta in ničesar ne vračajo. Da takšna funkcija postane opravilo, jo moramo navesti v seznamu opravil sch_tab[], ki se nahaja v datoteki rtos_tasks.c. Ker se izvorna koda opravil ne nahaja v isti datoteki kot izvorna koda operacijskega sistema, potrebujemo za vsako opravilo še tako imenovano deklaracijo extern, ki se nahaja v datoteki rtos_tasks.h. Za opisana tri opravila tim(), string() in lcd_driver_1() bi seznam opravil sch_tab[] v datoteki rtos_tasks.c s pripadajočimi deklaracijami extern v datoteki rtos_tasks.h izgledal takole:

rtos_tasks.h:

 extern void tim();
 extern void string();
 extern void lcd_driver_1();

rtos_tasks.c:

 voidfuncptr sch_tab[] = {tim, string, lcd_driver_1};

Izvorno kodo opravil napišite v datoteki main.c.

Operacijski sistem dvignemo s klicem funkcije sch_on(), ki smo jo že omenili. Za uporabo funkcije morate vključiti datoteko rtos.h. Deklaracija funkcije sch_on() je naslednja:

  void sch_on(unsigned int slice);

Iz argumenta slice se izračunajo nastavitve časovnika timer0, ki ga operacijski sistem izkorišča za merjenje časa. Pomen argumenta je sledeč:

   - slice ... dolžina časovne rezine mikrosekundah

S klicem funkcije sch_on() postane operacijski sistem aktiven in prične s klicanjem opravil. Pogostnost klicev je podana z dolžino časovne rezine, ki smo jo določili z argumentom slice. V naši vaji imamo zaenkrat tri opravila, pri čemer zahtevamo, da je opravilo tim() klicano točno enkrat na sekundo. Temu primerno bi časovna rezina morala biti enaka 1/3 sekunde, kar pa ni cela številka (= 1000000/3us). Zato v seznam opravil sch_tab dodamo še prazno opravilo void_task(), ki je priloženo v datoteki main.c. Sedaj imamo štiri opravila, zato je dolžina časovne rezine enaka 1/4 sekunde (= 250000us).

In še v razmislek. Kaj bi morali narediti, da bi dvopičja v nizu "hh:mm:ss" utripala na vsake pol sekunde?