cz6

cz6



Programowanie

ABC... C

Funkcje statlc i inllne

Funkcja statyczna

Umieszczenie przed nazwą jiunkcji słowa kluczowego statlc powoduje utworzenie tak zwanej funkcji statycznej. Nie ma to wiele wspólnego z poznanymi już statycznymi zmiennymi lokalnymi. Tworząc funkcją statyczną, informujemy kompilator, że będziemy korzystać z niej tylko w bieżącym module - co praktycznie oznacza bieżący plik źródłowy. Informacja o danej funkcji nie zostanie umieszczona przez kompilator w pliku obiektowym (*.o), przez co linkier nie będzie miał do takiej funkcji dostępu. Sam kompilator uzyskuje za to możliwość lepszej optymalizacji kodu. W skrajnym przypadku, jeśli funkcja nie zostanie wykorzystana, nic znajdzie się ona w kodzie wynikowym programu (jednak zostanie w tym przypadku wygenerowane ostrzeżenie).

Funkcji static użyjemy wszędzie tam, gdzie pewnych elementów modułu nie chcemy udostępniać na zewnątrz. W naszym module wyświetlacza można by


zastosować to do wszystkich funkcji niskiego pozio-


Funkcju rozwijana w miejscu wywołania

Pod tą niezwykle brzmiącą nazwą kryje się mechanizm zbliżony do makr. Ma on jednak kilka zalet. Przede wszystkim, wygodniej się pisze funkcje niż makro. Drugą sprawą jest to, że kompilator może zbadać, czy bardziej optymalne jest rozwinięcie funkcji na wzór makra, czy też jej zwykłe wywołanie.

Dodatkowo jeśli tworzymy funkcję, kompilator pilnuje, czy nasze argumenty są prawidłowe i jeśli to konieczne, dokonuje przekształcenia ich typów. Zauważmy, że z jednej strony zmniejsza to możliwość popełnienia błędu, z drugiej jednak sprawia, że w niektórych zastosowaniach sprawdzają się tylko makra. Weźmy jako przykład makro obliczające ilość elementów w tablicy: #define ELEMS(p)\

(sizeof (p)/s1zeof (p[0])) Twór taki zupełnie nie ma sensu, jeśli p miałoby określony typ - tak jak ma to miejsce w funkcji. Nale


ży zdawać sobie sprawę także, że nawet tak banalne makro, jak obliczenie sumy dwóch argumentów: #define DODA](a, b) (a+b) zachowa się inaczej jako funkcja inlinc: makro operuje na argumentach o oryginalnych typach; Funkcja inline przekształci je najpierw do typu identycznego ze swoimi argumentami.

statlc inline - czemu?

Jeśli chcesz zastosować funkcję inline, spotka Cię jeszcze jedna niespodzianka. Kompilator musi założyć, że poza jej wykorzystaniem w bieżącym pliku, mogą pojawić się zewnętrzne do niej odwołania. Jeśli nie zaznaczysz funkcji inline jako statycznej, oprócz tego, że jej kod będzie rozwinięty w każdym miejscu wywołania, dodatkowo zostanie w pamięci utworzona jej „zwykła" wersja. W naszym przypadku byłoby to marnowanie zasobów - słówko static rozwiązuje ten problem.

Dzięki optymalizacji kodu, funkcja static inllne składająca się tylko z rozkazu powrotu (return) nic zostanie w ogóle umieszczona w kodzie.


Plik główny

Na tym etapie pracy mamy gotowe wszystkie potrzebne nam moduły. Pozostaje połączyć je w działający program. Ponieważ zależy nam na szybkim uruchomieniu programu, teraz wszystkie niezbędne funkcje wywołamy z poziomu funkcji main - tylko po to, aby wreszcie coś się zaczęło dziać. Utwórz plik main.c.


Listing 46 - plik main.c


#inc1ude <avr\io.h> #inc1ude <stdio.h> łlnclude <inttypes.h> #1nclude <avr\pgmspace.h>

łinclude „harddef.h,, ♦tnclude ..delay.h„ #include „makra.h„ #1nclude „12c.h„

#inctude „lcd.h,,


łnt main(void)


// Inicjacja

PORTO - 1«I2C_SDA 1 i«l2C_SCL; DORD = 1«I2C_SCL;

DDRB - 1«LCD_E | 1«LCD_RS | 0x0F«l_CD_D4; łcCLinitO;


II Koniec Inicjacji


// Tekst informacyjny w górnej li 1cd_str_PC(prog_char *)PSTR C „Dane z 10:,,)) i lcd_command(LCDC_DDA 1 64);


