Skocz do zawartości

ADC to UART to PC


drakul12

Pomocna odpowiedź

Cześć

Mam problem i potrzebuję pomocy, aby się dowiedzieć, czy da się to jakoś sensownie rozwiązać.

Do pewnego projektu, który wykonuję, potrzebuję ADC, więc wpadłem na pomysł wykorzystania ADC z arduino UNO. Ogarnąłem, że:

f_CPU = 16Mhz
f_zegaraADC= 125khz (dla prescalera 128)
czyli f_próbkowania=9,62khz (czas konwersji 13cykli dla trybu Free Running)

Czestotliwosc próbkowania jest graniczną, którą mogę wykorzytać, bowiem chcę badać sygnał do czestotliwosci ~4,5khz. Wynika to z częstotliwosci Nyquista.

Problem jednak pojawia się przy przesyle danych na komputer. Domyślam się, że przesył przez UART będzie wąskim gardłem, jednak nie wiem jak bardzo. Zamysł pierwotny był taki, że dokonuje się konwersja ADC, a potem od razu przesylamy to na PC, druga konwersja, drugi przesył itd. Jednak nie wiem jak to zrobić. Próbowałem w przerwaniu od ADC wysyłać przez UART, jednak wtedy w czasie przesyłania, ADC moze przetworzyc kilka probek, które się zgubią. Nie wiem, jak zrobić tak, żeby nie gubić próbek z ADC i żeby zdążyć je wysłać do komputera.

 

 

Link do komentarza
Share on other sites

Może zacznij od postawienia pytania czy w ogóle to się da zrobić a dopiero potem martw się o szczegóły implementacji. Masz zatem do przesłania 9.62k próbek/s z których każda jest wynikiem konwersji, zakładam 10-bitowej. UART wysyła dane w paczkach po 8 bitów, ale dodaje swoje bity 2 "opakowania". Twoje 10 bitów musi być zatem wysłane jako dwa bajty czyli 20 bitów. To daje już strumień 192kbity/s. Typowy port szeregowy PC pracuje z pewnymi standardowymi prędkościami (wiesz jakimi?) i niektóre z nich są nawet wyższe niż tutaj policzone. Kłopot w tym, że Arduino musi umieć je "wyprodukować". W procesorku ATmega masz UART, którego prędkość określana jest podzielnikiem głównego zegara - sposób dzisiaj już dość prymitywny, choć wciąż powszechny. Niestety dysponujesz zegarem tylko 16MHz, który UART od razu dzieli przez 16. Możesz wybrać pewien tryb "turbo" i wtedy masz podział przez 8 (plus pewne wady) i załóżmy, że go wybrałeś. Zatem za pomocą liczb/podzielników naturalnych musisz zejść z 2MHz do pożądanej szybkości pracy portu w PC. Sam sprawdź, czy to możliwe, bo to, że 16MHz procesor bez problemu poradzi sobie z kotłowaniem danych z ADC do UARTa nie mam wątpliwości.

  • Lubię! 1
Link do komentarza
Share on other sites

(edytowany)

Nie do końca zrozumiałem

Typowy port szeregowy to nie tylko UART, ale także USB, jednak atmega natywnie tego nie wspiera, co zmusza do korzystania z wbudowanego w Arduino konwertera uart->USB .

Predkosci UARTa, to typowe 9600...115200, nie widziałem chyba wykorzystania szybszej. We wszystkich programach ciągle jest uzywane 9600... 

Ten tryb "turbo", o to Ci chodzi? "Normal asynchronous, Double Speed asynchronous, Master synchronous and Slave synchronous mode" znalazlem w datasheet

x2.thumb.png.f4a7eebac15a1c02d9684dfb94760a47.pngx3.thumb.PNG.da91ead7a3cd4ff5ac9be5620d10040a.PNGx2.png

