Powrót

Mikroprocesorowa ośla łączka, część 17

Tworzenie oprogramowania dla mikrokontrolerów to sztuka łączenia kilku elementów. Jednym z nich jest znajomość języka. Drugi to umiejętność tworzenia algorytmów i rozwiązań. Równie istotnym jest aspekt czysto rzemieślniczy, jak posługiwanie się narzędziem.

Uważam, że nadszedł czas na pewne podsumowanie dotyczące samego języka programowania. W dotychczasowych częściach pewne szczegóły były przedstawione pobieżnie, niektóre odłożone na później. Są również takie, które nie wystąpiły, czas więc na uzupełnienia.

Dyrektywy kompilacji warunkowej

Przy tworzeniu programu, użycie każdego elementu musi być poprzedzone jego określeniem. Rzadko się zdarza, że program składa się z jednego pliku, a nawet w takiej sytuacji wykorzystywane są elementy biblioteczne. Filozofia języka C (jak i każdego innego) sprowadza się do ustalenia ścisłego znaczenia zaledwie kilku elementów – słów kluczowych, które mają określone znaczenie i nie można ich używać w innym zastosowaniu. Wszystkie pozostałe detale, takie jak funkcje, które występują w programie a nie są napisane naszą ręką to elementy biblioteczne (nikt nie będzie realizował działań pozwalających przykładowo obliczyć ex, tylko zastosuje istniejącą funkcję biblioteczną exp ( x)). Jednak aby z niej skorzystać kompilator musi wiedzieć, że takie coś istnieje i czym to coś jest. Z tego powodu w języku C istnieją pliki określane jako nagłówkowe (plik z rozszerzeniem .h), które zawierają jedynie zapowiedzi dodawanych elementów (w przypadku zmiennych oraz funkcji) lub definiują nowe typy zmiennych. Kompilując swój program (lub jego fragment) kompilator musi „przejść” przez definicję tych elementów. Najprościej jest poinformować go, by chwilowo „przeskoczył” do innego pliku, wczytał go i następnie powrócił do aktualnie kompilowanego.
Na taki ruch pozwala dyrektywa #include <nazwa pliku> (jeżeli dotyczy to stałych bibliotek) lub #include „nazwa pliku” (jeżeli jest to nasz plik – programista również może tworzyć własne pliki o charakterze bibliotecznym, realizujące jakieś często wykorzystywane działania). Nie ma ograniczenia, by dołączany plik (przez #include) nie zawierał dołączeń kolejnych plików. To wnosi możliwość wielokrotnego definiowania tego samego elementu. Aby temu przeciwdziałać, język C jest wyposażony w kompilacje warunkowe. Klasyczny przykład pokazuje listing 1 (zaczerpnięty z pliku zawierającego obsługę alfanumerycznych modułów LCD):

#ifndef _LCDModule_
#define _LCDModule_
#include ”lcdequip.h”
#endif

Mamy tu zastosowanie #ifndef symbol (jeżeli nie jest zdefiniowany symbol) i w przypadku braku jego definicji, kolejne zapisy są standardowo kompilowane. W przeciwnym wypadku wszystkie wiersze, aż do #endif, są pominięte. To nie wyczerpuje możliwości kompilacji warunkowych. Wariantem przeciwnym do powyższego jest #ifdef symbol. Tutaj warunek jest spełniony, jeżeli specyfikowany symbol jest zdefiniowany (przez #define). Kompilacje warunkowe można zastosować w dowolnym miejscu. Przydatne zastosowanie pokazuje listing 2:

static void HardwareInit ( void )
{
 TIMSK = ( 1 << TOIE0 ) ;
 TCCR0 = ( 1 << CS01 ) ;
 TCNT0 = 0 ;
#ifdef __AVR_ATmega8515__
 MCUCR = ( 1 << SRE ) | ( 1 << SRW10 ) | ( 1 << ISC01 ) ;
 GICR = ( 1 << INT0 ) ;
#else
 MCUCR = ( 1 << SRE ) | ( 1 << SRW ) | ( 1 << ISC01 ) ;
 GIMSK = ( 1 << INT0 ) ;
#endif
} /* HardwareInit */

Jest mikrokontroler AT90S8515 (obecnie już przestarzały), który ma możliwość przyłączenia zewnętrznej pamięci RAM lub w jej miejsce dowolnego kontrolera (przykładowo układu transmisji szeregowej 16C450, którego sygnał przerwania jest przyłączony do wejścia INT0). Wymaga to nadania określonej zawartości dla odpowiednich rejestrów, by aktywować obsługę zewnętrznej pamięci. Jego następca ATMEGA8515 również ma takie możliwości, ale konfigurowanie jej w szczegółach jest odmienne (inne bity i inne rejestry). Można stworzyć program, który zrealizuje to poprawnie w obu przypadkach, jak pokazuje listing 2. Przy tworzeniu projektu dla określonego mikrokontrolera specyfikowany jest jego model (przykładowo jak na rysunku 1). To automatycznie definiuje symbol określający zastosowany mikrokontroler, który można wykorzystać we własnym programie.

Rysunek 1

Powyższy przykład pochodzi ze środowiska AVR Studio – poprzednika oprogramowania narzędziowego Atmel Studio, który już nie wspiera mikrokontrolera AT90S8515, ale zasada pozostaje nadal ważna. (…)

——– ciach! ——–

To jest tylko fragment artykułu, którego pełna wersja ukazała się w październikowym numerze czasopisma Zrozumieć Elektronikę (ZE 10/2025). Pełną wersję czasopisma znajdziesz pod tym linkiem. Natomiast niepełna, okrojona wersja, pozwalająca zapoznać się z zawartością numeru ZE 10/2025 znajduje się tutaj.

Andrzej Pawluczuk
apawluczuk@vp.pl

 

Uwaga! Wskazówki, jak nabyć pełne wersje dowolnych numerów ZE znajdują się na stronie:
https://piotr-gorecki.pl/n11.