Skocz do zawartości

[C] Licznik modulo i wyświetlanie na LCD. Intel 8051.


Yggas

Pomocna odpowiedź

Witam. Miałem na zajęciach z mikroprocesorów zrobić licznik modulo 100 i miał być wyświetlany na LCD. Problem w tym, że licznik jakoś tam udaje mi się robić lepiej lub gorzej ale nie wiem jak wyświetlać to na ekranie...

Mam tylko pozmieniać (w gotowym pliku prezentacyjnym kontrolera) void(main) i pętle while(1).

void disptext(unsigned char xdata *wsk){
unsigned char data i;
adrlcd(adres_linijka1);
for(i=0;i<16;i++){
datw=*wsk;
wsk++;
busylcd();
			}
adrlcd(adres_linijka2);
for(i=0;i<16;i++){
datw=*wsk;
wsk++;
busylcd();
			}
							}

To jest chyba od sterowania wyświetlaniem tekstu tak? Tylko, że to się chyba odwołuje do tablicy, a nie wiem jak w tablicy zamieścić zmienną i by licznik był od 0 do np 100 czyli 3 pozycje na wyświetlaczu 2x16. (mam to być w pierwszej linijce wyświetlacza)

Jak by mi to ktoś wyjaśnił to będę niezmiernie wdzięczny!

Link do komentarza
Share on other sites

1. Licznik modulo 100 to dwie cyfry dziesiętne do wyświetlenia, bo liczy w cyklu 0..99.

2. Pokazałeś funkcję obsługi wyświetlacza. Wygląda, że jest on podłączony (jako urządzenie w obszarze zewnętrznej pamięci danych?) pod adresem datw i że po ustawieniu "kursora" funkcją adrlcd() potem wystarczy wysłać kody znaków.

Jeśli nie chcesz modyfikować pokazanej funkcji, musisz zadeklarować sobie swój własny bufor danych, np:

unsigned char xdata ekran_wyswietlacza[32];

Potem piszesz do niego (wstawiasz do tablicy) potrzebne znaki w odpowiednie miejsca i po wywołaniu funkcji:

disptext(ekran_wyswietlacza);

masz to pokazane na wyświetlaczu.

A licznik modulo N możesz z robić na kilka sposobów:

a. zliczasz binarnie w cyklu od 0 do N-1:

if (++licznik >= N)
  licznik = 0;

b. korzystasz z operatora modulo:

licznik = (licznik + 1) % N;

ale te dwa pomysły dają licznik binarny, którego zawartość musisz przed wysłaniem do wyświetlacza przekonwertować na ciąg cyfr dziesiętnych. Na szczęście w przypadku małych liczb (w zakresie 0..99) jest to trywialne:

dziesiatki = licznik / 10;
jednosci = licznik % 10;

Te dwie wartosci zamieniasz na znaki ASCII i pokazujesz na wyswietlaczu:

ekran_wyswietlacza[0] = dziesiatki + '0';
ekran_wyswietlacza[1] = jednostki + '0';
adrlcd(adres_linijka1);
disptext(ekran_wyswietlacza);

To by było na tyle.

Oczywiście można wymyślić sobie o wiele ładniejszy i bardziej uniwersalny program obsługujący większe i mniejsze N gdzie będzie potrzebna lepsza konwersja bin→dec itd, ale powyższe chyba spełnia założenia. Umieść odliczanie i wyświetlanie w pętli w main() i nie zapomnij o jakimś opóźnieniu, bo takie rzeczy to nawet '51 umie bardzo szybko liczyć 🙂

Link do komentarza
Share on other sites

No niby jest OK ale nie 😃

	while(1){

	if (++licznik >= N) 
	licznik = 0;
	licznik = (licznik + 1) % N;
	dziesiatki = licznik / 10; 
	jednosci = licznik % 10;
	tblcw[9] = dziesiatki + '0'; 
	tblcw[10] = jednosci + '0'; 

	disptext(tblcw);

	for(i=0;i<20000;i++)
	;

}

To opóźnienie na końcu to prowadzący nam pokazał i mówi, że prymitywne 😋

Licznik odlicza ale co 2.

Co to znaczy jak użyłeś wpis: "dziesiatki + '0' "

Co oznacza to + "0"?

a inkrementacja jest już zrobiona w warunku ?

Link do komentarza
Share on other sites

Pozbądź się nawyku kopiowania wszystkiego. Przecież pokazałem dwie różne metody inkrementacji licznika, ale powinieneś stosować je alternatywnie (którą wolisz) a nie jednocześnie, bo +1+1 to razem +2, prawda?

