logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

ATmega48 - transmisja szeregowa

lukullus87 07 Sty 2010 14:16 2149 13
REKLAMA
  • #1 7498750
    lukullus87
    Poziom 11  
    Witam,
    chce uruchomić transmisje szeregową na podanym w tytule uC i tutaj napotkalem na problem, poniewaz dokumentacja do 48 jest bardzo uboga :/ Zaimplementowalem cos, ale nie dziala. Specyfikacja transmisji jest taka:
    - prędkość 9600 bodów
    - 8-bitowa ramka danych
    - 1 bit stopu
    - brak parzystosci
    - dane chce tylko odbierac
    Czy moglby mi ktos pomoc w implementacji tej transmisji? Z góry bardzo dziekuje:)

    pozdrawiam serdecznie
  • REKLAMA
  • Pomocny post
    #2 7498809
    mirekk36
    Poziom 42  
    lukullus87 napisał:
    Witam,
    chce uruchomić transmisje szeregową na podanym w tytule uC i tutaj napotkalem na problem, poniewaz dokumentacja do 48 jest bardzo uboga :/ Zaimplementowalem cos, ale nie dziala.


    jaka uboga? o czym ty mówisz ? skąd ty takie ubogie dokumentacje bierzesz?

    wejdź na stronę www.atmel.com i pobierz z tamtąd pełną notę PDF do jakiego zechcesz tylko procka AVR to po pierwsze

    po drugie to w każdej nocie, nawet innego czy podobnego procka AVR masz pokazane jak w najprostszy sposób nadawać i odbierać przez UART czy USART i to z przykładami w asemblerze oraz w języku C . Więc czego ci jeszcze potrzeba?

    no chyba, że łaskawie napisałbyś że ty potrzebujesz implementacji w jakimś konkretnym języku - może np w Bascomie? (żebyś chociaż pokazał coś ty już zaiplementował i ci nie działa to już można byłoby coś konkretnego podpowiedzieć)

    ale akurat w Bascomie to ty nawet w celu implementacji (jak to nazwałeś) odbioru przez RS232 - nie potrzebujesz noty PDF w ogóle ;) .... wystarczy ci zapoznać się z takimi poleceniami w Bascomie jak: Config Serialin oraz Input, lub Inkey czy Ischarwaiting
  • #3 7498920
    lukullus87
    Poziom 11  
    Mówiąc uboga mialem na mysli to, ze do ATmegi8 czy ATmegi16 dokumentacje sa znacznie bardziej dokladne, np. rejestr UCSRC w ATmedze8 jest dobrze opisany, a do ATmegi48 znlazlem tylko tyle, ze nazywa sie UCSR0C... , ale mniejsza o to. Mój kod wyglada tak:
    UCSR0C=(1<<UMSEL01) | (1<<UCSZ01) | (1<<UCSZ00);
    UBRR0L = 6;
    UCSR0B= (1<<RXEN0) | (1<<TXEN0);
    Czestotliwosc pracy ATmega48 wynosi 1MHz, dane odbieram z Matlaba, gdzie transmisa ustawiona jest standardowa, czyli taka jaka (wydaje mi sie) ustawilem na uC. Jesli ktos wie o co chodzi prosze o pomoc.
  • REKLAMA
  • Pomocny post
    #4 7498994
    AVRowiec
    Poziom 18  
    tutaj masz dobry kod na atmege8: (atmega48, 88, 168 troche sie różni rejestrami i są bardziej kłopotliwe ale to tylko kwestia podmiany nazw):

    Odbieranie koniecznie w przerwaniu!! jak dla mnie tylko taki sposób ma prawo bytu :)

    SIGNAL (SIG_UART_RECV) 
    { 
    
      odebranyZnak = UDR;  
    
      ....   <--- tu robisz sobie z tym znakiem co chcesz
    
    }


    Funkcje do wysyłania:

    void USART_Transmit(char data )
    {
    /* count for empty transmit buffer */
    while ( !( UCSRA & (1<<UDRE)) )
    ;
    /* Put data into buffer, sends the data */
    
    UDR = data;
    }
    /////////////////////////////////////////////////////
    void USART_Transmit_Word(char *slowo)
    {
       int n=0;
       while (slowo[n]) 
       { 
         USART_Transmit(slowo[n]);
    	 n++;
       }
    }


    Init:
    
    #define FOSC 8000000// Clock Speed
    #define BAUD 19200
    #define MYUBRR FOSC/16/BAUD-1
    void USART_Init( unsigned int ubrr)
    {
    /* Set baud rate */
    UBRRH = (unsigned char)(ubrr>>8);
    UBRRL = (unsigned char)ubrr;
    /* Enable receiver and transmitter */
    UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
    /* Set frame format: 7slowo, 2stop bit, Odd Parity */
    UCSRC = (1<<URSEL)|(3<<UCSZ0);
    }


    W main koniecznie na początku:

    sei();	
    USART_Init (MYUBRR);


    Jak chcesz coś wysłać to robisz:

    USART_Transmit_Word("słowo");


    Jak odebrać:

    to już gorzej, bo w przerwaniu trzeba by napisać coś co składa łańcuch z odebranego znaku. Ja to robie tak:

    SIGNAL (SIG_UART_RECV) 
    { 
      odebranyZnak = UDR; 
       // będzie składać slowo[] ze znaków różnych od:
    if ((odebranyZnak!=0x0D) && (odebranyZnak!=0x0A)
         && (odebranyZnak!=' ')&& (odebranyZnak!=',') && (odebranyZnak!='$')) 
      {
         slowo[i]=odebranyZnak;
    	 i++;
      }
      else 
      {
         slowo[i]=0;   i=0; 
    
        .... <--- tutaj obrabiam słowo :)
     }
    }
    

    Stosuje taki kod od dawna i do tej pory zero problemów. Tak naprawde to to wszystko jest w datasheecie. Może tylko jak zrobić to w przerwaniu jest słabo opisane, ale znalazłem dobrą stronke z opisem wektorów przerwań:

    Link

    Więc teraz łatwo jest się dopasować do nowych standardów :)
  • REKLAMA
  • Pomocny post
    #5 7499060
    mirekk36
    Poziom 42  
    lukullus87 napisał:
    Mówiąc uboga mialem na mysli to, ze do ATmegi8 czy ATmegi16 dokumentacje sa znacznie bardziej dokladne, np. rejestr UCSRC w ATmedze8 jest dobrze opisany, a do ATmegi48 znlazlem tylko tyle, ze nazywa sie UCSR0C... , ale mniejsza o to.


    no ale właśnie nie żadna mniejsza o to, tylko zassij sobie pełnego PDF'a gdzie wszystko masz dokładniusieńko opisane. Jak ty sobie wyobrażasz ustawienia bitów w jakimś rejestrze skoro nie masz przed oczami noty i opisanych ich znaczeń????

    jeszcze raz zapewniam cię że na 100000000% na www.atmel.com znajdziesz bez najmniejszego problemu PDF'a do całej serii procków Atmega48/88/168/328 (Tylko jeden i dosyć tłusty PDF)



    lukullus87 napisał:

    Mój kod wyglada tak:
    UCSR0C=(1<<UMSEL01) | (1<<UCSZ01) | (1<<UCSZ00);
    UBRR0L = 6;
    UCSR0B= (1<<RXEN0) | (1<<TXEN0);
    Czestotliwosc pracy ATmega48 wynosi 1MHz, dane odbieram z Matlaba, gdzie transmisa ustawiona jest standardowa, czyli taka jaka (wydaje mi sie) ustawilem na uC. Jesli ktos wie o co chodzi prosze o pomoc.


    tymczasem proszę zaglądam sobie w notę PDF tegoż procka a tu już w pierwszej linii masz MEGA ZONKA ;) ustawiasz bit UMSEL01 gdzie UMSEL00 ma domyślnie wartość 0. Tymczasem w nocie w opisie tych bitów w tym rejestrze jak byk stoi napisane że takie ustawienie bitów jest zarezerwowane (RESERVED) i nie można go używać

    poza tym skąd ty wytrzasnąłeś wartość UBRR0L = 6. No ok może i zajrzałeś (choć troszkę wątpię) na ostatnią stronę rodziału USART gdzie zobaczyłeś, że wartość w UBRR może być =6 dla 1MHz i dla prędkości 9600 - ale tylko pod warunkiem ustawienia bitu U2Xn = 1 ....... ale u ciebie w kodzie amba zjadła to ustawienie.

    Nie wspomnę już że troszkę ze strachem w związku z tym patrzę na to jak zezwalasz na przerwania UCSR0B= (1<<RXEN0) | (1<<TXEN0); ---- a napisałeś w ogóle programy do ich obsługi w tej swojej "implementacji" ????? jeśli tak? to dlaczego w ogóle z kolei odpalasz przerwanie do nadawania skoro wspominałeś że ty chcesz tylko odbierać ?????

    jak widzisz - cały ten kod nie trzyma się kupy i jasno widać dlaczego nie działa

    nie można się więc tak poddawać i nie zassać dobrej noty PDF ;) ...... a ta skrócona o której mówisz to wcale prawdopodobnie nie dotyczy procka ATmega48 - tylko zapewne dorwałeś notę w której atmel wyjaśnia różnice pomiędzy mega8 i 48 dlatego tylko tak porównawczo opisuje nazwy rejestrów jakimi się różnią

    mam nadzieję, że na przyszłość już ani razu nie odpuścisz sobie zassania porządnej noty PDF ;)

    Dodano po 5 [minuty]:

    AVRowiec ---> nie polecaj komuś używania starej konstrukcji prototypu przerwania typu SIGNAL - bo tego już się dawno nie używa - w zamian za to korzysta się z ISR() ..... doczytaj dlaczego i doczytaj jakie to może powodować komplikacje z warningami itp to po pierwsze

    po drugie ;) ..... to po co jakieś kurna magiczne linki tajemnicze z opisami wektorów przerwań .... skoro masz wszystko pod ręką w WinAVR

    wystarczy zajrzeć do pliku np: iom148.h jeśli korzystasz z procka ATmega48 albo do pliku iom32.h jeśli korzystasz z procka ATmega32 itd

    w tych plikach na własnym kompie masz najdokładniej na świecie a co ważne pod ręką - to czego ty doszukujesz się obecnie błądząc gdzieś po necie. Zresztą w tych plikach masz jeszcze wiele wiele innych pożytecznych informacji, które można we własnym programie wykorzystać
  • Pomocny post
    #6 7499151
    Samuraj
    Poziom 35  
    Ja osobiście przyczepił bym się do tego:
    AVRowiec napisał:


    SIGNAL (SIG_UART_RECV) 
    { 
      odebranyZnak = UDR; 
       // będzie składać slowo[] ze znaków różnych od:
    if ((odebranyZnak!=0x0D) && (odebranyZnak!=0x0A)
         && (odebranyZnak!=' ')&& (odebranyZnak!=',') && (odebranyZnak!='$')) 
      {
         slowo[i]=odebranyZnak;
    	 i++;
      }
      else 
      {
         slowo[i]=0;   i=0; 
    
        .... <--- tutaj obrabiam słowo :)
     }
    }
    


    Nie interpretował bym ramki danych w przerwaniu.
    Zaraz ktoś to przeczyta i zechce w interpretacji mazać po wyświetlaczu, lub co gorsza czytać dane z dallasa z waitem 750ms. i zaczną się cyrki gdyż część ramek będzie leciało w kosmos.

    Lepiej jest ustawić flagę iż ramka cała i do interpretacji a głównej pętli podejmować odpowiednią akcje.
  • REKLAMA
  • #7 7499181
    mirekk36
    Poziom 42  
    Samuraj napisał:
    Lepiej jest ustawić flagę iż ramka cała i do interpretacji a głównej pętli podejmować odpowiednią akcje.


    pewnie, że tak - no ale od tego to już tylko maleńki kroczek żeby zrobić po prostu odbiór do bufora cyklicznego w przerwaniu i tylko to. A odbieranie ramek już w dowolny sposób i widzi-mi-się ładnie z bufora - co będzie miało przy okazji mnóstwo zalet wynikających z buforowania nadchodzących rzeczy do procka
  • Pomocny post
    #8 7499250
    AVRowiec
    Poziom 18  
    macie racje. mój kod nie nadaje się do wszystkiego. mogłem wspomnieć że używam go tylko do rozpoznawania krótkich komunikatów i ustawiania flag. to był kawałek kodu parsowania gps albo czegoś podobnego i działało dobrze. wiadomo że w takim miejscu nie wolno przeprowadzać długich operacji, chyba że wyłączy się na chwilę odbiornik uart a po operacjach się go włączy - czasem tak robie i wydaje mi się że to dobry sposób.
    mirekk36 - dzięki za info odnośnie tych pliczków. nie wiedziałem że jest coś takiego.. dobrze wiedzieć.
    (btw: te pliczki są w: WinAVR-20090313\avr\include\avr jakby kto szukał)
    a o ISR sobie poczytam.
  • #9 7500156
    gigipawel
    Poziom 15  
    Witam.
    AVRowiec dzięki za dobry kodzik.
    MAm pytanie jak wysłać zmienną funkcją USART_Transmit_Word ?

    
    ...
    unsigned char  zmienna = 20;
    ...
    USART_Transmit_Word(zmienna);
    
    


    i nic nie wyświetla. Zmienne typu string wysyłane są okej.
  • #10 7500598
    lukullus87
    Poziom 11  
    Bardzo dziekuje wszystkim za tak szybka odpowiedz i dokladne rozjasnienie problemu, ale ... mirekk36 wydaje mi sie, ze kodem:
    UCSR0B= (1<<RXEN0) | (1<<TXEN0);
    nie uruchamiam przerwan, tylko wlaczam odbiornik i nadajnik, czy moze sie myle?
  • Pomocny post
    #11 7500639
    mirekk36
    Poziom 42  
    lukullus87 napisał:
    Bardzo dziekuje wszystkim za tak szybka odpowiedz i dokladne rozjasnienie problemu, ale ... mirekk36 wydaje mi sie, ze kodem:
    UCSR0B= (1<<RXEN0) | (1<<TXEN0);
    nie uruchamiam przerwan, tylko wlaczam odbiornik i nadajnik, czy moze sie myle?


    eeeh oczywiście, że się rozpędziłem - masz rację (sorki) ;)
  • #12 7500660
    lukullus87
    Poziom 11  
    i jesczze jedno predkosc UBRR0l=6 ustawiamy dla U2Xn=0... a nie 1, ale i taik bardzo dziekuje za pomoc, zobacze czy zadziala i dam znac:)
  • Pomocny post
    #13 7500700
    mirekk36
    Poziom 42  
    lukullus87 napisał:
    i jesczze jedno predkosc UBRR0l=6 ustawiamy dla U2Xn=0... a nie 1, ale i taik bardzo dziekuje za pomoc, zobacze czy zadziala i dam znac:)


    już chciałem z tym polemizować - ale jeszcze raz spojrzałem do PDF'a i sam przyznaję, że nie wiem dlaczego zobaczyłem wartość = 6 ale w kolumnie z U2Xn = 1.

    Koniec końców i tak - zamiast wpisywać tę wartość "z palca" lepiej jest ją sobie po prostu w preprocesorze obliczać, ja zawsze robię to tak:

    #define 9600 //----> tu definiuję jaką chcę mieć prędkość
    
    #define __UBRR (F_CPU/16/UART_BAUD-1) // tu wyliczam wartość do UBRR


    a później

      UBRRH = (uint8_t)(__UBRR>>8);     
      UBRRL = (uint8_t)__UBRR;

    i po zawodach
  • #14 7501062
    lukullus87
    Poziom 11  
    hmmm dziwnie to wyglada, obecny kod:

    #define F_CPU 1000000UL // 1 MHz
    #define UART_BAUD 9600UL
    #define UART_CONST (F_CPU/(16ul*UART_BAUD)-1)
    .
    .
    .
    char buf;

    //inicjalizacja trnsmisji szeregowej
    UCSR0C= (1<<UCSZ01) | (1<<UCSZ00);
    UBRR0H = (uint8_t)(UART_CONST>>8);
    UBRR0L = (uint8_t)UART_CONST;
    UCSR0B= (1<<RXEN0) | (1<<TXEN0);

    while(!(UCSR0A&_BV(RXC0)));
    buf=UDR0;

    i odbieram tylko krzaki, a w matlabie mam ustawione predkosc 9600, 8 bitow danych, 1 bit stopy, ma ktos jakis pomysl?
REKLAMA