II bajt adresowy, i2c_send(Cx'K));

// bajt kontrolny

i2c_send{OxOO);

12c_stopO;


zapis


// Pobieranie danych

for(;;j

ł

lcd_command(LCDC_DDA | 64);

// Odczyt danych

i2c_start() i

// bajt adresowy, odczyt i2c_sendC0x9l);

// Pobranie i wyświetlenie danej lcd_dec(i 2c_getĆi2c_NACK));

// Przysłonięcie reszty napisu

1cd_str_PC(prog_char*)PSTR(,    „));

i2c_stopO;


return 0;


Powinien pojawić się listing 46. Większa część zawartego tutaj kodu powinna być już Ci znana. Nowością jest jedynie wysyłanie oraz odbiór danych z układu przetwornika. Na rysunkach 32 i 33 zamieściłem fragmenty wyjęte z dokumentacji firmy Philips. Pokazują one, jak powinna przebiegać komunikacja z naszym układem. Jak widać na rysunku 32, zgodnie z opisanymi wcześniej ramkami transmisji, po podaniu warunku start, konieczne jest zaadresowanie układu. Adres PCF8591 składa się z czterech starszych bitów ustawionych na stale (1001 b = 9h) oraz trzech młodszych, które możemy wybrać poprzez odpowiednie zwarcie wyprowadzeń adresowych. Płytka AVT3500 ustawia na stałe w tym miejscu 0. Najmłodszy bit słowa adresowego służy do ustalenia czy odbywa się zapis, czy odczyt. Przy zapisie, w pierwszej kolejności wysyłany jest bajt konfiguracyjny. Jego znaczenie pokazuje rysunek 33.

Przyjrzyjmy się programowi. Po starcie transmisji wysyłamy bajt 90h - adres układu, zapis. Następnie bajt konfiguracyjny (0) - wyłączone wyjście przetwornika CA, konfiguracja wejść na cztery niezależne obwody, wyłączone automatyczne przełączanie kanałów dla każdego odczytu, kanał 0.

W pętli głównej włączamy transmisję, pobieramy bajt danych i wyłączamy transmisję. Usunięcie z pętli warunku STOP nie


spowoduje błędnego działania układu. Później, gdy uda nam się skompilować program, spróbuj przenieść inicjację odczytu poza pętlę a w pętli pozostawić samą instrukcję odczytu danych. Zgodnie z rysunkiem 32 takie działanie jest możliwe.

Wyświetlanie danych wykorzystuje utworzoną dziś funkcję lcd_dec. Zauważ, że zaraz po niej wpisywane są dodatkowo dwie spacje. Poprawia to czytelność wyniku, jeśli wcześniej wyświetlana była liczba o większej ilości cyfr - w takim przypadku na wyświetlaczu pozostaną stare cyfry i trzeba je usunąć. Przedstawiony sposób jest najprostszym z możliwych i nie wszędzie może być zastosowany. Dobrze się spisuje jeśli nie zamierzamy pisać nic więcej w danej linii.

W pliku main.c napisaliśmy prościutki program, którego zadaniem jest wyświetlanie danej odpowiadającej napięciu podanemu na wejście 10 naszej płytki. Zanim przejdziemy dalej, podłącz na to wejście źródło regulowanego napięcia. Może być to zasilacz albo -najwygodniej - zwykły potencjometr (l-100k) z przeciwległymi wyprowadzeniami wpiętymi między masę i zasilanie a środkowym do wejścia 10.


“ t *“7"" ~ *

I oj. | ranom | .

| . 1 ». |

________

.....m.. 1-

Z7SS. tra:

I H —• , 11 *

»»•« I .

| Ru-17 Bur protoool for re«l

ode, A/O comofmton


Konfiguracja makefile

Gdybyś chciał skompilować teraz program, czeka Cię przykra niespodzianka - w tej chwili nic jest to jeszcze możliwe. Jeśli zmieniłeś, tak jak zwykle, pole TARGET pliku makefile, otrzymasz komunikat w stylu:

make.exe: *** No rule to make target PCF8591.o', neededby PCF8591.elf. Stop.


Rysunek 32 - sposób komunikacji z układem PCF8591 - według dokumentacji


Nic dziwnego - nie istnieje przecież plik PCF8591.c. Skompilowanie programu składającego się z

większej liczby plików wymagać będzie niewielkiej modyfikacji


Elektronika dla Wszystkich Grudzień2005 47


Wyszukiwarka

Podobne podstrony:
tablice java str4 Pola statyczne Pola statyczne deklarowane są przez umieszczenie przed typem pola s
23.2. Tl OLE I SIJLFIDYSiarkowe analogi alkoholi i eterów Przedrostek tio-. umieszczony przed nazwą
cz6 Programowanie dodawanie przed nazwą funkcji nazwy pliku oraz znaku podkreślenia. Mogą być to za
Resize of7 1    Wyjściowy obraz do programowania funkcji w wybranym systemie. 2
IMG?35 W architekturze podziały są konsekwencją: —    programu funkcjonalnego (użytko
142 jpeg I I Sterowanie programowe w funkcji przebiegu procesu sterowniczego: Warunki włączenia kro
HPIM1505 Program funkcjonalny domu mlrizkalnago opracowany Josf dla potrzeb 4•osobowej rodziny (rodz
HPIM1552 Przeznaczenie i program użytkowy budynku Program funkcjonalny domu opracowany jest cii-* po
HPIM1588 Przeznaczenie I program użytkowy budynku Program funkcjonalny domu opracowany jost dla potr
HPIM1608 Przeznaczenie i program użytkowy budynku Program funkcjonalny domu opracowany Jasi dla potr

więcej podobnych podstron