C suli 3 - Első program, pogram fordítás, LED villogtatás

2016-10-27

 

Készítsünk egy egyszerű kapcsolást és programot, ami végtelen ciklusban fél másodpercre bekapcsol egy LED-et, majd fél másodpercre kikapcsolja. Minnél egyszerűbb valami, annál kevesebb hibát tudunk beleépíteni. Egyszerűsége ellenére kiinduló pontja lehet a legtöbb munkánknak, mert lehetővé teszi, hogy szemrevételezéssel meggyőződjünk az áramkörünk működőképességéről. Megszámolhatjuk, hogy a LED hányat villan egy perc alatt, így ellenőrizhetjük, hogy helyesen állítottuk-e be a sebességet? Íme az áramkör:

A bal oldalon vannak azok a lábak, amelyeket a programozó fejhez kell csatlakoztatni. Alul és felül vannak a táp lábak. Jobbra látható a LED, amit majd be/ki fogunk kapcsolgatni. A LED akkor fog világítani, ha a PB0 lábon 0 lesz.

Emlékeztetőül az ATmega8 bekötése:

Ez pedig a programunk:


/*
   
   c_suli_3_1.c
   C suli - Elso program - LED villogtatasa 1Hz-cel 

*/


#define F_CPU  4 MHZ


#include "tkiraaly_atmega8.h"
#include <util/delay.h>


int main( void)
{
   PB0_OUTPUT;                         // LED lab legyen kimenet
   for(;;)                             // vegtelen ciklus
   {
      PB0_0;                           // LED lab legyen 0, vilagit
      _delay_ms( 500);                 // fel masodperc varakozas
      PB0_1;                           // LED lab legyen 1, nem vilagit
      _delay_ms( 500);
   }
}

Azt látjuk, hogy az C suli 1-ből megszerzett tudásunkkal ezt a programot nemigen értjük. Ne vessétek a szememre, hogy azt írtam, a C nyelvet 10-20 kulcsszóval le lehet fedni, mert azt is írtam, hogy a C nagyon rugalmasan bővíthető. Szép sorban nézzük meg, minek mi az értelme?

A programba írhatunk magyarázatokat, hogy mások is megértsék mit csináltunk, de néhány hónap múlva már saját magunknak is jól jön. Egyik lehetőség,
a "/* Magyarázat */", így több soros szöveget is beírhatunk. A másik lehetőség "// Magyarázat", amit a sor végére biggyeszthetünk.


#define F_CPU  4 MHZ

Ez arról szól, hogy megadjuk a uC órajelének a frekvenciáját, ezt az értéket sok előre elkészített progam modul használja.


#include "tkiraaly_atmega8.h"

Ez egy általam előre megírt modul, ami megkönnyíti a munkát, majd később érdemes lesz belenézni. Egész pontosan azt mondja, hogy ide be kell szúrni a "tkiraaly_atmega8.h" file szövegét.


#include <util/delay.h>

Ez megint egy előre megírt modul beszúrása, de látjuk, hogy különbözik az előző utasítástól. Ez azért van, mert az előző file-t a programunk mappájában kell keresni, ez a modul meg a C fordító programunk tartozéka és az ott rendszeresített helyen lehet megtalálni.


int main( void) {}

C-ben a programunkat kisebb önállóan is működöképes mini programokra bontjuk, úgynevezett függvényekre. Egy C függvény hasonlít a matematikai függvényekre, átadhatunk neki változó(ka)t, majd a függvény az által kiszámolt értéket adja vissza. Magát a programunkat a kötelezően "main()" nevü függvény valósítja meg ( magyarul fő). A main() kötelezően "int" típusú, ami azt jelenti, hogy a függvény egy int (16 bites) számot ad vissza. A "( void)" (magyarul üres) részből látszik, hogy a main()-nek nem adunk át paramétert. Később lesz olyan függvényünk is, aminek átadunk paramétert. A "{ }" kapcsos zárójelek között soroljuk fel azokat az utasításokat, amikből a main() áll.


   PB0_OUTPUT;