@edit_0
Ok, znalazłem jak to zrobić, podwoić szybkość przesyłu UARTa, czyli zmiejszyć dzielnik z 16 na 8, tak jak mówiłeś. Jednak nie bardzo rozumiem, na co to się przekłada w praktyce, te Twoje "pewne wady". 

x3.PNG

@edit_1
Na drugim zdjęciu zaznaczyłem błędy związane z szybkością transmisji, które mnie interesują. Akwizycja danych w moim przypadku, jest z pewnego czujnika ICP, więc błąd na poziomie 3,5% może być kwestionowany w moim konkretnym zastosowaniu. Myślałem także o ewentalnej zmianie kwarcu w Arduino, ale to na razie zostawmy w spokoju.

@edit_2
ok, według przykładowego kodu w datasheet uruchomiłem uarta, zamiast typowej intrukcji w Arduino Serial.begin(9600). Zmieniłem tryb na ten 2x szybszy. Ale nie widzę różnicy, skoro poza tym rejestrem U2X0=1, zmienił się tylko rejestr UBRR0 na wartość z nowego przelicznika. 

x1.PNG

Edytowano przez drakul12
Link do komentarza
Share on other sites

Anonim
3 godziny temu, drakul12 napisał:

Predkosci UARTa, to typowe 9600...115200, nie widziałem chyba wykorzystania szybszej. We wszystkich programach ciągle jest uzywane 9600... 

Osiągnąłem max 2Mbps na 1m kablu tylko na zewnętrznym konwerterze bo te na płytkach są do.. mniejszych prędkości. Kwestia odpowiedniego podejścia programowego. 97% - 98% prawidłowych ramek.

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

Nie zrobiłeś najwazniejszego czyli oszacowania czy możesz z kwarcu 16MHz uzyskać zadowalającą prędkość UARTa, która będzie pasowała do portu w PC. Obies strony muszą przecież pracować z tą samą prędkością. W zależności od implementacji, w kompie można ustawiać czasem prawie dowolnie a czasem wybierać z bardzo ograniczonego zestawu prędkości, np (pomijając te małe, które dla Ciebie są bezużyteczne) masz: 115200, 230400, 460800 i 921600. A teraz zrób którąś z nich dzieląc 2MHz przez liczbę całkowitą. Oczywiście im mniejsza prędkość tym łatwiej dobrać podzielnik, ale wszystko poniżej 192000 Cię przecież nie interesuje, bo tyle danych masz do przesłania w sekundzie. Protokół UART dopuszcza delikatne różnice w prędkościach obu współpracującyh stron, ale powinien on być mniejszy niż kilka procent i został on policzony w tabelce którą zamieściłeś. Ta różnica nie ma nic wspólnego z błędami wielkości przesyłanych liczb czy innych danych. Po prostu dla błędu prędkości mniejszego od kilku procent UARTy po dwóch końcach kabelka "dogadają się" i dane będą przechodzić poprawnie a powyżej 5-10% nie masz szans na nawiązanie w ogóle jakiegokolwiek połączenia i praktycznie wszystko co odbierze druga strona będzie jedną wielką bzdurą.

I nie, USB nie nazywamy portem szeregowym, mimo że transmisja idzie po jednej parze różnicowej a więc szeregowo. Nazwa "port szeregowy" jest w PC zarezerwowana dla portów COM/RS232, czyli złącz DB9 występujących w starych kompach lub w nowszych komputerach tzw. przemysłowych (choć i tu coraz rzadziej). Procesor Arduino ma swój UART podłączony przez konwerter do USB, ale na tym krótkim odcinku, na płytce Arduino, UART procesora musi dogadać się z UARTem konwertera na jakiejś standardowej, takiej samej dla obu stron prędkości. Oczywiście dalej, już na USB nie ma po niej śladu bo sprzętowo USB jest tak odległe od protokołu UART jak stąd do Paryża.

