wojtekq2 Napisano Kwiecień 15, 2017 Udostępnij Napisano Kwiecień 15, 2017 Witam,Chciałbym się zwrócić do Was o pomoc w sprawdzeniu programu pod względem błędów. Mianowicie chcę zrobić miernik napięcia (od 0 do 5V) na arduino. Do tej pory mam wykonane połączenie i program który wgrywam do Arduino, jednak coś jest nie tak. Jak chce wyświetlić samą liczbę to nie mam z tym problemu, natomiast jak wykonam pomiar, przeliczę go na Volty, prze konwertuje zmienną za pomocą funkcji dtostrf na tablice znaków i teraz: jak wyświetlam na monitorze portu szeregowego który kol wiek znak tej tablicy wszystko ładnie pokazuje, a jak próbuje wyświetlić go na wyświetlaczu to brak reakcji (wyświetlacz niedziała). Czy moglibyście pomóc znaleźć mi błąd, ewentualnie powiedzieć co robię nie tak. Kod: #include <sevenSegmentDisplay.h> //do pobrania z github sevenSegmentDisplay name(COMMON_ANODE, 11,7,3,5,6,10,2,8); int VCC=12; int VC1=9; int VC2=13; int odczytanaWartosc = 0; //Odczytana wartość z ADC float napiecie = 0; //Wartość przeliczona na napięcie w V #define op 2 #define cz 2 char tablica1[4]; void setup() { Serial.begin(9600); pinMode(VCC, OUTPUT); pinMode(VC1, OUTPUT); pinMode(VC2, OUTPUT); } void loop() { odczytanaWartosc = analogRead(A5); //Odczytujemy wartość napięcia napiecie = odczytanaWartosc * (5.0/1023.0); //Przeliczenie wartości na napięcie Serial.println(napiecie); //Wysyłamy zmierzone napięcie dtostrf(napiecie,1,2,tablica1); //konwersja float na tablice char Serial.println(tablica1[0]); //sprawdzenie na monitorze portu szeregowego int czas_oczekiwania = 100; while(czas_oczekiwania>=20){ name.set(tablica1[0]); digitalWrite(VCC, HIGH); delay(cz); digitalWrite(VCC, LOW); delay (op); name.set(tablica1[2]); digitalWrite(VC1, HIGH); delay(cz); digitalWrite(VC1, LOW); delay(op); name.set(2); digitalWrite(VC2, HIGH); delay(cz); digitalWrite(VC2, LOW); delay(op); czas_oczekiwania--; } delay(500); } Cytuj Link do komentarza Share on other sites More sharing options...
marek1707 Kwiecień 15, 2017 Udostępnij Kwiecień 15, 2017 Opisz dokładnie, ale własnymi słowami co chciałbyś, by robiło to wywołanie: dtostrf(napiecie,1,2,tablica1); Postaraj się napisać co znaczy każdy argument i dlaczego dostał taką a nie inną wartość. A potem wytłumacz dlaczego na wyświetlaczu pokazujesz [0] i [2] pozycję tablicy oraz cyfrę 2. Cytuj Link do komentarza Share on other sites More sharing options...
wojtekq2 Kwiecień 15, 2017 Autor tematu Udostępnij Kwiecień 15, 2017 dtostrf(napiecie,1,2,tablica1); Tu widzę, że wkradł mi się chochlik o którym już wiedziałem wcześniej, a nie jest powodem nie działania poprawnie programu. Poprawnie napisana funkcja: dtostrf(napiecie,4,2,tablica1); dtostrf-funkcja zamieniająca float na tablice char,napięcie - tutaj przekazuje właśnie zmienną która ma być przekonwertowana,4 - nie jestem do końca pewien, ale ilość znaków które zawiera zmienna float,2 - to jest ilość miejsc po przecinku do których zostanie obcięty float,tablica1 - tablica ciągu znaków do której chcę aby została zapisana zmienna napięcie, Na wyświetlaczu pokazuje: [0] - pierwszą wartość w tablicy,[2] - trzecią wartość w tablicy (pomijam separator liczby),cyfrę 2 wyświetlam w celu sprawdzenia czy wyświetlacz działa (bo nie wyświetlał nic z tablicy); Cytuj Link do komentarza Share on other sites More sharing options...
marek1707 Kwiecień 15, 2017 Udostępnij Kwiecień 15, 2017 Proponuję rzecz najprostszą: uruchamiaj mniejsze kawałki kodu. Zrób pomiar i obliczenia wypisując cały wynik na porcie szeregowym. Potem zajmij się konwersją float->char. Mógłbym Ci tu opisywać jak działa funkcja dtostrf(), ale nic nie zastąpi tzw. pouczających doświadczeń 🙂 Na pewno czytałeś Mikołajka. Zarezerwuj sobie długi bufor, np. 20 znakowy, napisz dodatkową funkcję, która wypisuje go znak po znaku na port szeregowy, sprawdź czy działa wypełniając bufor jakimś znanym wzorcem a potem testuj dtostrf(). Wołaj ją dla różnych liczb, np. zawsze jakoś tak: dtostrf(liczba, 10, 2, bufor); lub tak jak założyłeś: dtostrf(liczba, 4, 2, bufor); i patrz co Ci oddaje dla kilku dobrze dobranych liczb udających wyniki pomiarów. Zdziwisz się a jednocześnie być może zrozumiesz dlaczego Twój kod nie działa jak sobie zaplanowałeś. A jeśli konwersja będzie już w porządku, zajmij się wyświetlaniem. Dlaczego samodzielnie multipleksujesz wyświetlacze? I to jeszcze z jakimiś dziwnymi opóźnieniami? Zapalasz cyfrę na chwilę a potem na tyle samo czasu robisz przerwę. Marnujesz 50% czasu i możliwej jasności LED. EDIT: I zapomniałem: masz także problem z odróżnianiem znaków '2' o kodzie 0x32 (oddawanych np. przez funkcję konwersji) od liczby 2 która w pamięci wygląda jak 0x02. Cytuj Link do komentarza Share on other sites More sharing options...
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. 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
wojtekq2 Kwiecień 18, 2017 Autor tematu Udostępnij Kwiecień 18, 2017 Wypełniłem tablicę ciągiem znaków i wszystko się ładnie wyświetla na monitorze portu szeregowego : char tablica1[20]={'1','2','3','4','5','6','7','8','9',',','0','0','1','2','3','4'}; // tablica uzupełniona 16 znakami void setup() { Serial.begin(9600); } void loop() { for(int i=0; i<sizeof(tablica1); i++) { Serial.print(i); Serial.print("="); Serial.println(tablica1[i]); delay(500); } Serial.print("tablica="); Serial.println(tablica1); } 2) nie czytałem Mikołajka i nie wiem o co chodzi 😉 I funkcja dtostrf Zrobiłem tak jak pisałeś, przetestowałem tą funkcję, dla różnych wariantów i wnioski mam następujące: -jeśli zmienna float jest za duża to zostaje obcięta jej część całkowita i zaokrąglona w górę albo w dół,-dtostrf(liczba, 10, 2, bufor)- teraz liczba 10 to tak jakby "miejsca w tablicy na których jest wpisywana zmienna float i jeśli jest ona większa od tej zmiennej to w tablice są wpisywane puste pola i bufor tak będzie uzupełniany aby skończył się wpisywać na 10 miejscu w tablicy. Natomiast jeśli będzie na odwrót to ta sytuacja nie występuje, bufor się uzupełnia po kolei. Tutaj niestety muszę się przyznać, że nie rozumie dlaczego wyświetlacz nie reaguje jak wywołuje znak z tablicy. Wkleje jeszcze raz kod. Na monitorze portu szeregowego wszystko się ładnie wypisuje a wyświetlacz pokazuje tylko dwójkę wpisaną "ręcznie". #include <sevenSegmentDisplay.h> //do pobrania z github sevenSegmentDisplay name(COMMON_ANODE, 11,7,3,5,6,10,2,8); int VCC=12; int VC1=9; int VC2=13; //int odczytanaWartosc = 0; //Odczytana wartość z ADC float napiecie = 4.1234; //Wartość przeliczona na napięcie w V #define op 2 #define cz 4 char tablica1[5]; void setup() { Serial.begin(9600); pinMode(VCC, OUTPUT); pinMode(VC1, OUTPUT); pinMode(VC2, OUTPUT); } void loop() { //odczytanaWartosc = analogRead(A5); //Odczytujemy wartość napięcia //napiecie = odczytanaWartosc * (5.0/1023.0); //Przeliczenie wartości na napięcie //Serial.println(napiecie); //Wysyłamy zmierzone napięcie dtostrf(napiecie,5,3,tablica1); //konwersja float na tablice char for(int i=0; i<sizeof(tablica1); i++) { Serial.print(i); Serial.print("="); Serial.println(tablica1[i]); delay(100); } Serial.print("tablica="); Serial.println(tablica1); // Serial.println(tablica1[0]); //sprawdzenie na monitorze portu szeregowego int czas_oczekiwania = 100; while(czas_oczekiwania>=20){ name.set(tablica1[0]); digitalWrite(VCC, HIGH); delay(cz); digitalWrite(VCC, LOW); delay (op); name.set(tablica1[2]); digitalWrite(VC1, HIGH); delay(cz); digitalWrite(VC1, LOW); delay(op); name.set(2); digitalWrite(VC2, HIGH); delay(cz); digitalWrite(VC2, LOW); delay(op); czas_oczekiwania--; } delay(500); } 3)Dlaczego samodzielnie multipleksuje wyświetlacze- ponieważ dorwałem taki wyświetlacz ze starego dekodera SATELITY i postanowiłem że zrobię miernik napięcia w ramach ćwiczeń. Odnośnie czasów jakimi zapalam i gaszę poszczególne segmenty to znalazłem podobne w czyimś projekcie i tym się zasugerowałem. Jak powinny wyglądać one prawidłowo, np 2 milisekundy wyłączone i 4 zapalone?, niestety nie mam na tyle czasu aby wszystko wyczytać/ sprawdzić lub też znajdę takie a nie inne informacje i przyjmuje je za poprawne. Aczkolwiek wiem, że w Internetach jest dużo błędnych informacji. 4)Teraz podejrzewam, że najważniejsza kwestia, zmienna liczbowa przekonwertowana na typ char jest już zapisana w kodzie inaczej i program jej nie wyświetli ponieważ nie widzi jej poprawnie? Co powinienem zrobić, przekonwertować typ char poszczególnych elementów tablicy na typ np. int? Czy w ogóle mój tok myślenia jest błędny? 0x32 to 50 0x02 to 2 Cytuj Link do komentarza Share on other sites More sharing options...
marek1707 Kwiecień 18, 2017 Udostępnij Kwiecień 18, 2017 Brawo, nie zmarnowałeś czasu. Jesteś już bardzo blisko rozwiązania. Wiesz już co dostajesz w buforze po konwersji więc wiesz jak wygląda znakowa postać twojego float'a. I teraz słowo klucz: znakowa. Funkcje operujące na znakach w najprostszej formie działają na 7-bitowych kodach ASCII (znajdź tabelę takich znaków, jest tego pełno). To historyczny już dzisiaj skrót oznaczający pewien standard kodowania znaków czy sposobu interpretacji kodów przez urządzenie pokazujące tekst człowiekowi. Jak szybko się zorientujesz jest tam kilka "stref" liczbowych: 0x00-0x1F: to kody tzw. sterujące urządzeniami. W tej grupie masz przejazdy kursora do początku linii, wysunięcie o 1 wiersz, nowa strona itd. Tak, ASCII powstawało w czasach dalekopisów i drukarek wierszowych 🙂 0x20-0x3F: to znaczki typu kropka, przecinek itd. W tej grupie masz cyfry (0x30-0x39). 0x40-0x5F: to są głównie duże litery plus kilka znaczków dodatkowych. 0x60-0x7F: tu są małe litery i kilka pozostałych znaczków. Mam nadzieję, że już rozumiesz: cyfry po konwersji w buforze wyjściowym funkcji dtostrf() są znakami. Mają więc kody 0x30-0x39. Czegoś takiego spodziewa się urządzenie (konsola/terminal) podłączone przez port szeregowy i dlatego bufor wyświetla się poprawnie. Wysłanie przez Serial.print() bajtu o kodzie np. 0x43 powoduje wyświetlenie litery 'C' a 0x32 to cyfra '2'. Natomiast niestety funkcje biblioteki z której korzystasz oczekują prawdziwych wartości cyfr. Żeby pokazać znak '2' musisz im zapodać po prostu 2 czyli wartość 0x02. To głupie i niekonsekwentne, bo już żeby pokazać literę 'A" (na 7 segmentach da się pokazać niektóre litery) trzeba wysłać kod znaku 'A' czyli 0x41. Na szczęście konwersja z cyfr kodowanych w ASCII na ich wartości jest prosta: jeżeli znak ma wartość w zakresie 0x30-0x39 to odejmujesz 0x30 i dostajesz wartość 0-9 🙂 A pytałem o samodzielne multipleksowanie dlatego, że np. biblioteka sevenseg (inna niż ta Twoja) umie robić dużo więcej. Tam po prostu zapodajesz jej na jakich pinach masz dołączony wyświetlacz LED (gdzie segmenty a gdzie anody/katody) a ona sama organizuje przełączanie cyfr i świecenie wszystkiego. To dużo wygodniejsze, spróbuj. Na pewno nie wolno tego robić tak jak zrobiłeś: w pętli z delay'ami. To prymitywne i zżera 100% czasu procesora. http://playground.arduino.cc/Main/SevenSeg Cytuj Link do komentarza Share on other sites More sharing options...
wojtekq2 Kwiecień 20, 2017 Autor tematu Udostępnij Kwiecień 20, 2017 Miernik działa poprawnie 😉 uporałem się z nim. Kod dla miernika: #include <sevenSegmentDisplay.h> //do pobrania z github sevenSegmentDisplay name(COMMON_ANODE, 11,7,3,5,6,10,2,8); int a,b,c; int VCC=9; int VC1=13; int VC2=12; int odczytanaWartosc = 0; //Odczytana wartość z ADC float napiecie = 0; //Wartość przeliczona na napięcie w V #define op 2 //opóźnienie #define cz 4 //czas palenia się segmentów char tablica1[4]; void setup() { Serial.begin(9600); pinMode(VCC, OUTPUT); pinMode(VC1, OUTPUT); pinMode(VC2, OUTPUT); } void loop() { odczytanaWartosc = analogRead(A5); //Odczytujemy wartość napięcia napiecie = odczytanaWartosc * (5.0/1023.0); //Przeliczenie wartości na napięcie Serial.println(napiecie); //Wysyłamy zmierzone napięcie dtostrf(napiecie,4,2,tablica1); //konwersja float na tablice char for(int i=0; i<sizeof(tablica1); i++) { Serial.print(i); Serial.print("="); Serial.println(tablica1[i]); } a=tablica1[0]; b=tablica1[2]; c=tablica1[3]; a=a-48; b=b-48; c=c-48; int czas_oczekiwania = 40; while(czas_oczekiwania>=0){ name.set(a); digitalWrite(VCC, HIGH); delay(cz); digitalWrite(VCC, LOW); delay (op); name.set(b); digitalWrite(VC1, HIGH); delay(cz); digitalWrite(VC1, LOW); delay(op); name.set(c); digitalWrite(VC2, HIGH); delay(cz); digitalWrite(VC2, LOW); delay(op); czas_oczekiwania--; } } Próbowałem zrobić aby zamiana wartości z kodu Ascii wykonywała się w pętli for i wpisywała do tablicy sama, jednak coś nie gra. Moje leonardo się wieszało albo nie było żadnej reakcji. Kod obliczeń i wpisywania do tablicy int: char tablica1[4]; int tablicaliczb[4]; dtostrf(napiecie,4,2,tablica1); for(int i=0; i<sizeof(tablica1); i++) { for(int j = 0; j<sizeof(tablicaliczb); j++) { tablicaliczb[j]=tablica1[i]-48; } } Czemu tak się dzieje? Na monitorze portu szeregowego dla tablica1 dostawałem różne dziwne znaki. Jak powinienem poprawnie to zrobić? Dzięki Marek za pomoc, w sumie przy tym projekcie dużo się nauczyłem i nie uporał bym się z nim prawdopodobnie bez Twojej pomocy 😉 Pozdrawiam. Cytuj Link do komentarza Share on other sites More sharing options...
marek1707 Kwiecień 20, 2017 Udostępnij Kwiecień 20, 2017 Niepotrzebnie zagnieździłeś pętle. Przecież wystarczy raz przejechać przez wszystkie cyfry. I zamiast 16-bitowych int'ów używaj krótszego typu byte, w mikrokontrolerach każdy kawałek pamięci się liczy. No i staraj się unikać magicznych liczb rozrzuconych po kodzie, ale znaczących to samo. Gdybyś Ty za pół roku (albo ktoś inny używający jutroTwojego kodu) chciał zmienić długość/format wypisywanej liczby np. z obecnego 4/2 na 5/2, to które czwórki w kodzie ma zmienić, w ilu miejscach i czy wszystkie czwórki jakie znajdzie odpowiadają za to samo? Musiałby zająć się analizą działania całego programu. To zły pomysł. #define CYFRY 4 char tablica_znakow[CYFRY]; byte tablica_liczb[CYFRY]; dtostrf(napiecie, CYFRY, 2, tablica_znakow); for(int i=0; i<CYFRY; i++) tablica_liczb[i] = tablica_znakow[i] - '0'; Odejmowanie dziwnej stałej 48 nic nikomu nie powie. Warto pisać tak, by kod cokolwiek wyjaśniał. Może nawet tak: tablica_liczb[i] = ascii2bin(tablica_znakow[i]); definiując wcześniej funkcję: byte ascii2bin(char ch) { return (byte)(ch - '0'); } Wtedy każdy czytający Twój kod (przecież nie piszesz go dla kompilatora, jemu jest wszystko jedno jak to wygląda) od razu zrozumie co się dzieje i co chciałeś zrobić. Poza tym powyższe kody nie sprawdzają poprawności znaków. Gdyby w łańcuchu znaków zdarzyła się kropka, konwersja ascii2bin() odejmująca od wszystkiego kod 0x30 zrobi z niej kaszanę. Jeśli miałbyś napisać (bo dlaczego nie?) uniwersalną funkcję wypisującą skonwertowany w dowolnym formacie float na wyświetlacz 7-seg, to musiałbyś jeszcze analizować pozycję kropki i ew. spacji. Przymierz się do tego - tak dla sportu 🙂 Cytuj Link do komentarza Share on other sites More sharing options...
Pomocna odpowiedź
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!