Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Computer Controls
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

EvB 4..3 - Zbieranie danych z określoną częstotliwością

mikroice90 19 Gru 2012 12:14 3567 37
  • #1 19 Gru 2012 12:14
    mikroice90
    Poziom 13  

    Witam,

    piszę program, który zbiera bity do pełnego bajtu z określonego pinu i wystawia je po ośiągnięciu 8b na UART. UART jest ustawiony na pracę 1Mb. Problem polega na tym, że użytkownik ma mieć możliwość z software;u podawania prędkości zbierania bitów np. żeby zbierać z f=(1Hz-1MHz). Jak zrealizować taką strukturę na mikrokontrolerze?

    Dziękuję z góry za pomoc

    0 29
  • Computer Controls
  • #3 19 Gru 2012 13:33
    mikroice90
    Poziom 13  

    chodzi o to jak przesłać z aplikacji liczbę od 1-1000000. 10^6 da się zapisać na 20 pozycjach dwójkowo. Zatem chciałem po prostu odebrać tą wartość(odbieranie jest po bajcie i tu mam problem jak zapisać 20 bitów, żeby potem przekonwertować to na system 10). i jak już będę miał to w dziesiętnym (int czestotliwosc)to wtedy

    for(i=0;i<czestotliwosc;i++)
    _delay_ms(0.001)

    0
  • #4 19 Gru 2012 13:49
    BlueDraco
    Specjalista - Mikrokontrolery

    Mikrokontroler nie przechowuje liczb w systemie dziesiętnym, a w reprezentacji binarnej, więc nic nie musisz konwertować. Zbieranie danych musi być na przerwaniu timera. Jeżeli chcesz wejść w częstotliwości ok. 1 MHz, to trzeba to dobrze przeliczyć. 8-bitowiec tu nie da rady, a Cortex M3 ledwie da radę albo i nie. Trzeba bardzo uważnie zaprojektować procedurę obsługi przerwania.
    O jakim procesorze mówimy?

    0
  • #5 19 Gru 2012 13:52
    mikroice90
    Poziom 13  

    ATmega32
    wg Datasheetu przy oscylatorze wewnętrznym 16MHz maksymalna prędkość UART jest równa 1Mbaud

    0
  • Computer Controls
  • #7 19 Gru 2012 14:07
    mikroice90
    Poziom 13  

    Mogę wysyłać na 3 sposoby:

    port.Write(String)
    port.Write(Byte[], Int32, Int32)
    port.Write(Char[], Int32, Int32)

    0
  • #8 19 Gru 2012 14:16
    BlueDraco
    Specjalista - Mikrokontrolery

    Człowieku, to nie o UART chodzi, a o to, co musi zrobić program, żeby skompletować i wysłać daną. Przy 16 MHz bez procedur i bez przerwań masz na to realnie jakieś 10 instrukcji głupiutkiego procesora.
    Można próbować coś kombinować z użyciem interfejsu SPI do próbkowania danych, ale i tak będzie trudno się wyrobić nawet na poziomie asemblera - język wysokiego poziomu praktycznie wykluczony. To nie jest zadanie dla zabawkowego mikrokontrolerka.

    0
  • #9 19 Gru 2012 14:25
    szulat
    Poziom 23  

    pewnie da się wykorzystać do tego SPI, dzięki temu zamiast pobierać 1 bit z wejścia co 1µs procesor musiałby tylko czytać z rejestru wejściowego SPI 1 bajt co 8µs - przy tej metodzie 1MHz, a może i więcej, nie powinno być problemem.

    niestety w ten sposób nie uzyska się dowolnej częstotliwośc próbkowania a tylko takie które można ustawić w SPI. być może da się to ominąć dodatkowo przetwarzając odebrane bajty żeby ominąć niechciane bity (ale dodatkowego przetwarzania chcemy jednak unikać żeby procesor nadążył), albo możesz wysyłać wszystko a omijać co N-ty bit dopiero w programie który je odbiera.

    0
  • #10 19 Gru 2012 14:25
    mikroice90
    Poziom 13  

    Może i nie jest, w każdym razie przy UBRR = 0 producent podaje komunikację na poziomie 1Mbaud. Aplikacja w C# gdzie port.baudRate = 1000000 przyjmuję poprawnie taką komunikację. Problem jest innej natury i został opisany powyżej.
    Jeśli chodzi o przerwanie USART_RXC_vect to np. 0x80-rozpocznij zbieranie danych, 0x81-zakończ zbieranie danych, więc zamierzam wysylać 0xFF jako bajt startu do odbierania częstotliwości zbierania, tylko teraz:
    Mam załóżmy dla skupienia uwagi do wysłania zmienną o wartości 1000000, jak wysłać spod C# i jak odebrać i zapisać do choćby int'a tą częstotliwośc?
    Czy _delay_ms(1000000* 0.001) da rzeczywiście opóźnienie 1s?

    0
  • #11 19 Gru 2012 14:43
    szulat
    Poziom 23  

    mikroice90 napisał:
    Mam załóżmy dla skupienia uwagi

    skupiasz uwagę na rzeczach zupełnie nieistotnych ;)
    jeżeli liczbę przesyłasz przez uart jako tekst to możesz ją z powrotem zamienić na liczbę funkcją atoi() lub atol()
    http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html

    mikroice90 napisał:
    Czy _delay_ms(1000000* 0.001) da rzeczywiście opóźnienie 1s?

    da takie opóźnienie ale w niczym ci to nie pomoże bo parametrem _delay_ms musi być stała a nie zmienna, a po drugie, powiedzmy że jednak masz funkcję delay(liczba_mikrosekund), wtedy i tak użycie jej w programie nie zapewni stałego odstępu między pobieraniem kolejnych bitów bo operacje wywoływane pomiędzy delayami też zajmuja czas i w dodatku nie zawsze tyle samo czasu

    0
  • #12 19 Gru 2012 14:46
    BlueDraco
    Specjalista - Mikrokontrolery

    1. Wysyłaj albo obliczony na PC podzielnik dla timera, albo okres próbkowania w us, a nie częstotliwość. 16-bitowy podzielnik możesz wysłać np. tak: send_byte(x); send_byte(x >> 8);, zakładając, że masz funkcję send_byte, która wysyła daną przez RS232.

    2. Zapomnij o używaniu jakichkolwiek wartości zmiennopozycyjnych w programie dla uC.

    3. Zapomnij o języku wysokiego poziomu dla uC, albo zmień procesor na jakiegoś Cortexa.

    4. Zapomnij o użyciu funkcji delay() do odmierzania okresu próbkowania danych.

    Problemy w Twoim projekcie są zupełnie inne, niż Ci się to wydaje - czytaj odpowiedzi, których dobrzy ludzie udzielają.

    0
  • #13 19 Gru 2012 14:47
    mikroice90
    Poziom 13  

    to np wysyłam z aplikacji port.Write("1000000")
    jak widzi to USART_RXC_vect?

    0
  • #14 19 Gru 2012 14:53
    BlueDraco
    Specjalista - Mikrokontrolery

    UART odbiera kolejno 7 znaków ASCII, z których możesz poskładać 32-bitową liczbę, z której będziesz miał znikomy pożytek.
    Jeśli o to pytasz, tu znaczy, że nie dasz sobie na razie rady z tym projektem. Zacznij dostrzegać problem tam, gdzie on naprawdę jest.

    0
  • #15 19 Gru 2012 15:23
    mikroice90
    Poziom 13  

    częstotliwość w tym wypadku jest rozumiana jako okres próbkowania.
    Dlaczego nie powinienem użyć funkcji delay()
    Co do SPI, zadanie zostało określone do wykonania na RS-232

    0
  • #16 19 Gru 2012 15:47
    szulat
    Poziom 23  

    mikroice90 napisał:
    Dlaczego nie powinienem użyć funkcji delay()

    było!
    szulat napisał:
    bo operacje wywoływane pomiędzy delayami też zajmuja czas i w dodatku nie zawsze tyle samo czasu


    mikroice90 napisał:
    Co do SPI, zadanie zostało określone do wykonania na RS-232

    SPI byłoby używane tylko do pobierania bitów a wysyłasz dalej na RS

    0
  • #17 19 Gru 2012 15:50
    BlueDraco
    Specjalista - Mikrokontrolery

    1. Bo zamiast delay() potrzebujesz funkcji turn_back_time(), która spowoduje cofnięcie czasu, dzięki czemu Twój procesor być może zdąży spróbkować daną i przygotować ją do wysłania.

    2. SPI to jedyna (chociaż niepewna) szansa na spróbkowanie danych, które masz czytać i potem wysyłać po UART. Nie da się próbkować stanu wejścia programowo z okresem 1 us i jeszcze coś robić z odczytaną informacją. Dotarło wreszcie?

    Twoje pytania brzmią mniej więcej jak:
    "Do jutra muszę przewieźć 100 ton kamieni na drugi koniec miasta. Powiedzcie mi, jak wkłada się kluczyk do stacyjki mojego skutera. Reszta mnie nie obchodzi, tylko co z tym kluczykiem."

    0
  • #18 19 Gru 2012 15:53
    mikroice90
    Poziom 13  

    To powiem konkretniej:
    Do pinu mikrokontrolera jest podłączony generator losowy oparty o złącze p-n spolaryzowane w kierunku zaporowym. Emituje on sygnał na pin z określoną częstością. Zadaniem mikrokontrolera jest z określoną przez użytkownika częstotliwościa zbierać(odczytywać) sygnał z pinu i gdy uzbiera się cały bajt wysyłać go UART-em z prędkością 1Mbaud do PC.

    0
  • #19 19 Gru 2012 15:57
    BlueDraco
    Specjalista - Mikrokontrolery

    Powtórzę jeszcze konkretniej: na 100 MHz Cortexie jakoś powinno się to dać zrobić, chociaż całkiem łatwo nie będzie.

    Zbieranie danych po wejściu SPI to jedyna szansa na podejście do tego na ATmega, przy zmniejszeniu częstotliwości próbkowania i bardzo uważnym programowaniu w asemblerze.

    0
  • #20 19 Gru 2012 16:03
    mikroice90
    Poziom 13  

    Prawdopodobnie użyteczne częstotliwości będą zakresu do 16kHz.
    Jednak sam program ma być przenoszalny więc ma obsługiwać "możliwość" użycia 1MHz.
    Możesz mi pomóc jak zorganizować ustalanie częstotliwości pomiędzy PC a uC?

    0
  • #21 19 Gru 2012 16:07
    BlueDraco
    Specjalista - Mikrokontrolery

    Lepiej pomyśl o liczbie kursów skuterka, torbach na kamienie, czasie potrzebnym na przejazd i kosztach paliwa. Ten kluczyk, to naprawdę najmniejszy kłopot, taki dla początkującego programisty. Kluczyk do skuterka raczej nie będzie pasował do lokomotywy.

    0
  • #22 19 Gru 2012 21:31
    szulat
    Poziom 23  

    BlueDraco napisał:
    Powtórzę jeszcze konkretniej: na 100 MHz Cortexie jakoś powinno się to dać zrobić, chociaż całkiem łatwo nie będzie.

    hehe, myślałem że tak, ale jednak nie!
    tego się nie da zrobić ani na 100MHz ani na miliard GHz - bo założenia są sprzeczne :P
    po prostu nie można wysłać miliona próbek na sekundę przez RS232 przy szybkości 1Mbps bo 1/5 z tego zajmą bity startu i stopu...

    ale załóżmy że autor pogodzi się z mniejszą częstotliwością próbkowania albo przyspieszy RS albo nie przeszkadza mu gubienie co 5 bajtu (przy danych losowych to może być bez znaczenia), wtedy to może być prawda że na 100MHz procku da się to zrobić metodą naiwnego ale łatwego do ogarnięcia programowania typu delay i zbieranie po bicie, tylko że to nigdy nie będzie naprawdę dobre rozwiązanie bo nie gwarantuje stałej częstotliwości (ale może to też nie przeszkadza w tym zastosowaniu).

    a na atmedze... ciekawie byłoby sprawdzić jaką maksymalną szybkość próbkowania jednobitowego da się osiągnąć. faktyczna przepustowość w bajtach to przecież tylko 1/8 częstotliwości, 1 MHz to bardzo mało jeżeli poza tym procesor nie ma wiele do roboty.

    0
  • #23 19 Gru 2012 21:43
    BlueDraco
    Specjalista - Mikrokontrolery

    Ech, czepiasz się takich drobiazgów jak format danych UART - no to dorzućmy jeszcze odstępy bajtów niezbędne co jakiś czas do resynchronizacji...
    Właściwie na początek wypadałoby grzecznie poprosić PC o ustawienie szybkości 1 Mbps na RS232, potem już pójdzie jak z płatka. ;)
    Alternatywnie można namówić 16 MHz Atmega na ustawienie 921600, zapewne z podobnym skutkiem.

    A na M3 oczywiście dałoby się to zrobić na timerze, ale chyba lepiej na SPI, tym bardziej, że ma szersze możliwości programowania częstotliwości transmisji.

    0
  • #24 19 Gru 2012 23:35
    dejmos
    Poziom 23  

    Ale po co tak szybko chcesz to wysyłać do PC? Nie może być wolniej? Możesz to zrobić tak, że uC zbiera sobie z określoną częstotliwością te liczby do jakiejś tablicy a w międzyczasie z prędkością np 115200 komunikuje się z PC i przesyła mu dane zgromadzone w tablicy.
    Druga sprawa to to że jest to generator oparty o złącze p-n czyli jakiś pseudolosowy więc myślę że jeżeli co jakiś czas przerwiesz ( bo to chyba u Ciebie determinuje taką prędkość komunikacji, aby nie przerywać zbierania tych liczb losowych) zbieranie tych liczb i w tym czasie wyślesz to do PC to nic się nie stanie bo... to są liczby losowe więc czy w tej czy w następnej ms będziesz je zbierał to i tak za bardzo nie wpłynie na wynik .

    0
  • #25 20 Gru 2012 00:36
    mikroice90
    Poziom 13  

    Rozumiem wszystkie wasze spostrzeżenia i sugestie. To rozwiązanie nie musi być ani dobre ani efektywne, po prostu ma działać. Celem zadania jest znalezienie optymalnej częstotliwości próbkowania. Czy program jak poniżej ma szansę działać?

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Przesyłanie częstotliwości staram się zrealizować w ten sposób że wysyłam z aplikacji 0xFF jako bajt startu przesyłania częstotliwości. Następnie będę zbierał do tablicy 7-kolejnych wartości a bajt stopu jest 0xFE. Dalej jw
    [/code]

    0
  • #26 20 Gru 2012 01:43
    szulat
    Poziom 23  

    mikroice90 napisał:
    Czy program jak poniżej ma szansę działać?

    na pierwszy rzut oka jest okej.
    niepotrzebnie robiłeś funkcje przelicz(), wystarczy wywołać gotową funkcję atol(char*) (a wcześniej zadbać żeby ciąg cyfr kończył się bajtem zerowym). w dodatku w tej funkcji przelicz() traktujesz kolejne cyfry jak gdyby były bajtami o wartościach 0..9 podczas gdy w rzeczywistości będą to kody ascii tych cyfr. tym bardziej warto użyć atol.

    0
  • #27 20 Gru 2012 02:24
    mikroice90
    Poziom 13  

    Program istotnie działa, jednak wysyła on dane ze stałą prędkością niezależnie od podanej częstotliwości. Może właśnie problemem jest funkcja przelicz(). Mógłbyś podać przykład tego rozwiązania z atol?

    0
  • #28 20 Gru 2012 02:38
    szulat
    Poziom 23  

    mikroice90 napisał:
    Mógłbyś podać przykład tego rozwiązania z atol?

    coś w tym stylu:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #29 20 Gru 2012 09:18
    BlueDraco
    Specjalista - Mikrokontrolery

    Na moje oko nic w tym programie, który przedstawiłeś, nie ma prawa działać poprawnie., za to na pewno będzie działać wolno.

    Stan wejścia próbkowany jest w różnych, trudnych do określenia odstępach czasu.
    Błędna metoda konwersji liczby dziesiętnej - działa, ale karykaturalnie.

    Wciąż nie dociera do Ciebie to, że na wykonanie każdej instrukcji procesor potrzebuje jakiegoś czasu, a na wywołania procedur, mnożenia itp - kilku mikrosekund.

    0
  • #30 20 Gru 2012 10:39
    mikroice90
    Poziom 13  

    Z funkcją przelicz działa wolno ale działa, natomiast z atol już w ogóle nie wysyła danych. Problem musi być z wyliczaniem poprawnej wartości zmiennej częstotliwość, ponieważ nie ważne czy podam 1 czy 1000000 to okres wysłania bajtu jest taki sam.

    Blue rozumiem, nie zmienia to faktu że różnica w działaniu rzeczywistym a teoretycznym zostanie ustalona na podstawie odczytu z oscyloskopu jak tylko program zacznie funkcjonować zgodnie z założeniami. Więc proszę albo powiedz jak to poprawić albo już nie pisz w tym temacie.

    0