Jeszcze jedno: funkcja Serial.begin() nie robi żadnej magii więc nie może wypodukować dowolnej prędkości jaką wpiszesz, bo jest ograniczona sprzętowym UARTem procesora Arduino a ten ma cechy o których już wiesz. Jeżeli więc np. Twój PC będzie wymagał prędkości np. 230400 to żebyś nie wiem jak się starał nie wygenerujesz jej z małym błędem z kwarcu 16MHz. Nie mówiąc już o 460800. Do takich "dziwnych", lecz wciąż standardowych prędkości używa się "nierównych" kwarców np. popularnego 11.0592MHz. Spróbuj podzielników całkowitych na nim.

  • Lubię! 1
Link do komentarza
Share on other sites

W Arduino tryb U2X powinien się włączać automatycznie (znaczy biblioteka wylicza kiedy trzeba tego użyć). Kwarc 16MHz preferuje prędkości typu 250/500/1000kb, to nie jest takie trudne znaleźć odpowiedni adapter, np.  FTDI, właśnie testuje i działa OK na 1Mbit, 500k, 250k. Tak samo Leonardo bez problemu nadaje z taką prędkością do PC przez swój "UART" USB. Co ciekawe w przypadku portu USB Atmegi (Arduino Micro) wybór prędkości w terminalu jest nieistotny.

Link do komentarza
Share on other sites

Anonim

Jeśli chcesz osiągnąć na prawdę duże prędkości zapomnij o "automatycznie" i "biblioteka arduino" tak samo o konwerterze n a płytce. Za swój konwerter dałem kilka złotych. Podłącza się go pod port bezpośrednio a efekty jak pisałem. Zauważ też że ten wyliczony błąd dla wyższych prędkości zmniejsza się przy kwarcu 16MHz. Zobacz tabelę prędkości usart w DS od atmegi. Przyjemnego wyścigu z czasem 🙂

Link do komentarza
Share on other sites

No tak, ale Autor a) zamierza użyć UNO a tam jest wbudowany konwerter pracujący o ile dobrze pamiętam tylko do 115200, b) chyba nie do końca ogarnia temat, c) być może niezbyt precyzyjnie opisał problem albo ja go źle zrozumiałem. Np. nie wiemy, czy pomiary ADC bedą wykonywane ciągle - bo wtedy trzeba wysyłać wszystko co się zmierzyło i transfer po UART musi być wyższy niż ilość napływających z ADC wyników. A jeśli np. pomiary będa wykonywane szybko, ale w paczkach po kilkaset, to procesor może je zwyczajnie zbuforować w RAMie a w chwili przerwy wysłać już na spokojnie dane do PC, niechby i na 9600.

Link do komentarza
Share on other sites

4 minuty temu, marek1707 napisał:

No tak, ale Autor a) zamierza użyć UNO a tam jest wbudowany konwerter pracujący o ile dobrze pamiętam tylko do 115200, b) chyba nie do końca ogarnia temat, c) być może niezbyt precyzyjnie opisał problem albo ja go źle zrozumiałem. Np. nie wiemy, czy pomiary ADC bedą wykonywane ciągle - bo wtedy trzeba wysyłać wszystko co się zmierzyło i transfer po UART musi być wyższy niż ilość napływających z ADC wyników. A jeśli np. pomiary będa wykonywane szybko, ale w paczkach po kilkaset, to procesor może je zwyczajnie zbuforować w RAMie a w chwili przerwy wysłać już na spokojnie dane do PC, niechby i na 9600.

Ad.a)  taki miałem zamiar 😉  Próbowałem przesyłać z większą prędkością, czyli 250kb, i działało, ale nie do końca. Tzn sam przesył szedł, ale kiedy ograniczyłem sampling poprzez sztuczny prescaler w przerwaniu od ADC, więc wynikowy sampling, który odebrałem "bez straty", był 8albo9 razy mniejszy, czyli ok1khz z adc (liczyłem na 9,6 na początku jak się wziąłem za to ogarnianie)

