Skocz do zawartości

Elvis

Użytkownicy
  • Zawartość

    2603
  • Rejestracja

  • Ostatnio

  • Wygrane dni

    191

Wszystko napisane przez Elvis

  1. Jak chodzi o IAR to warto sprawdzić ile ten kompilator kosztuje...
  2. Źle jest wpięty kondensator 1uF na samej górze. Powinien być między pin 2, a GND. Na datasheecie jest oznaczony jako C3.
  3. Poprzednia część kursu. [Kurs] Programowanie ARM LPC1114 cz.4 - PWM Programowy PWM Podobnie jak w poprzednim kursie przygotujemy programowe sterowanie jasnością diod. Mamy do dyspozycji tylko 2 diody, ale to wystarczy do nauki. W pliku program11.zip znajdziemy kod programu. W poprzednim kursi znajdziemy sporo informacji o PWM: https://www.forbot.pl/forum/topics20/kurs-programowania-arm-cz7-pwm-vt3926.htm Wykorzystamy timer jak w poprzednim przykładzie, ale zmienimy częstotliwość wywoływania procedury przerwania. Tym razem będziemy wywoływać ją co 100us. Wystarczy zmienić wartość rejestrów MR0 oraz PR. W procedurze obsługi przerwania wywołamy procedurę pomocniczą pwm_proc(). Działa ona tak jak opisywana dokładnie w poprzedniej edycji kursu - realizuje programowy PWM na liniach podłączonych do diod LED1 i LED2. Działanie PWM zostało już opisane w poprzednim kursie. Warto zwrócić na nową funkcję delay() - pozwala ona na odczekiwanie przez zadany czas (parametrem jest opóźnienie w jednostkach 10ms). Nieco mylące jest sterowanie diodami - wystawiając logiczne 0 zapalamy diody, a 1 gasimy. Więc wypełnienie PWM 0% oznacza maksymalną jasność diody, a 100% - jej wygaszenie. Stąd w wyliczeniach niejako odwrotne sterowanie. Sprzętowy PWM Umiemy już programowo obsługiwać PWM, czas poznać możliwości sprzętowego PWM. Sprzętowe rozwiązanie jest pod wieloma względami znacznie lepsze niż programowe. Nie obciąża procesora, jest znacznie dokładniejsza niż realizacja programowa. Następny przykład znajdziemy w pliku program12.zip. Celem programu jest sterowanie silniczkami robota. Za pomocą joysticka na płytce ZL32ARM będziemy sterować robotem. Wykorzystamy znany nam już 16 bitowy timer 0, tym razem uruchomimy w nim tryb PWM. Do wyprowadzeń P0_9 oraz P0_10 podłączamy sterownik silników. W opisywanym przykładzie są to po prostu tranzystory BC337. Równie dobrze, a nawet lepiej można byłoby podłączyć mostek H, przykładowo dobrze znany L293. W poprzedniej części kursu wspomniane zostały funkcje alternatywne linii procesora. Teraz z nich skorzystamy. Domyślnie P0_9 oraz P0_10 są to linie wejścia-wyjścia. My chcemy, żeby działał na nich sprzętowy PWM. Zmieniamy działanie linii następującym kodem: LPC_IOCON->PIO0_9 = 0x02; LPC_IOCON->SWCLK_PIO0_10 = 0x03; Dokładny opis kodów dla każdego pinu znajduje się w dokumentacji procesora. Po wykonaniu powyższego kodu linie P0_9 i P0_10 zamiast zwykłymi I/O stają się wyjściami modułu PWM. Musimy dokonać drobnej zmiany w naszej konfiguracji timera. Po pierwsze uruchamiamy PWM na tym timerze pisząc: LPC_TMR16B0->PWMC = 0x06; Kod uruchamia wyjścia MAT1 i MAT2 timera (są one wyprowadzone na liniach P0_9 i P0_10). Kolejna zamiana to przypisanie rejestrom MR1 i MR2 wartości wypełnienia linii PWM: LPC_TMR16B0->MR1 = PWM_PERIOD; LPC_TMR16B0->MR2 = PWM_PERIOD; Czeka nas tutaj pewna niespodzianka. PWM układu LPC1114 działa w ten sposób, że na początku okresu PWM na wyjściu wystawiane jest logiczne 0, po doliczeniu do wartości rejestru MR1 (albo MR2), wyjście zmienia wartość na 1. Oznacza to, że wpisanie do MR1 wartości 0 daje 100% wypełnienie PWM, a wartość MR1 - daje na wyjściu 0%. Czyli niejako odwrotnie niż byśmy tego oczekiwali. Aby ułatwić sterowanie silnikami przygotujemy funkcję, która przyjmie (w procentach) wypełnienie PWM, dokona odpowiednich przeliczeń i ustawi odpowiednie rejestru. Kod tej funkcji wygląda następująco: void pwm_set(int32_t l_proc, int32_t r_proc) { LPC_TMR16B0->MR1 = PWM_PERIOD*(100-l_proc)/100; LPC_TMR16B0->MR2 = PWM_PERIOD*(100-r_proc)/100; } Prosty program główny pozwoli nam na sterowanie robotem: if (GPIOGet(JOY_U)==0) pwm_set(100, 100); else if (GPIOGet(JOY_OK)==0) pwm_set(25, 25); else if (GPIOGet(JOY_L)==0) pwm_set(50, 0); else if (GPIOGet(JOY_R)==0) pwm_set(0, 50); else pwm_set(0, 0); Sterowanie silnikiem - znaczenie diod zabezpieczających Postanowiłem zaryzykować uszkodzenie tranzystorów sterujących i przepadać wpływ diod na pracę układu. Na początek podłączyłem silnik bez diod zabezpieczający. Pierwszy program nie wykorzystywał PWM, jedynie w pełni załączał silnik. Co ciekawe diody nie okazały się niezbędne. Jak widać na oscylogramie poniżej, wszystko działało poprawnie. Jednak uruchomienie PWM diametralnie zmieniło sytuację. Poniżej widać oscylogramy (po prawej zmieniona jest skala - indukowane napięcie było tak duże, że nie było widać go przy poprzedniej skali) Co prezentują powyższe oscylogramy? Przy rozłączaniu zasilania silników indukuje się całkiem znaczne napięcie. Jak widać jest to ponad 25V! Dopóki stale zasilaliśmy silnik nic złego się nie działo. Jednak, gdy używamy PWM, każde rozłączanie zasilania indukuje niekorzystne dla nas napięcie. Mój układ wytrzymał takie sterowanie, jednak potencjalnie możemy w ten sposób uszkodzić sterownik silnika, a nawet procesor. Sytuacja jest jeszcze gorsza, gdy zablokujemy silnik. Po lewej stronie widać oscylogram przy pracy silników bez obciążenia, po prawej gdy zablokujemy koła: Teraz pojawia się napięcie ponad 45V! Na początek dodamy diodę równolegle do tranzystora - taka dioda jest wbudowana w większość tranzystorów MOSFET. Jak widać dioda ta niewiele pomaga. Musimy więc dodać kolejne diody - tym razem równolegle z uzwojeniami silnika. Teraz wreszcie sytuacja jest nieco lepsza. Napięcie nieznacznie przekracza 7V. Ja zastosowałem tanie i wolne diody 1N4148. Gdyby zastosować diody szybkie (schotky'ego) uzyskalibyśmy jeszcze lepsze rezultaty. Wniosek jest następujący: diody zabezpieczające są niezbędne. Warto wspomnieć o jeszcze jednym efekcie - z diodami silniki uzyskały znacznie większy moment i prędkość przy takim samym wysterowaniu. program11.zip program12.zip
  4. Poprzednia część kursu. [Kurs] Programowanie ARM LPC1114 cz.3 - zegary i przerwania Na początek dobra wiadomość. Rdzenie Cortex mają znacznie poprawioną obsługę przerwań w porównaniu do starszej rodziny ARM7TDMI. Inżynierowie firmy ARM wzięli sobie do serca krytykę poprzednich procesorów i dodali do rdzenia znacznie poprawioną obsługę przerwań. Przed lekturą tego artykułu zachęcam do przeczytania piątej części poprzedniego kursu, w której poruszona została pokrewna tematyka. Najpierw zajmiemy się przerwaniami od układów licznikowych, tzw. timerów. Procesor LPC1114 jest wyposażony w 5 timerów. Dwa są 16-bitowe, dwa 32-bitowe oraz jeden specjalny, który ma rozdzielczość 24-bitów. Rejestry 16 i 32 bitowe są to liczniki tzw. ogólnego zastosowania. Oferują bogatą funkcjonalność, w szczególności mogą działać jako PWM. Ostatni timer (SysTick timer) ma specjalne zastosowanie - służy do zapewniania podstawy czasu. Jest to bardzo wygodne rozwiązanie dla każdego projektanta systemu. Timer systemowy Najpierw musimy napisać procedurę obsługi przerwania. Jest to nadzwyczaj łatwe zadanie. Wystarczy napisać funkcję o nazwie SysTick_Handler. Co powinna robić taka funkcja? Na początek może po prostu zwiększać globalny licznik czasu. Mamy więc kod: volatile uint32_t global_timer = 0; void SysTick_Handler(void) { global_timer++; } Chcemy, aby zmienna global_timer była zwiększana co powiedzmy, 10 ms. Konfiguracja jest bardzo łatwa dzięki funkcji SysTick_Config zdefiniowanej w pliku core_cm0.h (plik został dołączony wraz z biblioteką CMSIS). Aby uruchomić przerwanie piszemy: SysTick_Config(480000); // 10ms Wartość 480 000 wynika z prędkości działania procesora - jest on skonfigurowany do pracy z częstotliwością 48MHz. Więc 48 000 000 / 480 000 daje nam 100Hz, czyli oczekiwane 10ms. W pliku program09.zip znajdziemy przykład wykorzystania timera do domierzania czasu zapalania i gaszenia diod. Dla dociekliwych Ktoś może zapytać, jak to się dzieje, że procesor działa z prędkością 48MHz. Odpowiedź znajdziemy w pliku system_LPC11xx.c znajdującym się w bibliotece CMSIS. Znajdziemy tam funkcję SystemInit. Uruchamia ona pętlę PLL, domyślnie wykorzystuje zewnętrzny kwarc 12MHz i konfiguruje procesor do pracy z podaną prędkością. Zmieniając plik system_LPC11xx.c możemy łatwo zmienić konfigurację systemu. Kolejne pytanie to nazwa funkcji - skąd bierze się akurat SysTick_Handler. Aby się o tym przekonać możemy otworzyć plik cr_startup_lpc11.c - został on automatycznie dodany do naszego projektu. W pliku tym znajdziemy domyślne funkcje obsługujące przerwania. W szczególności funkcję obsługi interesującego nas przerwania. Jest ona oznaczona słówkiem WEAK, dzięki czemu nasza funkcja niejako zastąpi tę domyślną. Warto jeszcze przyjrzeć się funkcji ResetISR. Jest ona wywoływana po resecie (więc i przy uruchomieniu) mikrokontrolera. Ta funkcja najpierw wywołuje SystemInit, a następnie nasz program - funkcję main(). W pliku cr_startup_lpc11.c znajdziemy również domyślne funkcje obsługi pozostałych przerwań. Możemy je przedefiniować, aby zapewnić własne funkcje obsługi przerwań. Timery ogólnego przeznaczenia Mamy już globalny licznik czasu, teraz poznamy 16-bitowy licznik czasu. W pliku program10.zip znajduje się opisywany przykład. Program uruchamia 2 timery. Timer systemowy oraz 16 bitowy timer 0. Ten timer musimy skonfigurować sami. W tym celu wykorzystujemy wskaźnik LPC_TMR16B0. Pełny opis rejestrów znajdziemy w dokumentacji, następujący kod uruchamia timer: LPC_SYSCON->SYSAHBCLKCTRL |= 0x80; // CT16B0 clock enable LPC_TMR16B0->TCR = 2; // timer reset LPC_TMR16B0->MCR = 3; // reset and interrupt on MR0 LPC_TMR16B0->MR0 = 48000; // 1 ms LPC_TMR16B0->PR = 9; // prescaler 10 LPC_TMR16B0->TCR = 1; // timer enable NVIC_EnableIRQ(TIMER_16_0_IRQn); // interrupt enable Pierwsza linijka jest konieczna, aby moduł timera zaczął działać. Aby oszczędzać prąd procesor początkowo ma uruchomione tylko niezbędne moduły. Za pomocą rejestru MCR ustawiamy tryb działania timera - chcemy aby liczył do wartości MR0, następnie wywoływał przerwanie i liczył od początku. Do MR0 wprowadzamy wartość 48000, więc przerwanie byłoby wywoływane co 1ms. Wykorzystujemy preskaler w rejestrze PR aby zamiast co 1ms wywoływać przerwanie co 10ms. Do rejestru PR wpisujemy wartość o 1 mniejszą niż oczekiwane „spowolnienie” timera. Funkcja NVIC_EnableIRQ uruchamia nasze przerwania. Pozostaje jeszcze dodać funkcję obsługi przerwania. Podobnie jak poprzednio wystarczy napisać funkcję o nazwie TIMER16_0_IRQHandler. void TIMER16_0_IRQHandler(void) { static uint8_t bit = 0; if (bit) { GPIOClear(LPC_GPIO2, 0x80); bit = 0; } else { GPIOSet(LPC_GPIO2, 0x80); bit = 1; } LPC_TMR16B0->IR = 0x1f; // clear interrupt flag } Funkcja na pinie P2_7 generuje sygnał prostokątny. Jeśli mamy pod ręką oscyloskop, możemy zobaczyć jak działa nasze przerwanie. Ostatnia linijka funkcji jest bardzo ważna. W niej zerujemy flagę przerwania. Inaczej zaraz po zakończeniu funkcji zostałaby ona wywołana ponownie. Kolejna część naszego kursu, w której omówiony zostanie PWM pojawi się już za tydzień. program09.zip program10.zip
  5. Zobacz: Poprzednia część kursu! Programowanie ARM LPC1114 cz.2 - porty I/O Porty wejścia-wyjścia są niewątpliwie najważniejszymi układami peryferyjnymi każdego procesora. W poprzedniej wersji kursu opisywałem dokładnie ich działanie. Teraz skoncentruję się nad zmianami w nowym mikrokontrolerze. Podobnie jak poprzednio, najważniejsza jest umiejętność korzystania z dokumentacji procesora. Całą dokumentację znajdziemy na stronie producenta. Najciekawszy jest dokument nazwany „User Manual” (co ciekawe Datasheet to jedynie ogólny opis procesora). Link do dokumentacji: http://ics.nxp.com/support/documents/microcontrollers/pdf/user.manual.lpc11xx.lpc11cxx.pdf Podobnie jak poprzednio, w dokumentacji możemy znaleźć rozmieszczenie pinów procesora: W procesorze LPC2114 porty I/O były 32-bitowe. Nowy procesor ma również 32-bitowe porty, jednak każdy port ma maksymalnie 12 pinów. Ułatwia to adresowani linii procesora. Dostępne są 4 porty: PORT0 PORT1 PORT2 PORT3 Piny oznakowywane są jako: PIO0_0, PIO0_1, itd. PIOx to numer portu, a część po podkreśleniu (_) to numer linii. Sterowanie wyjściami procesora Dostęp do portów nieco się zmienił w nowej wersji procesora. Zamiast bezpośrednio odwoływać się do rejestrów, wykorzystujemy wskaźniki. Każdy port posiada zdefiniowany wskaźnik na strukturę w pamięci. Szczegóły znajdziemy w pliku LPC11xx.h. Do portów odwołujemy się więc przez wskaźniki: LPC_GPIO0 LPC_GPIO1 LPC_GPIO2 LPC_GPIO3 Każdy wskaźnik wskazuje na strukturę nazwaną LPC_GPIO_TypeDef. Jej pola odpowiadają rejestrom procesora. Przykładowo pole DIR odpowiada za kierunek działania linii wejścia-wyjścia. Ustawienie bitu ustawia linię jako wyjście (identycznie jak w przypadku rejestrów DDRA, DDRB itd. procesorów AVR). W zestawie ZL32ARM dioda LED1 podłączona jest do linii P0_6. Aby ustawić tę linię jako wyjście użyjemy kodu: LPC_GPIO0->DIR |= _BV(6); Nie należy się więc obawiać wskaźników. Jest to nieco inny zapis niż byliśmy dotychczas przyzwyczajeni, ale działanie jest identyczne jak dotychczas. Kolejny rejestr który będzie nas interesował to rejestr DATA. Zapis do niego ustawia stan linii danego portu. Działa więc identycznie jak odwołanie do PORTA, PORTB, itd. w procesorach AVR. Aby zapalić diodę LED1 wykonujemy kod (zapalamy wystawiając logiczne zero!) LPC_GPIO0->DATA &= ~_BV(6); Diodę gasimy podobnie: LPC_GPIO0->DATA |= _BV(6); Rejestr DATA można również wykorzystać do odczytania stanu linii, gdy pracuje ona jako wejście. Wykorzystanie rejestru DATA nie jest najlepszym rozwiązaniem, ale na początek może wydawać się najłatwiejsze. Pozwala na programowanie w stylu znanym z procesorów AVR. W pliku program01.zip znajdziemy przykładowy program. Ustawia on linię P0_6 jako wyjście, a następnie cyklicznie zapala i gasi diodę LED1. Plik program02.zip zawiera kolejny przykład, tym razem sterowane są diody LED1 oraz LED2 i zapalane naprzemiennie. Dostęp maskowany Korzystanie z rejestru DATA może powodować problemy, gdy w programie używane będą przerwania. Dodatkowo problemem może być jednoczesne ustawianie i wygaszanie bitów - konieczne może być wykonanie najpierw zerowanie, następnie ustawianie bitów. Aby w jednej instrukcji umożliwić zapis zarówno zer jak i jedynek do wybranych linii portu, dodany został rejestr MASKED_ACCESS. Rejestr ma postać tablicy o rozmiarze 4096 (czyli 2^12). W celu dostępu do wybranych linii zapisujemy (lub odczytujemy) pod indeks taki jak maska zmienianych bitów. Przykładowo, załóżmy że do linii P1_4, P1_5, P1_6, P1_7 mamy podłączony wyświetlacz alfanumeryczny. Chcemy w jednej instrukcji zapisać wartość 5 do linii wyświetlacza, nie zmieniając jednocześnie pozostałych wartości. Chcemy więc wyzerować P1_7, P1_5, a ustawić P1_4 i P1_6, nie zmieniając stanu pozostałych linii. Za pomocą rejestru DATA moglibyśmy wykonać następujący kod: LPC_GPIO1->DATA |= _BV(6)|_BV(4); LPC_GPIO1->DATA &= _BV(5)|_BV(6); Aby wykorzystać rejestr MASKED_ACCESS, najpierw musimy ustalić jaka jest maska naszego zapisu. Maska ma „1” tam gdzie chcemy zmieniać dane, a „0” w miejscach które mają pozostać niezmienione. Czyli powinna wyglądać następująco: Możemy ją zapisać jako: _BV(7)|_BV(6)|_BV(5)|_BV(4) Albo, co chyba nieco wygodniejsze po prostu: 0x0f0 Teraz możemy w jednej instrukcji dokonać zapisu danych: LPC_GPIO1->MASKED_ACCESS[0x0f0] = 0x050; Podobnie można odczytywać stan wybranych linii. Przykład użycia rejestru MASKED_ACCESS znajdziemy w pliku program03.zip. W kodzie zaprezentowane są 2 wersje. Pierwsza jednocześnie zapala diodę LED2 i gasi LED1: LPC_GPIO0->MASKED_ACCESS[LED_MASK] = LED_1; Druga wersja oddzielnie odwołuje się do każdego pinu. Ustawienie bitu (czyli zgaszenie diody) realizuje kod: LPC_GPIO0->MASKED_ACCESS[LED_1] = LED_1; Natomiast wygaszenie bitu: LPC_GPIO0->MASKED_ACCESS[LED_2] = 0; Funkcje dostępu do pinów Przyznam, że wykorzystanie rejestru MASKED_ACCESS chociaż wydajne, nie zawsze jest intuicyjne. Aby nieco ułatwić programowanie, zdefiniujemy funkcje do ustawiania i wygaszania odpowiednich linii procesora. Funkcja ustawiająca „1” na odpowiednich wyjściach wygląda następująco: void GPIOSet(LPC_GPIO_TypeDef* gpio, uint32_t pin) { gpio->MASKED_ACCESS[pin] = pin; } Natomiast ustawienie „0” wygląda tak: void GPIOClear(LPC_GPIO_TypeDef* gpio, uint32_t pin) { gpio->MASKED_ACCESS[pin] = 0; } Warto zwrócić uwagę na parametr gpio. Jest to wskaźnik na strukturę opisującą port. Dzięki temu funkcja może obsługiwać każdy port GPIO procesora. W pliku program04.zip znajdziemy opisane funkcje oraz przykład ich użycia: while(1) { GPIOSet(LPC_GPIO0, LED_1); GPIOClear(LPC_GPIO0, LED_2); for (i=0;i<1000000;i++) ; GPIOClear(LPC_GPIO0, LED_1); GPIOSet(LPC_GPIO0, LED_2); for (i=0;i<1000000;i++) ; } W pliku program05.zip zobaczymy pewne ułatwienie w definiowaniu, gdzie podłączone są diody. Zamiast wpisywać LPC_GPIO0 w wywołaniu GPIOClear/GPIOSet definiujemy następujące stałe: #define LED_1_PIN _BV(6) #define LED_2_PIN _BV(7) #define LED_1 LPC_GPIO0, LED_1_PIN #define LED_2 LPC_GPIO0, LED_2_PIN Dzięki takiej definicji kod jest jeszcze łatwiejszy do analizy, a zmiana podłączenia peryferiów na inny port wymaga jedynie zmiany w definicji. GPIOSet(LED_1); GPIOClear(LED_2); Plik program06.zip zawiera kolejną wersję programu, tym razem definicje podłączeń układów zostały przeniesione do nowego pliku hardware.h. Ułatwia to dostosowywanie programu do zmian w elektronice. Opisy podłączeń są zebrane w oddzielnym pliku. Odczyt stanu linii Gdy potrafimy już sterować liniami procesora, czas odczytać stan linii. W przykładowym zestawie znajdziemy joystick, którego stan postaramy się odczytywać. Jak widać przycisk środkowy (JOY_OK) jest podłączony do portu 0, pozostałe do portu 1. Dzięki opisanej wcześniej definicji linii nie stanowi to problemu. #define JOY_OK_PIN _BV(3) #define JOY_U_PIN _BV(8) #define JOY_OK LPC_GPIO0, JOY_OK_PIN #define JOY_U LPC_GPIO1, JOY_U_PIN Teraz potrzebujemy funkcji odczytu stanu linii. Wygląda następująco: int GPIOGet(LPC_GPIO_TypeDef* gpio, uint32_t pin) { if (gpio->MASKED_ACCESS[pin]) return 1; return 0; } Aby sprawdzić kod w działaniu, będziemy zapalać diodę po przyciśnięciu przycisku joysticka (trzeba pamiętać, że na wejściu pojawia się 0, gdy przycisk jest naciśnięty): if (GPIOGet(JOY_OK)==0) GPIOClear(LED_1); else GPIOSet(LED_1); W pliku program07. zip znajdziemy przykład odczytu stanu linii wejścia-wyjścia. Własna biblioteka funkcji Kolejny plik - program08.zip zawiera opisywane wcześniej funkcje wydzielone do nowego modułu. Pliki gpio.c oraz gpio.h będą wykorzystywane w kolejnych programach. Dodatkowe funkcje Warto wspomnieć o pozostałych możliwościach portów I/O. Większość pinów oprócz działania jako wejście-wyjście może też pełnić inne funkcje, jak chociażby wyprowadzenia modułów UART, I2C, czy SPI. Do konfiguracji funkcji alternatywnych służy wskaźnik LPC_IOCON. Wskazywana struktura posiada pola dopowiadające kolejnym pinom. Możemy w niej ustawić funkcje pełnione przez linie, włączyć lub wyłączyć rezystory podciągające i histerezę. Z możliwości tych będziemy korzystać w kolejnej części kursu - gdy będziemy poznawać komunikację przez RS-232 oraz działanie przetwornika analogo-cyforwego (ADC). Warto również wspomnieć o możliwości generowania przerwań w reakcji na zmianę stanu pinu (lub poziom). Nie będziemy tego wykorzystywać, jednak czasem może być to użyteczne - szczególnie, gdy zależy nam na natychmiastowej reakcji np. na wykrycie przeszkody czujnikiem. program01.zip program02.zip program03.zip program04.zip program05.zip program06.zip program07.zip program08.zip
  6. Ja chodziłem do szkoły bardzo nisko w rankingach. A nie uważam, żeby to było dużym problemem
  7. Teraz to Ty robisz wodę z mózgu... Nie bez powodu mówimy "uczyć się" - jeśli sam się nie nauczysz, nikt za Ciebie tego nie zrobi. Więc szkoła, prestiż, kadra itd. to nie wszystko
  8. To moje doświadczenie, każdy ma prawo do swojego. Ale jak widzę ludzi po technikum na analizie matematycznej, to nie jest łatwo...
  9. Jeśli mogę dołączyć się do dyskusji, to zagłosuję za liceum. Sam dawno temu chciałem iść do technikum, bo interesowałem się chemią. W międzyczasie zupełnie mi się odwidziało i zmieniłem zainteresowania. Jak pójdziesz do LO to możesz iść na właściwie dowolne studia. A kto wie co będzie Ci się podobało za kilka lat.
  10. Witam, chciałbym wszystkich zachęcić do lektury nowego kursu programowania procesorów ARM. Niestety podczas pisania kursu okazało się, że producent płytek ewaluacyjnych zakończył ich produkcję. Nie pozostało nic innego, jak wybrać inny zestaw ewaluacyjny i przygotować kolejny kurs, oparty na nowych - dostępnych płytkach. Wybór padł na relatywnie tanie zestawy ZL32ARM. Są one dostępne w sklepie Kamami, więcej na stronie producenta. Dla użytkowników Diody płytki te dostępne są w specjalnej, promocyjnej cenie - szczegóły poście Treker'a poniżej. Opis zestawu Zamontowany na płytce procesor jak i obsługę darmowego kompilatora LPCXpresso opisywałem już w jednym z moich poprzednich artykułów. Kurs zaprojektowany jest jako rozszerzenie poprzedniej wersji kursu. Zachęcam więc do przeczytania jego poprzedniej wersji przed lekturą nowej odsłony. Ponieważ nowa płytka ma mniej elementów niż zastosowana poprzednio, postanowiłem przykłady oprzeć na budowie prostego robota typu LineFollower - w końcu Dioda jest stroną o robotyce Robot jest jedynie ilustracją przykładów, więc nie będzie on na pewno konkurować z topowymi konstrukcjami dostępnymi na forum. Ma on za zadanie przybliżyć zastosowanie ARM'ów LPC1114 w naszym hobby. Do konstrukcji robota wykorzystałem elementy dostępne „pod ręką”, a głównym celem było użycie tanich elementów. Robot składa się z kilku płytek. Dokładniej z 4. Dzięki temu łatwiej było projektować płytki oraz dokonywać zmian. Jedna płytka jest tylko elementem konstrukcyjnym - służy jako podstawa dla płytki ewaluacyjnej. Kluczowe są dwie pozostałe płytki: płytka czujników - wyposażona w 8 czujników TCRT5000 (chociaż ostatecznie używane są tylko 4) płytka silników - zawiera sterownik silników oraz stabilizator 3.3V Dla uproszczenia przykładu wykorzystałem tylko jedno napięcie - 3.3V. W związku z tym nie stosowałem mostka H. Do sterowania silnikami wykorzystane są zwykłe tranzystory bipolarne (BC337 - akurat miałem pod ręką), przedstawiam poniżej dwa schematy: Kurs będzie się z składał z następujących części (linki zostaną dodane w miarę publikacji): 1) Kompilator, zestaw ZL32ARM 2) Wstęp do nowego kursu 3) Porty I/O 4) Zegary i przerwania 5) PWM 6) RS-232 7) ADC 8) Czujniki odbiciowe 9) Line follower Kurs będzie pojawiał się regularnie - nowy odcinek będzie pojawiał się w każdą niedzielę. Zapraszam do zapoznania się z możliwościami zestawu ZL32ARM oraz z poprzednim artykułem opisującym środowisko, kompilator oraz nasz zestaw testowy.
  11. Witam, postaram się opisać postępy prac nad moim pierwszym robotem kroczącym. Pierwsza wersja będzie bazować na gotowym szkielecie. Dokładniej na częściach kupionych tutaj: http://www.hexapodrobot.com/store/product_info.php?cPath=21_22&products_id=29 Nie cierpię projektowania mechaniki, więc dla mnie gotowy szkielet to idealne rozwiązanie. Dzisiaj dotarła przesyłka z elementami, zawartość pudełka wygląda następująco: Jutro planuję większe zakupy w sklepie modelarskim. Kolejnym krokiem będzie zaprojektowanie elektroniki. Zamierzam wykorzystać któryś z procesorów ARM, ale na razie jestem na etapie wybierania rozwiązań. Kolekcja serwomechanizmów już kupiona: Montaż robota zajmuje raptem chwilę Muszę pochwalić zestaw, wszystkie elementy pasują idealnie. Poniżej rezultat pracy: Teraz czas przystąpić do projektowania elektroniki. Koniec z gotowcami.
  12. A ustawiłeś RA0..3 jako wyjścia?
  13. Możesz wykorzystać program BTRobot.zip z artykułu. W pętli głównej kod wysyłający jest zakomentowany, czyli pętla główna powinna wyglądać tak: while (1) { sprintf(buf, "Hello world! %d\r\n", ++counter); KAmodBT_SendBuffer(buf); _delay_ms(100); }
  14. Jeśli nie otwiera się okno terminala, to coś jest nie tak z konfiguracją połączenia. Kod pin podałeś poprawnie? Atmega wysyła dane standardowo, przez UART. Przy okazji - jeśli używasz modułu BTM222, to zakładam, że pamiętasz o konwersji napięć 5V<->3.3V?
  15. Podłączenie musi być skrosowane, czyli: UART_TX -> BTM_RX UART_RX <- BTM_TX Natomiast jak chodzi o putty, to przy standardowych ustawieniach nie pojawia się tzw. echo. Czyli gdy naciskasz klawisze, ich kody są wysyłane przez port COM, ale znaki nie są wyświetlane na ekranie. Dopiero jeśli po drugiej stronie łącza zostanie wysłany znak, pojawi się on na ekranie. Więc jeśli program na AVR nie odsyła tego co dostał, nie widać wpisywanych znaków. Radziłbym na początek napisać program na AVR, który będzie w pętli wysyłał komunikat. Jeśli uda się go przesłać do PC i wyświetlić w ekranie terminala, to już połowa sukcesu.
  16. IRFZ44 przy 20A wydzielą koło 10W. Więc konieczny byłby spory radiator, żeby przeżyły. Zobacz IRF2804, które polecał Xweldog. Mają 10x niższy Rds, więc i moc będzie znacznie mniejsza.
  17. Odradzam używanie IRFZ44. Przy 20A nie mają większych szans. Jak koniecznie chcesz je stosować, to od razu daj bardzo duży radiator.
  18. Moduły Mobot-a są bardzo proste w obsłudze. To co wysyłasz przez UART przychodzi po drugiej stronie. Więc jeśli udało Ci się komunikować przez RS232 to bez zmian w programie wszystko powinno działać.
  19. xamrex moim zdaniem wynik jest poprawny, ale nie do końca rozumiem Twój dowód. Ja bym to wyprowadził tak: a + (a * b) = (a + a) * (a + b) = 1 * (a + b) = a +b
  20. Działanie bootloadera opisałem tutaj: https://www.forbot.pl/forum/topics20/kurs-programowania-arm-cz11-rs-232-cd-2-bootloader-vt4392.htm W przypadku LPC111x jest tak samo - zmienia się tylko pin P0.1 zamiast P0.14. Pull-up jest po to żeby bootloader się nie uruchamiał. Jeśli P0.1 zewrzemy do masy (np. zworką) to bootloader wejdzie w tryb programowania (po resecie). Jeśli wykonamy wszystko wg. schematu ZL32ARM - reset i sterowanie P0.1 będzie automatyczne. [ Dodano: 14-11-2010, 10:20 ] OldSkull w Keil-u trzeba zmienić deklarację funkcje przerwania: void timer0(void) __irq { } A jak chodzi o asemblera, to najłatwiej wydzielić kod do nowej funkcji: volatile __asm void enable_irq() { STMDB SP!, {R0} MRS R0, CPSR ... }
  21. Najprościej jest wykorzystać programator jak w zestawie ZL32ARM: http://www.kamami.pl/dl/zl32arm.pdf W dokumentacji jest schemat, można samemu wykonać. Warto dodać sterowanie resetem i uruchamianiem bootloadera (P0.1) - inaczej trzeba ręcznie sterować pinami. Można jeszcze taniej zrobić przejściówkę RS-232 <->UART. Schematy są na stronach Kamami - trzeba zobaczyć inne zestawy, np. ZL1ARM. Jak chodzi o interfejsy, to nowe cortex-y odchodzą od JTAG-a, zamiast nich używany jest SWD. Nie wiem jak jest z programatorami, ale oryginalny Keil-a jest baaaardzo drogi. Główny powód używania JTAG-a, czy SWD to możliwość debugowania programów. Jeśli nie chcemy debugować, to najlepiej programować przez UART - czyli przejściówkę RS-232 lub USB. Jak chodzi o podłączenie - SWD wymaga tylko 2 linii.
  22. LPC21xx to już nieco stara rodzina - rdzeń ARM7TDMI. Natomiast nowe to niewątpliwie Cortex. Odpowiednio Cortex-M3 - LPC17xx i Cortex-M0 - LPC11xx. Jest duża szansa, że ceny M0 będą spadać, więc mogą poważnie zagrozić 8-bitowcom. Oczywiście M0 mają być słabsze niż M3. Ale w porównaniu z małym AVR mają się czym pochwalić. [ Dodano: 13-11-2010, 22:05 ] Natomiast LPC2103 nie polecam z jednej przyczyny - stare LPC wymagały 2 napięć zasilających. Więc trzeba dać 3.3V i 1.8V. W nowszych już jest wbudowana przetwornica.
  23. O ile wiem, nie ma możliwości wgrywania programu przez SPI. Tak jest w AVR. Natomiast można przez UART, czasem nawet przez CAN i oczywiście SWD. A co do dokumentacji, to więcej jest w User's Manual-u: http://ics.nxp.com/support/documents/microcontrollers/pdf/user.manual.lpc11xx.lpc11cxx.pdf W okolicach strony 275 jest dokładnie wszystko opisane.
  24. SPI to nie to samo co ISP. O ile wiem, nie można LPC111x programować za pomocą SPI. ISP to skrót od In-System Programming. Czyli programowanie za pomocą sofware-u. Polega to na tym, że bootloader (który jest programem) programuje pamięć flash. Natomiast do LPC111x wystarczy konwerter RS-232<->UART, nic więcej do programowania nie jest niezbędne.
  25. Tani ARM - LPC1114 Wstęp W artykule chciałbym przedstawić rodzinę tanich mikrokontrolerów firmy NXP. Większość osób słyszało już o rdzeniu Cortex-M3. Jest to nowsza, pod wieloma względami udoskonalona wersja rdzenia ARM7TDMI. Znacznie mniej znana jest rodzina tanich mikrokontrolerów o rdzeniu Cortex-M0. Cortex-M0 zostały opracowane jako konkurencja dla obecnie stosowanych mikrokontrolerów 8-bitowych. Wobec podwyżki cen układów AVR warto zainteresować się nowym rdzeniem. Firma NXP jako jedna z pierwszych zaprezentowała mikrokontrolery z rdzeniem Cortex-M0. Są to mikrokontrolery oznaczone jako LPC-111x. Parametry mikrokontrolerów LPC-111x: • prędkość do 50 MHz • do 32 kB pamięci Flash • do 8kB pamięci RAM • wbudowany generator RC • wbudowany watchdog • sprzętowa obsługa I2C, SPI, UART • 10-bitowy przetwornik ADC • nowy interfejs programowania - SWD • możliwość programowania przez UART (RS-232) • dostępne wersje z obsługą interfejsu CAN Warto zwrócić uwagę na dostępne obudowy. Aktualnie w sprzedaży dostępne są układy w obudowach SMD, jednak zapowiadany jest układ w obudowie PLCC44 - pozwala ona na umieszczenie w podstawce i montaż przewlekany. Ostatnią, chociaż nie najmniejszą zaletą nowych układów jest ich cena. W sklepie Kamami dostępne są już za 5,55 zł brutto (cena za LPC1113 przy 30szt., 13.11.2010). Nawet cena detaliczna jest całkiem przystępna: 8,48 za procesor z 24kB pamięci Flash i 8kB RAM. ZL32ARM Aby rozpocząć przygodę z nowymi układami musimy mieć płytkę z procesorem. Niestety dopóki wersja w obudowie PLCC44 nie będzie dostępna, wlutowanie układu w obudowie SMD może być trudne dla początkującego elektronika. Jeśli chcemy łatwo zapoznać się z LPC1114 możemy wykorzystać płytkę ewaluacyjną. Firma Kamami przygotowała ciekawy zestaw uruchomieniowy ZL32ARM: http://kamami.pl/index.php?ukey=product&productID=137779 Zestaw składa się tak naprawdę z dwóch płytek. Jedna to konwerter USB<->UART wraz ze stabilizatorem 3.3V, układami sterowania resetem i uruchamianiem bootloadera. Druga to właściwa płytka z procesorem LPC1114. Zestaw jest dostarczany jako jedna płytka, ale gdy już poznamy nowy mikrokontroler możemy rozłączyć płytki i konwerter USB<->UART wykorzystywać w innych projektach. Jest to bardzo praktyczne rozwiązanie. Zestaw jest kompletny, potrzebujemy tylko kabla USB, aby rozpocząć przygodę z nowym procesorem. Nawet zasilacz nie jest potrzebny - programator ma wbudowany stabilizator 3.3V, zasilanie może być pobierane z portu USB. Oprogramowanie Będziemy nam potrzebne następujące oprogramowanie: • sterowniki układów FTDI (konwerter USB<->UART) - http://www.ftdichip.com/ • FlashMagic do programowania procesora - http://www.flashmagictool.com/ • kompilator LPCXpresso - http://lpcxpresso.code-red-tech.com/LPCXpresso/ Aby pobrać kompilator konieczna jest rejestracja. Jest ona darmowa. Sterowniki FTDI należy zainstalować przed podłączeniem układu, jednak w wielu systemach takie sterowniki już są zainstalowane. Konfiguracja kompilatora Instalacja LPCXpresso nie powinna stanowić problemu. Przy pierwszym uruchomieniu program zapyta o położenie naszych projektów: Domyślna ścieżka jest nieco niewygodna, warto zmienić ją na lokalizację łatwiejszą do odnalezienia na dysku. Każdy projekt będzie zakładany w podkatalogu podanej lokalizacji. Po naciśnięciu OK widzimy okno naszego kompilatora. Osoby znające Eclipse powinny być zadowolne - LPCXpresso bazuje właśnie na tym środowisku. Zanim zaczniemy pisanie programów musimy zaimportować bibliotekę CMSIS. Wybieramy opcję „Import Example project(s)” z menu widocznego w lewym dolnym rogu. Pojawi się następujące okno: Naciskamy przycisk „Browse”, automatycznie pojawi się katalog z przykładami. Wybieramy foldery: NXP->LPC1000->LPC11xx, a następnie plik: CMSISv1p30_LPC11xx.zip Zatwierdzamy wybór i sprawdzamy, czy w projektach pojawił się nowy zawierający dodaną bibliotekę. Teraz kompilator jest gotowy do pracy. Pierwszy program Wybieramy opcję „New project...”->„NXP LPC1100 projects”->”NXP LPC1100 C Project”. Pojawia się okno kreatora projektu. W pierwszym kroku wpisujemy nazwę projektu, np. „program01”. Naciskamy „Next” i wybieramy nasz procesor - LPC1114/301. Następny krok jest bardzo ważny. Musimy zaznaczyć opcję „Use CMSIS”: Jest to już ostatni krok, więc przyciskamy „Finish”. Kreator tworzy dla nas projekt: Możemy skompilować przykładowy program wybierając opcję „Project”->”Build Project”, albo klikając na przycisk z symbolem młotka w pasku narzędziowym. W widoku konsoli pojawią się informacje o poprawnej kompilacji. Nasz program nic nie robi, więc czas zmienić kod, tak żebyśmy mogli widzieć rezultat działania. Zestaw ewaluacyjny wyposażony jest w diody LED, wykorzystamy je do sygnalizacji działania programu. Wpisujemy kod: int main(void) { volatile static int i = 0 ; LPC_GPIO0->DIR |= 0x040; while(1) { LPC_GPIO0->DATA |= 0x040; for (i=0;i<100000;i++) ; LPC_GPIO0->DATA &= ~0x040; for (i=0;i<100000;i++) ; } return 0 ; } Program powinien skompilować się poprawnie. Teraz możemy otworzyć katalog z naszym kodem wynikowym. Niestety czeka nas niemiła niespodzianka. Domyślnie tworzony jest plik wynikowy w formacie .axf, zamiast oczekiwanego .hex. Musimy zmienić konfigurację kompilatora. Wybieramy opcję „Project”->”Properties”. Odnajdujemy zakładkę „Build Steps”, a następnie w okienku „Post-build steps” wpisujemy w pole „Command” polecenie: arm-none-eabi-objcopy -O ihex ${BuildArtifactFileName} ${BuildArtifactFileBaseName}.hex Tym razem plik .hex zostaje utworzony: Nasz program wgrywamy za pomocą FlashMagic-a. Wgrywamy pierwszy program Podłączamy płytkę, do komputera i sprawdzamy, który port COM został wybrany do podłączenia zestawu. W moim komputerze jest to COM40: Następnie uruchamiamy FlashMagic i ustawiamy odpowiednio jego konfigurację: • Select Device: LPC1114/300 • COM Port: - port do którego został podłączony nasz zestaw • Baud Rate - jeśli pojawią się problemy z programowaniem, można wybrać inną prędkość • Interface: None (ISP) • Oscillator (MHz): 12 • Hex File - plik, który utworzyliśmy za pomocą LPCXpresso Następnie naciskamy „Start” i programujemy układ. program01.zip
×
×
  • Utwórz nowe...