Skocz do zawartości

[Kurs] Kurs programowania procesorów ARM (LPC21xx)


Pomocna odpowiedź

Po 1) nie "aksambler" tylko asembler (asm)

po 2) BASCOM to środowisko programistyczne dla AVRów (i niektórych uC z rodziny tzw. '51)

po 3) regulamin, punkt 3a

Widzisz profesorek, i ty się chcesz brać za ARMy jak ty nawet nie wiesz do czego służy Bascom. Naucz się może najpierw jednego z najprostszych języków czyli właśnie Bascoma, jak go poznasz i zaczniesz robić urządzenia, dla których Bascom już nie będzie wystarczał, wtedy przesiądziesz się na ARM'y i inne języki programowania np asemblera czy C.

Co do języków programowania, to na ARM-y na pewno da się pisać w C++. Na ARM9 można uruchomić linux-a, a wtedy już pełna gama programów, nawet serwer www+php. Jednak raczej nie o to w mikrokontrolerach chodzi.

Pierwsze pytanie jest trudniejsze. Teoretycznie wszystko co można zrobić na ARM-ie można też zrobić na AVR. ARM9 ma MMU i to jest istotna różnica. ARM7 i cortex raczej nie mają "czegoś", co by je istotnie różniło od AVR.

Główna różnica to 32-bitowa architektura, większa pamięć i szybkość.

Pamięć można podłączyć (zewnętrzną) i do AVR, programowo można działać na dłuższych danych niż 8-bitów. Więc jedyne w czym AVR niewątpliwie przegrywa to szybkość wykonywania programów.

Gdyby porównywać mikrokontrolery do mikroprocesorów, to pytanie byłoby jak: co można zrobić na najnowszym Core Duo, a nie da się na 386.

Jeśli zaczynasz przygodę z elektroniką, to AVR w zupełności wystarczą. Są łatwiejsze do nauki i tańsze. ARM to temat raczej dla bardziej zaawansowanych.

  • Lubię! 1

Z tym, że uC z rdzeniem ARM9 to nie uC, a bardziej procesory się nie zgodzę, wystarczy spojrzeć na rodzinę STR91x z STM =] To są mikrokontrolery "pełną gębą" i spokojnie można je oprogramowywać jak takowe, a stopień trudności pisania na nie programów wcale nie jest większy niż na ARM7. Tyle, że ARM9 jest rdzeniem wydajniejszym.

  • 4 miesiące później...

Jak chodzi o biblioteki to niestety na arm jest trudniej.

Nigdy nie używałem, ale znalazłem bibliotekę ArmLib - http://hubbard.engr.scu.edu/embedded/arm/armlib/index.html , w niej jest trochę funkcji, które wydają się ciekawe.

Najprościej opóźnienie zrobić na pętli - oscyloskopem wyregulować i chodzi.

Niestety dokładność jest wtedy bardzo słaba.

Jeśli opóźnienia maja być dokładnie mierzone pozostaje użyć timer. LPC21xx ma 2 timery. Można wykorzystać jeden do tworzenia opóźnień, albo wprowadzić globalny licznik czasu i za jego pomocą tworzyć opóźnienia.

Jest jeszcze jedna możliwość, uruchomić RTOS, np. FreeRTOS - http://www.freertos.org/ . Dopiero wtedy procesor nie będzie marnował czasu czekając aktywnie w pętlach.

Mi chodzi o to aby program właśnie czekał (tak jakby w petli) określona cześć czasu.

Chce zaprogramować wyświetlacz 2x14 LCD oraz termometr na 1-wire a one wymagają odczekiwania określonych czasów, a nie ma sensu zaprzęgać do tego timerów.

Jeżeli wiemy jak taktowany jest procesor, wiemy ile cykli potrzebnych jest na sprawdzenie warunku + wykonanie skoku (petla for, lub mała wstawka asemblerowa) możemy sobie sami takie funkcje napisać.

Takie aktywne czekanie ma kilka poważnych wad. Po pierwsze jest mało dokładne. Jeśli w trakcie wystąpi przerwanie, to czas będzie inny. Dla 1-wire może to mieć znaczenie, więc trzeba wyłączać przerwania czekając, co z kolei może powodować problemy procedur działających na przerwaniach.

Dodatkowy problem to pobór prądu. Procesory ARM potrafią sporo pobrać. W końcu 60MHz to sporo. Więc czekanie w pętli to marnowanie czasu i prądu.

Najlepiej jest uruchomić timer i uśpić procesor. Wtedy mamy dokładność działania, brak opóźnień przerwań i oszczędność prądu.

  • 1 rok później...

Witam!!

Rozpocząłem naukę z programowaniem mikrokontrolerów ARM z książki Pawła Borkowskiego i mam kilka pytań co do jeżyka C. Załączę listing, którego zbytnio nie rozumiem.

#include

//tablica kodów cyfr