Wyglądało, że masz problem jedynie z ogarnięciem wyświetlacza, inkrementacją modulo i konwersją bin->dec a nie ogólnie z programowaniem 🙂 Zaproponuj coś z tym opóźnieniem. Jak Ty byś chciał to zrobić? Jaka metoda wg Ciebie lub prowadzącego nie jest prymitywna (jakby cały ten "program" taki nie był..)? Chcesz się czegoś nauczyć? Wiesz coś więcej o '51 czy próbujesz tanim kosztem opędzić pracę domową? Jeśli to pierwsze, zastanów się i napisz coś konstruktywnego. Czekamy.

BTW: Dodanie stałej '0' jest prostą konwersją liczby binarnej w zakresie 0..9 na kod znaku '0'..'9' jakim posługuje się wyświetlacz. Hasło do poszukania: tablica znaków kodu ASCII.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

No niestety mam braki, mało się przykładałem na początku studiów do programowania (kierunek elektryczny) w dodatku ocena z zajęć była na obecność co też nie zachęcało.

Ale staram się to w miarę nadrobić i się do tego przyłożyć.

Co do opóźnień to na chwilę obecną będę stosował takie 😋

Tutaj program z dwiema zmiennymi, jakoś bardziej byłem nastawiony, że jedna się zwiększa o jeden i jeżeli dojdzie do tej naszej dzielnej = 100 to się zeruje i od nowa, a inna zmienna licznik zlicza zerowania.

	while(1){

	do
		k++;
	while(k%N==0);
	licznik++;
	k=0;
	jednosci=licznik%10;
	dziesiatek=licznik/10;

	tblcw[9]=dziesiatek + '0';
	tblcw[10]=jednosci + '0';
	if(licznik>=N)
		licznik=0;

	disptext(tblcw);

	for(i=0;i<15000;i++)
	;

}

W sumie dużo zmian nie zrobiłem :/ Muszę jeszcze poczytać o kodowaniu ASCI lub znaleźć gdzie to jest wytłumaczone. Wcześniej jak próbowałem to właśnie mi zliczało ale po cyfrze 9 pojawiały się litery duże potem małe a potem znaczki i nie wiedziałem co tam się dzieje 😋

Teraz będę kombinował z odczytaniem sygnału analogowego z potencjometru i wyświetleniem napięcia. Przy tym chyba będę musiał przeliczyć to jakoś *5.0/1023.0 ? Tak jak się robi w Arduino?

Link do komentarza
Share on other sites

Albo to jest część jakiegoś Wielkiego Planu którego nie ogarniam albo robisz w kodzie jakieś głupstwa.

Czy mógłbyś na chłopski rozum wytłumaczyć do czego służą te machlojki ze zmienną k? Ani razu nie używasz jej wartości w sensowny sposób. Poniżej wrzucam Twój kod z usuniętymi liniami korzystającymi z k. Działa tak samo:

  while(1){
       jednosci=licznik%10;
       dziesiatek=licznik/10;

       tblcw[9]=dziesiatek + '0';
       tblcw[10]=jednosci + '0';

       if (++licznik>=N)
           licznik=0;

       disptext(tblcw);

       for(i=0;i<15000;i++)
       ;
}

Zmieniłem odrobinkę inkrementację licznika by było widać, że jest to zliczanie modulo. Dwie rozstrzelone po kodzie linie nie ułatwiają zrozumienia. Staraj się pisać programy jak list do kogoś, tłumaczący co chcesz zrobić. Nie gub wątków, nie mieszaj myśli, za to skupiaj się na jednej rzeczy w danym miejscu na raz.

A konwersję ADC na mV napięcia możesz zrobić wprost, używając arytmetyki zmiennoprzecinkowej:

float voltage_mv = (float)ADC * 5.0 / 1023.0;

Tak robi wielu ludzi i gdy masz dużo czasu i miejsca w pamięci, zadziała. Gdy jesteś sportowcem lub masz jakieś pojęcie o arytmetyce komputerów, zrobisz to bez problemu na stałym przecinku.

Acha, pomyśl jak zrobić konwersję większej liczby (np. z zakresu 0..255 lub 0..65535) na postać dziesiętną, znakową.

Link do komentarza
Share on other sites

	while(1){

for(i=0;i<10000;i++)
;
odczytADC=PTAC;
wynik=odczytADC/51;
tblcw[10]=wynik + '0';

disptext(tblcw);



}