Ez egy általam előre megírt program részlet, ami PB0 lábat kimenetre állítja. Később még részletesen meg fogjuk ezt nézni.


   for(;;) { }

Végre valami ismerős! Ezt láttuk a C suli 1-ben. Ez egy olyan ciklus, aminek a törzsét, vagyis a "{ }" közé zárt utasításokat a vég nélkül fogja a uC ismételgetni.


   PB0_0;

Ez megint én követtem el, ez a program részlet a PB0 lábat 0-ba állítja. Ilyenkor a LED világítani fog.


    _delay_ms( 500);

Ez a "delay.h"-ban van leprogramozva. Ez egy 500 milisecundum, azaz fél másodpercig tartó mini program. Az utasításaink feldolgozása a mini program lefutását követően folytatódnak. Fontos, hogy a uC orajele helyesen legyen megadva, mert ez a modul az F_CPU figyelembe vételével fut.


   PB0_1;

Mint fent, csak értelemszerűen a PB0 lábat 1-ba állítja. Ilyenkor a LED nem fog világítani

A programozási nyelvek két csoportba sorolhatók, az interpreterekre, és a compilerekre. Az interpreter értelmezőt jelent, úgy működik, hogy a program sorainkat egyenként értelmezi és végrehajta. Tehát futtatás közben az interpreter programnak, és a forrásprogramnak is bent kell lennie a gépben. A compiler az egész programunkat egyszerre lefordítja, és csak a lefordított gépi kódú programot töltjük be a gépbe. A C compiler. A valóságban a C programunk több lépésben kerül lefordításra, ami nagyfokú rugalmasságot és modularitást biztosít. Ezt talán majd akkor lehet megismerni/belátni, amikor az ember már nem ilyen egyszerű kis példaprogramokat ír, hanem talán egy csoport feladatának egy modulját dolgozza ki. Nekünk most fontos, hogy első lépésben a preprocesszor (előfeldolgozó) próbálja megemészteni a kódunkat. A "#" - heshmark-kal kezdődő sorok szólnak a preprocesszornak, itt csak kétféle található. A "#define" utasítással egy kifejezés párt adunk meg a preprocesszornak, úgy működik, mint egy keress/cserél utasítás a szövegszerkesztőben. A "#include" azt jelenti, hogy a programunk szövegébe szúrja be a megadott file-t. A preprocesszor által előkészített kód több lépésben kerül fordításra, ez látszik a munka közben generált file-okból is. Nekünk a végeredmény a fontos, aminek .hex lesz a neve (Intel HEX formátumú állomány), ezt az égető programmal tudjuk a uC-be betölteni. Most, amikor mindenkinek elment a kedve az egésztől, elmondom, hogy a C programunkat kvázi egy utasítással fogjuk lefordítani, a "fordit.bat"-tal (batch - parancs köteg). Itt látható a tartalma:


avr-gcc -g -Wall -O2 -mmcu=atmega8 -c -o prg.o prg.c
avr-gcc -g -O2 -mmcu=atmega8 -Wl,-Map,prg.map -o prg.elf prg.o
avr-objdump -h -S prg.elf > prg.lst
avr-objcopy -j .text -j .data -O ihex prg.elf prg.hex
avr-size --format=avr --mcu=atmega8 prg.elf

A a GNU C fordító AVR-re (Atmel uC-k) adaptált változatát használjuk. Azért választottam ezt, mert ingyenes, korlátozások nélkül használható. Inkább ne kérdezzétek ez a sok parancssori kapcsoló, kutyafüle mit jelent. Egyszer beleástam magam, de azóta sokat felejtettem. Akit érdekel, vagy szüksége van rá, a doksik a neten elérhetők. A lefordítani kívánt programot át szoktam nevezni "prg.c"-re, így nem kell a batch file-t piszkálnom.