unsigned int kody[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66,
0x6D, 0x7D, 0x07, 0x7F, 0x6F};

void Czekaj(int ile)

{

for(; ile>0; ile--);

}

void W_LED(unsigned int n_A, //numer wyprowadzenia podłączonego do A

unsigned int tab[], //tablica indeksów kodów cyfr

unsigned int n_W1 //numer wyprowadzenia podłączonego do W1

)

{

int i;

unsigned int w;

w = 1<

for(i=3; i>=0; i--)

{

//ustaw wyświetlacz

//a) zgaś wszystkie części wyświetlacza

IOSET = 0xF<

//b) włącz odpowiednią część

IOCLR = w;

//wyświetl cyfrę

//a) zgaś wszystkie diody

IOSET = 0xFF<

//b) zaświeć diody cyfry

IOCLR = kody[tab]<

//zaczekaj 2,5 ms

Czekaj(30000);

//przesuń bit włączający część wyświetlacza

w <<= 1;

}

}

int main()

{

//tablica indeksów tablicy kodów

unsigned int tablica[4] = {9, 0, 0, 2};

//ustaw kierunek wyjściowy dla linii od P0.16 do P0.27

IODIR = 0x0FFF0000;

//pętla nieskończona

for(;😉

{

W_LED(16, tablica, 24);

}

}

Moje pytania brzmią :

1. Jak została zdefiniowana zmienna w, jeśli nie mamy wcześniej podanej wartości zmiennej n_W1. Czy mógłby mi ktoś rozpisać w systemie binarnym przesunięcia bitowe. Uczyłem się tego z symfonii grębosza, ale było tam jedynie przesunięcie o liczbę całkowitą. A tutaj jest zapis 1<

1. Do wpisywania kodu słuzy [ code]

2. Kod przepisywałeś zapewne ręcznie, bo brakuje średników i jest nadprogramowy nawias

3. unsigned int n_W1 oznacza prawdopodobnie, że zostawiamy zmienną niezainicjowaną - co zwykle oznacza, że ma wartość równą zero. I jest to odpowiedź na wytanie: n_W1 jest równe 0

 #include <LPC210x.h>

//tablica kodów cyfr
unsigned int kody[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66,
					0x6D, 0x7D, 0x07, 0x7F, 0x6F};

void Czekaj(int ile)
{
for(; ile>0; ile--);
}

void W_LED(unsigned int n_A,	//numer wyprowadzenia podłączonego do A
          unsigned int tab[],	//tablica indeksów kodów cyfr
	   unsigned int n_W1	//numer wyprowadzenia podłączonego do W1
	   )
{
int i;
unsigned int w;
w = 1<<n_W1;

for(i=3; i>=0; i--)
{
	//ustaw wyświetlacz
	//a) zgaś wszystkie części wyświetlacza
	IOSET = 0xF<<n_W1;
	//b) włącz odpowiednią część
	IOCLR = w;

	//wyświetl cyfrę
	//a) zgaś wszystkie diody
	IOSET = 0xFF<<n_A;
	//b) zaświeć diody cyfry
	IOCLR = kody[tab[i]]<<n_A;
	//zaczekaj 2,5 ms
	Czekaj(30000);

	//przesuń bit włączający część wyświetlacza
	w <<= 1;
}
}


int main()
{
//tablica indeksów tablicy kodów
unsigned int tablica[4] = {9, 0, 0, 2};

//ustaw kierunek wyjściowy dla linii od P0.16 do P0.27
IODIR = 0x0FFF0000;

//pętla nieskończona
for(;;)
{
	W_LED(16, tablica, 24); 
}
}

Jeśli n_W1 = 0

to zapis IOSET = 0XF << n_W1 równoważy się z zapisem IOSET = 0xF - czyli nie ma przesunięcia o bit?

Mam problem jedynie z funkcją void W_LED i czy mógłby mi ją ktoś szczegółowo wytłumaczyć zwracając uwagę na przesunięcia bitowe włączające odpowiednią część wyświetlacza. Z góry dzięki 🙂

W sumie to nie do końca poprawnie Ci powiedziałem 😉

Generalnie jest tak: n_W1 jest wartością przekazywaną do funkcji W_LED, czyli np. przy wywołaniu W_LED(16, tablica, 24); n_A = 16, n_W1 = 24, a tab = tablica. Wcześniej nie zauważyłem, że tam jest funkcja, dopiero jak były wcięcia.

w = 1<<n_W1;

przesunięcie '1' o wartość n_W1. Np. jeśli n_W1 = 3 to w = 1000b, jeśli n_W1 = 0, to w = 0001b, jeśli 6 to 0010 0000b

 IOSET = 0xFF<<n_A;

To samo, ale z 0xFF, czyli jeśli n_A = 6 to IOSET = 0011 1111 1100 0000b itd. Podobnie z przesuwaniem wartości z tablicy, tylko tam masz presuwanie np. 1011 0011.

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...