Takie coś zrobiłem, przetwornik ADC jest 8-bitowy czyli jego rozmiar danych to 0-255, dobrze to rozumiem? No i trzeba z tego zrobić proporcję czyli dlatego dopisałem dzielenie przez 51 by wyszedł zakres wyświetlania 0V-5V.

Niestety (albo stety bo nie określone mam czy część ułamkową też ma pokazywać) pokazuje napięcie w liczbach całkowitych. Nie wiem czy jeszcze dziś będę miał czas ogarnąć ale jak tylko znajdę chwilkę (dla mnie pewnie trochę dłużej) to postaram się to zrozumieć i napisać i wtedy wrzucę do sprawdzenia.

EDIT:

Tamten post z kodem ze zmienną k rozumiałem(czy tam wyobraziłem sobie) na ten sposób, że zliczam taktowanie jakiegoś sygnału i to k imitowało ten sygnał, a licznik zliczał. No i tak właśnie z tym wymyślaniem było :<

Link do komentarza
Share on other sites

Mając 8-bitowy ADC dostajesz z niego trochę ponad 2 dziesiętne cyfry znaczące. Trzech nie ma sensu wyświetlać, ale dwie wypadałoby (z ew. kropką między nimi i symbolem 'V' na końcu?). Pokazywanie jednej leży moim zdaniem poniżej poziomu dopuszczalnej chały.

Musisz więc zmapować zakres 0..255 na 0..99 a potem to już łatwo: masz liczbę co najwyżej 2-cyfrową czyli zadziała prymitywna konwersja bin->dec, której już używałeś. Do roboty 🙂

Link do komentarza
Share on other sites

//Zmienna tablicy jest taka:
unsigned char xdata tblcw[]="Napiecie: 0.0 V";

while(1){

	for(i=0;i<10000;i++)
		;
	wynik=PTAC;
	jednosci=wynik/51;
	switch(jednosci){
		case 0:
			ulamek1= (wynik/26) % 10;
					break;
		case 1:
			ulamek1= (wynik/26) % 10;
					break;
		case 2:
			ulamek1= (wynik/26) % 10;
					break;
		case 3:
			ulamek1= (wynik/26) % 10;
					break;
		case 4:
			ulamek1= (wynik/26) % 10;
					break;
		default:
			ulamek1=0;
		break;
	}
	ulamek2=(jednosci*2)%10;
	tblcw[10]=jednosci +'0';
	tblcw[12]=ulamek1 + '0';
	tblcw[13]=ulamek2 + '0';

disptext(tblcw);



}

Działa lecz odczyt nie jest zbyt liniowy chyba 😋 Bardziej pięcio(sześcio)-pozycyjny.

EDIT: Zmieniłem na pokazywanie trzech. Zdaję sobię sprawę z tego, że pewnie niekonieczne było użycie funkcji switch ale inaczej nie wykombinowałem. Do tego druga cyfra po przecinku zmienia się od 0 do 9 nie zerując się przy liczbie całkowitej :< Jutro to dokończę.

A jutro już kolejne zajęcia gdzie mam przerwania i multipleksowanie. Kiedy ja to nadrobie 🙄

Link do komentarza
Share on other sites

Sam widzisz, że marnie to wygląda. Bardziej eleganckich sposobów konwersji jest kilka. Jeden z nich to znów wykorzystanie operatora modulo. Prosty kod wyliczający trzy cyfry z liczby 8-bitowej wyglądałby jakoś tak:

jednostki = licznik % 10;
licznik /= 10;
dziesiatki = licznik % 10;
licznik /= 10;
setki = licznik;

Przemyśl jak to działa.

Gdybyś miał wypisywać jakąś większą liczbę (np. 16-bitową czyli 5 cyfr), możesz łatwo rozszerzyć powyższą metodę do 4 razy modulo i 4 dzieleń, ale ładniej będzie to zapisać w pętli:

char cyfry[5];
for(n=0; n<5; n++)
{
  cyfry[n] = (licznik % 10) + '0';
  licznik /= 10;
}

Po zakończeniu pętli masz w tablicy cyfry[] rozwinięcie dziesiętne licznika od razu w postaci znaków ASCII. Najmłodsza cyfra została policzona pierwsza więc jest w cyfry[0], najstarsza w cyfry[4] 🙂

Nadrobisz, nadrobisz, brakuje Ci trochę programistycznej ogłady, ale przecież nie święci garnki lepią.

Link do komentarza
Share on other sites

No troszkę mnie nie było 😋

