K U R S Mikrokontrolery z rdzeniem ARM, część 22 Przetwarzanie C/A, biblioteka standardowa Przetworniki C/A są układami List. 14. Program do odgrywania ciągu próbek z pliku WAV #include lpc213x.h peryferyjnymi stosunkowo #include armint.h #include wav.h rzadko spotykanymi w typowych #define P025_DAC_SEL (2<<18) mikrokontrolerach. Producent #define TIMER0_VIC (1<<4) #define TIMER0_VIC_BIT 4 mikrokontrolerów LPC, począwszy #define VIC_IRQSLOT_EN (1<<5) od wersji LPC21x2, wyposażyli static int AdcPos = 0; je w jeden kanał konwersji //Przerwanie od Timera void IrqTimerHandler(void) __attribute__ ((interrupt( IRQ ))); C/A o rozdzielczości 10 bitów void IrqTimerHandler(void) z buforowanym wyjściem { //Zapis danych do DAC napięciowym. DACR = ((unsigned int)wav_file[AdcPos++])<<8; if(AdcPos>= wav_length) T0TCR = 0; //Kasuj zrodlo przerwania T0IR = T0IR_MR0; //Informacja dla VIC koniec procedury przerwania VICVectAddr = 0; } /* Funkcja glowna main */ int main(void) { PINSEL1 |= P025_DAC_SEL; //Preskaler wylaczony T0PR = 0; Przetwornik wbudowany w pre- //Gdy warunek spelniony zeruj Timer i zglaszaj przerwanie T0MCR |= T0MCR_Interrupt_on_MR0 | T0MCR_Reset_on_MR0; zentowane mikrokontrolery charak- //Przerwanie z częstotliwością 11khz T0MR0 = 2720; teryzuje się czasem przetwarzania //Zeruj licznik i preskaler rzędu 1 ms. Wyjściem przetworni- T0TCR = T0TCR_Counter_Reset; //Zalacz licznik T0 ka jest sygnał AOUT (P0.25), któ- T0TCR = T0TCR_Counter_Enable; ry może przyjąć wartości napięć //Wektor 0 VICVectAddr0 = (unsigned int)IrqTimerHandler; z zakresu 0& Vref. Przetwornik ten VICVectCntl0 = TIMER0_VIC_BIT | VIC_IRQSLOT_EN; może być wykorzystany do różno- //Zalaczenie przerwania VICIntEnable = TIMER0_VIC; rakich celów na przykład do gene- //Zalacz IRQ rowania sygnału audio, a sterowanie enable_irq(); return 0; nim jest naprawdę bardzo proste, } ponieważ sam przetwornik posiada tylko jeden rejestr. Zamiana warto- ści cyfrowej na analogową sprowa- BIAS Bit ten pozwala na wpisania wartości reprezentującej dza się do wpisania odpowiednich ustalenie prędkości pracy przetwor- napięcie do rejestru DACR. Jedyną wartości do tego rejestru. Rejestrem nika C/A, a co się z tym wiąże czynnością, o której musimy pamię- tym jest DACR (0xE006C000), któ- umożliwia określenie prądu pobie- tać to, ustawienie linii P0.25 por- rego wykaz bitów przedstawiono na ranego przez przetwornik. W przy- tu za pomocą rejestru PINSEL1, rys. 72. padku, gdy bit ten jest wyzerowa- tak, aby pełniła ona rolę wyjścia Funkcje jego poszczególnych bi- ny prąd pobierany przez przetwor- przetwornika C/A. Na zakończenie tów są następujące: nik wynosi około 700 mA, a czas kursu napiszemy program (dostęp- VALUE Zapisanie odpowiedniej przetwarzania przetwornika wynosi ny na CD EP9/2007B pod nazwą wartości na tych bitach powoduje 1 ms. W przypadku, gdy bit ten ep9c.zip), który wykorzystując prze- pojawienie się napięcia na wyjściu jest ustawiony, wówczas przetwor- twornik C/A, będzie odtwarzał plik AOUT, będącego odzwierciedleniem nik charakteryzuje się zmniejszo- dzwiękowy zawarty w wewnętrznej wartości tych bitów. Wartość na- nym poborem prądu do 350 mA, pamięci Flash, na głośniczku wbu- pięcia pojawiającego się na wyjściu ale równocześnie ulega zwiększe- dowanym w zestaw ZL6ARM. Plik AOUT możemy wyznaczyć według niu do 2,5 ms czas przetwarzania dzwiękowy został zapisany bezpo- wzoru: U =(VALUE/1023)*Vref przetwornika. średnio w pliku wav.c, w postaci out Używanie tego próbek dzwiękowych i został przy- & BIAS VALUE & & przetwornika A/C gotowany na podstawie zwykłego jest naprawdę bar- pliku w formacie wav z wykorzysta- 31 & 16 15 14 13 12 11 10 9 8 7 6 & 0 dzo proste i spro- niem narzędzi sox oraz awk, które Rys. 72. Rejestr DACR wadza się tylko do zawarte są w pakiecie Cygwin. Plik Elektronika Praktyczna 9/2007 101 K U R S Tab. 8. Skrócony opis funkcji w bibliotece stdio o jakimś prostym algorytmie umoż- Nazwa funkcji Opis liwiającym skompresowanie próbek dzwiękowych, co pozwoli na za- _ssize_t _read_r(struct _reent *r,int file, void funkcja odczytująca dane z pliku lub konsoli lub *ptr,size_t len) terminala oszczędzeniu dodatkowego miejsca _ssize_t _write_r (struct _reent *r,int file,const funkcja zapisująca dane do pliku lub konsoli lub w pamięci. Można również pliki void *ptr,size_t len) terminala dzwiękowe przechowywać w jakiejś int _close_r(struct _reent *r,int file) funkcja zamykająca plik dużej zewnętrznej pamięci takiej _off_t _lseek_r(struct _reent *r,int file,_off_t jak karta MMC, czy pamięć DATA funkcja określająca przesunięcie w pliku ptr,int dir) Flash. int _fstat_r(struct _reent *r,int file,struct stat funkcja zwracająca status pliku *st) Biblioteka standardowa (stdio) funkcja zwracająca czy otwarty plik jest termi- W prezentowanych przykładach int isatty(int file) nalem posługiwaliśmy się bezpośrednio funkcjami biblioteki standardowej dzwiękowy opiera się na zmien- merHandler(). W procedurze obsłu- , a dokładniej funkcją nej tablicowej wav_file[] zawiera- gi przerwania próbki przesuwane printf w celu wyświetlania komu- jącej próbki sygnału w formacie są na odpowiednią pozycję oraz nikatów tekstowych bezpośrednio 8 bitowym oraz wav_length okre- przesyłane do rejestru przetwornika na terminalu szeregowym. W przy- ślającej rozmiar próbek. Zmienne C/A. Dzieje się tak do momentu padku standardowych kompute- te zostały zadeklarowane ze sło- dopóki wszystkie próbki nie zosta- rów PC zadanie tej funkcji jest wem kluczowym const, przez co ną przesłane, natomiast po zakoń- oczywiste i polega na wyświetle- kompilator automatycznie traktując czeniu przesyłania ostatniej próbki niu ciągu znaków bezpośrednio na je jako dane stałe umieszcza je zatrzymywany jest układ czasowo monitorze komputera. W tym celu w obszarze pamięci Flash. Odtwa- licznikowy i cały proces odtwarza- funkcja printf wywołuje odpowied- rzanie pliku dzwiękowego sprowa- nia pliku dzwiękowego kończy się. nie funkcję systemu operacyjnego dza się do wysyłania poszczegól- Ponowne rozpoczęcie odtwarzania wyświetlające poszczególne znaki. nych próbek sygnału analogowego pliku dzwiękowego rozpocznie się W przypadku mikrokontrolerów nie do przetwornika C/A z częstotliwoś- po wciśnięciu przycisku zerującego mamy zdefiniowanego monitora cią 11 kHz. Fragment programu do mikrokontroler. Przedstawiony tu- ekranowego, jednak do tego celu odgrywania ciągu próbek za pomo- taj przykład miał pokazać jedynie można wykorzystać port szerego- cą przetwornika C/A przedstawiono możliwość odtwarzania prostych wy mikrokontrolera. Pisząc progra- na list. 14. plików dzwiękowych za pomocą my dla małych mikrokontrolerów Odtwarzanie pliku dzwiękowego przetwornika C/A, wykorzystano pracujemy bez obecności systemu rozpoczyna się od razu po wyze- tutaj bezpośrednie przechowywa- operacyjnego zapewniającego jedno- rowaniu mikrokontrolera, a po jego nie parametrów próbek w pamięci lity interfejs programowy, a każdy zakończeniu jest zatrzymywane, Flash. W rzeczywistym programie mikrokontroler posiada z reguły dlatego aby ponownie odsłuchać odtwarzającym warto pomyśleć, inny układ portu szeregowego, nie zawartość pliku należy nacisnąć przycisk zerowania mikrokontro- List. 15. Funkcja umozliwiająca zapis danych do terminala _ssize_t _write_r (struct _reent *r,int file,const void *ptr,size_t len) lera. Po wyzerowaniu rozpoczyna { się wykonywanie funkcji głównej int i; const unsigned char *p; (main), w której na początku usta- p = (const unsigned char*) ptr; wiana jest linia P0.25 tak, aby for (i = 0; i < len; i++) pełniła rolę wyjścia przetwornika { C/A. Przesyłanie pustych pró- if (*p == \n ) Uart0PutChar( \r ); Uart0PutChar(*p++); bek do przetwornika odbywa się } w przerwaniu od układu czasowo return len; } licznikowego T0, z wykorzystaniem układu porównującego MR0, dlate- go następną czynnością jest skon- List. 16. Funkcja umożliwiająca odczyt znaków z terminala i przekazywanie figurowanie układu porównującego ich do wyższych funkcji biblioteki stdio w taki sposób, aby zgłaszał prze- _ssize_t _read_r(struct _reent *r,int file, void *ptr,size_t len) { rwanie z częstotliwością 11 kHz. char c; int i; Następnie konfigurowany jest kon- unsigned char *p; troler przerwań VIC, tak, aby p = (unsigned char*)ptr; for (i = 0; i < len; i++) przerwanie od T0 powodowało { generowanie przerwania wektoryzo- c = Uart0GetChar(); if (c == 0x0D) wanego, a na koniec włączana jest { globalna flaga zezwoleń na prze- *p= \0 ; break; rwanie. Całą pracę polegającą na } *p++ = c; przesyłaniu poszczególnych próbek Uart0PutChar(c); sygnału z odpowiednią częstotliwoś- } return len i; cią do przetwornika C/A wykonuje } funkcja obsługi przerwania IrqTi- Elektronika Praktyczna 9/2007 102 K U R S funkcji biblioteki standardowej, na List. 17. Funkcja _close_r służąca do zamykania plików przykład na karcie pamięci MMC, int _close_r(struct _reent *r,int file) { wówczas wspomniane wcześniej return 0; funkcję należy znacząco rozbu- } dować, o dodatkowe mechanizmy. Konieczność zadeklarowania dodat- kowych niskopoziomowych funkcji List. 18. Funkcja _lseek_r umożliwiająca zmian ę pozycji w pliku zapewnia bibliotece uniwersalność _off_t _lseek_r(struct _reent *r,int file,_off_t ptr,int dir) { i niezależność od platformy syste- return (_off_t)0; /* Always indicate we are at file beginning. */ mowej i sprzętowej. } Zakończenie Podczas kursu zapoznaliśmy List. 19. Funkcja _fstat_r służąca do zwracania informacji o otwartym pliku się z możliwościami analogowymi int _fstat_r(struct _reent *r,int file,struct stat *st) { mikrokontrolerów LPC213x/214x, /* Always set as character device. */ które w sposób znaczący nie wy- st >st_mode = S_IFCHR; return 0; różniają się niczym szczególnym } na tle innych podobnych układów i należą do klasyki w tej klasie. i przekazywania do wyższych funk- Jednak rozdzielczość i dokładność List. 20. Funkcja wykrywająca ter- cji biblioteki. przetworników A/C wbudowanych minal Działanie tej funkcji sprowadza w mikrokontroler jest wystarczająca int isatty(int file) { się do pobierania poszczególnych dla większości popularnych apli- return 1; znaków z terminala do momentu kacji, i tylko w przypadku bardziej } napotkania znaku końca linii, a na- zaawansowanych aplikacji pomiaro- stępnie zwraca ona liczbę odczyta- wych użytkownik będzie zmuszony da się więc bezpośrednio przygo- nych bajtów. To są właśnie dwie do zastosowania innych mikrokon- tować uniwersalnej biblioteki stdio, główne funkcje, które odpowia- trolerów (na przykład ADCU7000 która pasowałaby do każdego mi- dają za współpracę z terminalem. również z rdzeniem ARM), lub krokontrolera. Aby umożliwić dzia- Oprócz tego musimy zdefiniować użycia zewnętrznych przetworni- łanie tej biblioteki musimy wraz kilka funkcji pomocniczych, które ków. Wbudowany w mikrokontroler z programem przygotować pewien nie będą nic robić oprócz zwra- przetwornik C/A, umożliwia prze- zestaw funkcji umożliwiających cania odpowiednich parametrów. twarzanie wielkości cyfrowych na wysyłanie i odbieranie znaków, któ- Funkcja _close_r (list. 17) służy do analogowe, co możemy wykorzy- re są zależne od typu mikrokontro- zamykania plików, a ponieważ my stać na przykład do odtwarzania lera. Dla zapewnienia minimalnej pracujemy tylko z terminalem i nie plików dzwiękowych. funkcjonalności musimy zapewnić można go zamknąć, dlatego funkcja To jest już ostatni odcinek tego interfejs do następujących funkcji zwraca wartość 0. Kolejną funkcją kursu. Mam nadzieję, że przed- niskopoziomowych: jest funkcja _lseek_r umożliwiająca stawione zagadnienia, informacje Funkcje te służą do wykony- zmianę pozycji w pliku, ponieważ i przykłady pozwoliły Czytelnikom wania operacji na plikach, gdzie terminal nie posiada żadnej pozy- zapoznać się z możliwościami mi- uchwyty do plików o wartości 0, cji, więc funkcja ta zwraca zawsze krokontrolerów LPC21xx. Cykl ten 1, 2 są w systemach operacyjnych wartość zerową bez wykonywania miał także pokazać, że mikrokon- szczególnymi plikami, czyli stan- żadnych czynności. trolery z rdzeniem ARM nie są dardowym wejściem i wyjściem. Funkcja _fstat_r (list. 19) służy takie straszne, a posługiwanie się Ponieważ w naszym przypadku nie do zwracania informacji o otwar- nimi wcale nie musi być dużo pracujemy pod kontrolą systemu tym pliku, w naszym przypadku trudniejsze od programowania operacyjnego i nie wykorzystujemy zawsze zwracamy informację, że 8 bitowych mikrokontrolerów na plików, funkcje te są bardzo proste jest to urządzenie znakowe, nato- przykład AVR ów. i sprowadzają się jedynie do wysy- miast funkcja isatty (list. 20) po- Niestety ograniczone łamy ni- łania i odbierania znaków z portu winna zwracać wartość prawda niejszego kursu nie pozwoliły na szeregowego. Do zapisywania da- w przypadku, gdy urządzenie jest przedstawienie wszystkich zagad- nych do terminala wykorzystywana terminalem, w naszym przypad- nień, ale na podstawie przedsta- jest funkcja _write_r, którą przed- ku również powinna zwracać ona wionych materiałów użytkownik stawiono na list. 15. wartość prawdziwą. we własnym zakresie będzie mógł Działanie tej funkcji sprowadza To już są wszystkie funkcje rozwinąć zagadnienia stosownie do się do wysłania wszystkich zna- niezbędne do tego, aby biblioteka swoich wymagań. W razie jakiś py- ków przekazanych do funkcji jako standardowa umożliwiała wyświet- tań wątpliwości oraz uwag na te- argument prosto do terminala za lanie i odbieranie znaków do ter- mat niniejszego kursu, czekam na pomocą funkcji Uart0PutChar(). Ko- minala za pomocą standardowych kontakt. lejną funkcją umożliwiającą współ- mechanizmów znanych z kompute- Lucjan Bryndza, EP pracę z terminalem jest funkcja rów PC. W przypadku, gdybyśmy lucjan.bryndza@ep.com.pl _read_r (list. 16), która służy do chcieli obsługiwać zapisywanie odczytywania znaków z terminala i odczytywanie plików za pomocą Elektronika Praktyczna 9/2007 103