Ad.b) owszem, nie do końca ogarniam temat, ale mocno próbuję 😉 niestety nie jest to łatwe, więc chętnie posłucham kogoś, kto ma większą wiedzę ode mnie 🙂

Ad.c) Pomiary z ADC mają być ciągłe i ciągłe ma być przesyłanie

Link do komentarza
Share on other sites

Anonim

Zgadza się, dlatego bawiąc się arduino warto mieć zewnętrzny konwerter. Swego czasu też się tak z usartem zmagałem na atmedze aż się uparłem i samą siłą uporu wycisnąłem z niego co się da. 2 mibsy to sensowny max. nawet kwarc 18.432MHz nie umożliwia takiej prędkości ale za to oferuje zdecydowanie wyższą jakość przy niższych prędkościach no i prędkość procka ponad normę. Wg noty przy 2Mbps błąd wynosi 0% praktycznie tak jak pisałem ale to być może wina kabla od starej myszki.

Link do komentarza
Share on other sites

No też nie wiem co ma autor, natomiast z ESP8266 używałem jeszcze CH340 i CP21xx i oba moduły oferują znacznie więcej niż 115200, nie ma problemu by soft uploadować z prędkością ~900k. CP21xx kończy się przy około 900k, ale ma do wyboru 250 i 500k, a CH340 ma max 2Mbit, za to brakuje mu prędkości 250, 500 i 1000k. Oba zresztą mają dużo krótszą listę dostępnych baudrate niż FTDI, gdzie jest dla "uproszczenia" podany wzór by wyliczyć jakie są możliwe. W oryginalnym Arduino UNO jest konwerterem Atmega z USB, kwarc 16MHz  więc tu dla dowolnej prędkości UART błąd jest 0% (między Atmegami, kwestia czy Atmega prześle to dalej na USB).

Wg mnie nie ma co narzekać na to co jest do wykorzystania w Arduino i jego klonach.

Link do komentarza
Share on other sites

(edytowany)
12 minut temu, kaczakat napisał:

No też nie wiem co ma autor, natomiast z ESP8266 używałem jeszcze CH340 i CP21xx i oba moduły oferują znacznie więcej niż 115200, nie ma problemu by soft uploadować z prędkością ~900k. CP21xx kończy się przy około 900k, ale ma do wyboru 250 i 500k, a CH340 ma max 2Mbit, za to brakuje mu prędkości 250, 500 i 1000k. Oba zresztą mają dużo krótszą listę dostępnych baudrate niż FTDI, gdzie jest dla "uproszczenia" podany wzór by wyliczyć jakie są możliwe. W oryginalnym Arduino UNO jest konwerterem Atmega z USB, kwarc 16MHz  więc tu dla dowolnej prędkości UART błąd jest 0% (między Atmegami, kwestia czy Atmega prześle to dalej na USB).

Wg mnie nie ma co narzekać na to co jest do wykorzystania w Arduino i jego klonach.

Mam dokładnie taki model:

https://allegro.pl/oferta/klon-arduino-uno-r3-ch340-avr-atmega328-7813463878

Edytowano przez drakul12
Link do komentarza
Share on other sites

1 godzinę temu, drakul12 napisał:

Próbowałem przesyłać z większą prędkością, czyli 250kb, i działało, ale nie do końca. Tzn sam przesył szedł, ale kiedy ograniczyłem sampling poprzez sztuczny prescaler w przerwaniu od ADC, więc wynikowy sampling, który odebrałem "bez straty", był 8albo9 razy mniejszy, czyli ok1khz z adc (liczyłem na 9,6 na początku jak się wziąłem za to ogarnianie)