Zmodyfikowałem na takie coś:

unsigned char xdata tblcw[]="Napiecie: 0.0 V"; 
unsigned char xdata PTAC _at_ 0x8000;

   while(1){ 

   for(i=0;i<10000;i++) 
      ; 

   licznik=PTAC; 

	setki=licznik/51;
	jednostki=licznik%10;
	licznik/=10;
	dziesiatki=licznik%10;


   tblcw[10]=setki +'0'; 
   tblcw[12]=dziesiatki + '0'; 
   tblcw[13]=jednostki + '0'; 

   disptext(tblcw); 

}

Sęk w tym, że zaraz po wartości 4,5V wyskakuje 5,55V :<

Link do komentarza
Share on other sites

Moim zdaniem robisz coś dziwnego w okolicach konwersji. Przecież setki liczysz z innej wartości niż resztę cyfr. Najpierw powinieneś wyprodukować kompletną wartość, którą chcesz pokazać. Dopiero potem, osobno konwersja na cyfry. Przecież to nie konkurs na najkrótszy program. Zrób to po prostu:

licznik=PTAC;
napiecie = licznik/51;

jednostki = napiecie%10;
napiecie /= 10;
dziesiatki=napiecie%10;
napiecie /= 10;
setki = napiecie;   // Tu już nie trzeba modulo, bo calosc i tak byla <= 999 wiec ostatnia cyfra jest podana na talerzu
Link do komentarza
Share on other sites

Yggas, wyjmij kartkę, ołowek i policz na spokojnie co Twój program robi.

Załóżmy, że odczytaliśmy z ADC wartość 254. Masz wtedy:

setki=licznik/51; 

Czyli setki = 4

jednostki=licznik%10

Daje: jednostki = 5

licznik/=10; 
       dziesiatki=licznik%10; 

Teraz licznik = 25, dziesiatki = 5

Spróbuj policzyć co dostaniesz dla odczytu 255 to sam zobaczysz skąd jest wynik 5.5V 🙂

Jak już przećwiczysz okolice 254, to zobacz co dzieje się dla odczytu z ADC w okolicy 203/204 - niestety Twój program jest po prostu błędny, ale jeszcze wszystkich błędów nie zauważyłeś.

Link do komentarza
Share on other sites

		
   licznik=PTAC; 
	napiecie= licznik/51;

	setki = napiecie;
	jednostki=(licznik*2)%10;
	licznik/=10;
  dziesiatki=(licznik*2)%10;


   tblcw[10]=setki +'0'; 
   tblcw[12]=dziesiatki + '0'; 
   tblcw[13]=jednostki + '0'; 

   disptext(tblcw); 

A teraz koledzy można to zatwierdzić jako kod zapisany w C?

Dodatkowo teraz muszę element przeliczający napisać w Asemblerze i się do niego odwołać z C, po czym wrócić i wypisać komentarz. Program ma działać tak samo tylko ma część być w Asemblerze. Przećwiczę to i wam przedstawię kod.

PS: Aha, czy to odwołanie Asemblera to trzeba do tego robić osobny plik czy mogę to wpisać w main.c?

Link do komentarza
Share on other sites

Moim zdaniem zupełnie nie rozumiesz jak konwersja int -> cyfry oparta na modulo działa. Znów napisałeś coś bez sensu. Kolejność operacji jest ważna, bo algorytm wyznacza kolejne cyfry sekwencyjnie od najmłodszej do nastarszej. Znajdź dziecko różnice między dwoma rysunkami:

napiecie = licznik/51;
jednostki = napiecie%10;
napiecie /= 10;
dziesiatki=napiecie%10;
napiecie /= 10;
setki = napiecie;
napiecie= licznik/51;
setki = napiecie;
jednostki=(licznik*2)%10;
licznik/=10;
dziesiatki=(licznik*2)%10;

Nie ma sensu zabierać się za asembler skoro nie wiesz jak ten algorytm działa, a Twój kod (ten w drugiej ramce powyżej) jest zły. Przecież jeśli zaraz na początku zrobisz:

setki = napiecie;

to jaka będzie wartość zmiennej setki np. gdy napiecie=123? Na pewno nie 1, prawda?

Weź skup się, usiądź na chwilę, narysuj na kartce liczbę trzycyfrową i spróbuj wyznaczyć jej cyfry patrząc na swój algorytm. A potem postaraj się zrozumieć na spokojnie jak działa mój przykład. Nie pisz żadnych programów tylko myśl. Może wtedy coś do Ciebie dotrze.

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.