Instrukcja do ćwiczeń SYSTEMY WBUDOWANE Lab. 3 Przetwornik ADC + potencjometr
1. Należy wejść na stronę Olimexu w celu znalezienia zestawu uruchomieniowego SAM7-EX256 (https://www.olimex.com/products/arm/atmel/sam7-ex256/). 2. Pobrać dokumentację ze strony Olimexu: SAM7-EX256 User Manual 3. Na podstawie instrukcji obsługi należy dowiedzieć się, jakie rejestry obsługują potencjometr zestaw AT91SAM7X256 posiada wbudowany konwerter sygnałów analogowych na cyfrowe (ADC - Analog to Digital Converter). Potencjometr (trim) jest obsługiwany przez konwerter w rejestrze AD6. 4. Należy utworzyć nowy projekt w środowisku CrossWorks. 5. Do obsługi konwertera ADC, potrzebne są odpowiednie pliki, które należy uwzględnić w utworzonym projekcie ("adc.h" i "adc.c"). 6. W pliku main.c należy dołączyć potrzebne biblioteki: #include <targets/at91sam7.h> #include"adc.h" W głównej części programu należy włączyć obsługę konwertera ADC poprzez wywołanie funkcji: InitADC(); 7. Potencjometr TRIM należy ustawić w pozycji maksymalnej (do oporu zgodnie z ruchem wskazówek zegara) oraz włączyć tryb debugowania:
8. Następnie w grupach rejestrów należy włączyć ADC (tryb ON ): 9. Należy uruchomić tryb debugowania, po czym zatrzymać:
10. W oknie rejestrów podświetliły się na czerwono rejestry, których zawartość uległa zmodyfikowaniu. Należy pamietać, że potencjometr jest obsługiwany przez AD6, wobec czego należy sprawdzić jego wartość: 11. Wiadomo teraz, jaką wartość przyjmuje rejestr ADC_CDR6, jeżeli potencjometr ustawiony jest na wartość maksymalną (gałka potencjometru ustawiona w pozycji możliwie maksymalnej zgodnie z ruchem wskazówek zegara) należy zapisać podaną wartość rejestru. 12. Następnie należy ustawić potencjometr na wartość minimalną (gałka potencjometru ustawiona w pozycji możliwie minimalnej odwrotnie do ruchu wskazówek zegara). Ponownie należy uruchomić i zatrzymać wykonywanie programu w trybie debugowania, odczytać i zapisać podaną wartość rejestru:
13. Gdy już wiadomo na jakim rejestrze pracuje potencjometr oraz jak sprawdzić jego wartość, można przystąpić do oprogramowania ADC. Poniżej zostanie przedstawiony prosty przykład jak można wskazać wartość rejestru na ekranie oraz graficzne przedstawić pozycję potencjometru. 14. W tym celu potrzebne są biblioteki do obsługi ekranu należy użyć plików z poprzednich zajęć, ponieważ ze strony Olimexu są wybrakowane "lcd.c", "lcd.h", "bmp.h", "bits.h", "lcd_font.h". 15. W poniższym przykładzie obsługi potencjometru podczas przekręcania go ładują się gwiazdki na pozycji minimalnej nie wyświetla nic, po przekroczeniu 10% pokazuje się jedna gwiazdka, 20% dwie itd. aż do pozycji maksymalnej. Wówczas na ekranie pojawia się 10 gwiazdek. Przy każdym pojawieniu się (bądź zniknięciu) gwiazdki z głośnika wydobywa się pyknięcie. Zaimplementowana jest również obsługa przerwań po naciśnięciu lewego przycisku pokazuje się aktualna wartość rejestru w wartościach dziesiętnych, ponowne naciśnięcie lewego przycisku aktualizuje wartość, natomiast prawy przycisk czyści wskazanie. Poniżej listing programu: #include <targets/at91sam7.h> #include"adc.h" #include"lcd.h" #define AUDIO_OUT PIOB_SODR_P19 // #define SW_1 PIOB_SODR_P24 // lewy przycisk #define SW_2 PIOB_SODR_P25 // prawy przycisk attribute ((section(".fast"))); // konfiguracja delay void delay(int n){ volatile int i; for(i=3000*n; i>0; i--){ asm ("nop"); int main() { PMC_PCER = PMC_PCER_PIOB; // włączenie obsługi przerwań PIOB_OER = AUDIO_OUT; PIOB_PER = AUDIO_OUT; int kanal; int w;
int x=25, y=50; int play=-1, play_b=-1; char* bufor; InitLCD(); InitADC(); LCDSettings(); LCDClearScreen(); //inicjalizacja LCD // inicjalizacja ADC //ustawienie LCD // wyczyszczenie ekranu while(1) { kanal = GetAdcChanel(ADC_CHN_7); switch(kanal){ case 0: // MIN LCDPutStr(" ",y,x,large,white,black); if (play_b==0){ PIOB_CODR = AUDIO_OUT; play=1; play_b=1; case 102: LCDPutStr("* ",y,x,large,white,black); if ((play==1) (play_b==1)){ PIOB_CODR = AUDIO_OUT; play=2; play_b=0; case 204: LCDPutStr("** ",y,x,large,white,black); if ((play==2) (play_b==2)){ PIOB_CODR = AUDIO_OUT; play=3; play_b=1;
case 306: LCDPutStr("*** ",y,x,large,white,black); if ((play==3) (play_b==3)){ PIOB_CODR = AUDIO_OUT; play=4; play_b=2; case 409: LCDPutStr("**** ",y,x,large,white,black); if ((play==4) (play_b==4)){ PIOB_CODR = AUDIO_OUT; play=5; play_b=3; case 512: LCDPutStr("***** ",y,x,large,white,black); if ((play==5) (play_b==5)){ PIOB_CODR = AUDIO_OUT; play=6; play_b=4; case 614: LCDPutStr("****** ",y,x,large,white,black); if ((play==6) (play_b==6)){ PIOB_CODR = AUDIO_OUT; play=7; play_b=5; case 716: LCDPutStr("******* ",y,x,large,white,black); if ((play==7) (play_b==7)){ PIOB_CODR = AUDIO_OUT; play=8; play_b=6;
case 818: LCDPutStr("******** ",y,x,large,white,black); if ((play==8) (play_b==8)){ PIOB_CODR = AUDIO_OUT; play=9; play_b=7; case 921: LCDPutStr("********* ",y,x,large,white,black); if (play==9){ PIOB_CODR = AUDIO_OUT; play=10; play_b=8; case 1023: // MAX LCDPutStr("**********",y,x,LARGE,WHITE,BLACK); if (play==10){ PIOB_CODR = AUDIO_OUT; play=9; if((piob_pdsr & SW_1) == 0){ bufor = (char*)malloc(40); sprintf(bufor,"%d \0",kanal); LCDPutStr(bufor,70,40,LARGE,WHITE,BLACK); free(bufor); if((piob_pdsr & SW_2) == 0){ LCDPutStr(" ",70,40,LARGE,WHITE,BLACK); return 0;
Zdjęcia wykonywanego programu w ustawieniu potencjometru na pozycji: a. Minimalnej b. Środkowej
c. Maksymalnej Wraz ze sprawdzeniem wartości rejestru. 16. Wyjaśnienie poszczególnych fragmentów kodu: Aby przypisać wartość rejestru do jakiejś zmiennej, należy użyć funkcji: GetAdcChanel(); Zawartej w pliku "adc.h" a zaimplementowanej w "adc.c". Wygląda ona następująco: unsigned int GetAdcChanel(unsigned char chanel) { // variable unsigned int result; // Enable desired chanel a_padc->adc_cher = chanel; // Start conversion a_padc->adc_cr = 0x2;
// wait for end of convertion while(!(a_padc->adc_sr&chanel)); switch (chanel) { case ADC_CHN_1: result = a_padc->adc_cdr0; case ADC_CHN_2: result = a_padc->adc_cdr1; case ADC_CHN_3: result = a_padc->adc_cdr2; case ADC_CHN_4: result = a_padc->adc_cdr3; case ADC_CHN_5: result = a_padc->adc_cdr4; case ADC_CHN_6: result = a_padc->adc_cdr5; case ADC_CHN_7: result = a_padc->adc_cdr6; case ADC_CHN_8: result = a_padc->adc_cdr7; return result; Widać, że interesujący rejestr ADC_CDR6, pod którym jest potencjometr ma kanał ADC_CHN_7, tak też należy wywołać funkcję, tzn.: int kanal; ( ) kanal = GetAdcChanel(ADC_CHN_7); Teraz zmienną kanal można wykorzystać w bloku switch, którego część jest niżej opisana: switch(kanal){ case 0: // MIN LCDPutStr(" ",y,x,large,white,black); if (play_b==0){
PIOB_CODR = AUDIO_OUT; play=1; play_b=1; ( ) case 512: // MEDIUM LCDPutStr("***** ",y,x,large,white,black); if ((play==5) (play_b==5)){ PIOB_CODR = AUDIO_OUT; play=6; play_b=4; ( ) case 1023: // MAX LCDPutStr("**********",y,x,LARGE,WHITE,BLACK); if (play==10){ PIOB_CODR = AUDIO_OUT; play=9; Wartość rejestru ADC_CDR6, jest w zmiennej kanal, dana jej wartość wykonuje odpowiedni blok case. Zmiennej play i play_b warunkują nam pyknięcie tylko przy każdej zmianie bloku case, zabezpieczenie jest potrzebne, ponieważ np. gdy potencjometr pozostanie w pozycji idealnie środkowej, gdzie rejestr zmienna kanal=512, blok case 512 będzie się wykonywał w nieskończoność, jednak warunek if
((play==5) (play_b==5)) zabezpiecza przed ciągłym wydawaniem dźwięku, ponieważ po pojedynczym wykonaniu następuje inkrementacja zmiennej play oraz dekrementacja play_b więc warunek w danym case jest niespełniony, natomiast umożliwia wydanie dźwięku w poprzedzającym i następującym bloku (widać to dokładnie w listingu programu). Zmienne x oraz y to pozycja wyświetlanego paska postępu. Następnym krokiem jest wyświetlenie danej wartości rejestru. Ponieważ wartości w rejestrze są niesformatowane, należy użyć funkcji sprintf, która zapisuje tekst sformatowany do wskazanego bufora znakowego. Kod: char* bufor; // wskaźnik na bufor znakowy ( ) // wyświetlenie sformatowanej wartości pamięci if((piob_pdsr & SW_1) == 0){ // lewy przycisk bufor = (char*)malloc(40); // rezerwacja pamięci sprintf(bufor,"%i \0",kanal); // wywołanie funkcji LCDPutStr(bufor,70,40,LARGE,WHITE,BLACK); // wyświetlenie sformatowanego tekstu free(bufor); // zwolnienie pamięci //wyczyszczenie if((piob_pdsr & SW_2) == 0){ // prawy przycisk LCDPutStr(" ",70,40,LARGE,WHITE,BLACK); Pierwszy warunek obsługuje przycisk lewy, drugi warunek przycisk prawy.