Nic z tego nie rozumiem oprócz tego, że coś spaprałeś. Zrób jeden prosty eksperyment: napisz prosty program ustawiający prędkość na 250000 albo 500000 (Serial.begin + Serial.printf itd) i przesyłający coś do kompa, jakieś "Akuku!" czy cokolwiek. Jeżeli jesteś to w stanie odebrać na monitorze portu szeregowego w Arduino IDE to znaczy, że transmisja działa i możesz przesyłać setki kilobitów na sekundę. Wtedy wystarczy jedynie oprogramować ADC i zrobione. W Arduino podstawowa biblioteka Serial ma buforowanie nadawania i odbioru i działa na przerwaniach więc nie zabiera czasu procesora na oczekiwanie. Pokaż jak zrobiłeś pomiary i jak wypisujesz wyniki i pewnie szybko się wyjaśni co poszo źle. Skoro potrzebujesz transferu "jedynie" 192k a okaże sę, że możesz działać np. na 500k to nie ma walca żeby nie dało się tych próbek przesyłać na bieżąco.

Pytanie pomocnicze: co ma odbierać dane po stronie kompa? Jakiś program terminalowy, Twoja własna aplikacja czy jakiś gotowiec?

Link do komentarza
Share on other sites

#include <AVR/io.h>      //biblioteka wejść/wyjść
#include <AVR/interrupt.h>    //biblioteka dotycząca przerwań
#include <util/delay.h>     //biblioteka zawierająca instrukcje opóźnień

volatile unsigned int wynikADC[500];
volatile unsigned int cnt;
volatile unsigned char i;
volatile unsigned char presc;
//************przerwanie od ADC***********************************************************************************************
ISR(ADC_vect)
{
  presc++;
  if(presc>6)
  {
    wynikADC[cnt++]=ADC;
    presc=0;
  }
}

void setup() {
  // put your setup code here, to run once:
//-----------------konfiguracja ADC--------------------------------------------------------------------------------------------
ADCSRA |= (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2); //preskaler 128 czyli f_zegara 125kHz, ale f_ADC=8,62kHz
              
ADMUX |=  (1<< REFS0);     //źródło odniesienia AVcc=5V
ADMUX &=  ~(1<< REFS1);    //źródło odniesienia AVcc=5V
ADMUX &=  ~(1<< MUX0);    //A0
ADMUX &=  ~(1<< MUX1);    //A0
ADMUX &=  ~(1<< MUX2);    //A0
ADMUX &=  ~(1<< MUX3);    //A0

ADCSRA |= (1<<ADEN);       //włączenie przetwornika ADC
ADCSRA |= (1<<ADIE);       //włączenie przerwania od ADC
ADCSRA |= (1<<ADATE);      //tryb Free Running
ADCSRB &=~ (1<<ADTS0)&~(1<<ADTS1)&~(1<<ADTS2);

ADCSRA |= (1<<ADSC);       //start pierwszej konwersji
sei();
Serial.begin(115200);

}

void loop() {
  // put your main code here, to run repeatedly:

//
 if(cnt>0)
 {
    Serial.println(wynikADC[i]);
    //Serial.println(cnt);
    i++;
    
    if(i==cnt){cnt=0;i=0;}
 }
 
}

 

Po stronie komputera dane ma odbierać DasyLab. Niestety spostrzegłem się, że umożliwia on jedynie odbiór do 115200, więc może wykorzystam inny program, albo sam już nie wiem, trochę zmęczony już jestem 😄  Na razie chciałbym to jakkolwiek ogarnąć, żeby przesyłać całość i nie gubić danych.

Link do komentarza
Share on other sites

No - w ten sposób to na 100% nie osiągniesz takiej prędkości. Zamiast dwóch przesyłasz w porywach sześć bajtów na próbkę (bo przecież to robi println, prawda?).

Teoretycznie da się zrobić to co chcesz, o ile:

a) ograniczysz się do 8-bitowych próbek

b) użyjesz binarnej transmisji (czyli Serial.write(), a po stronie odbierającej coś sobie naskrobiesz).

Przy okazji zainteresuj się makrami typu ATOMIC.

 

  • Lubię! 1
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.