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

[atmega8-attiny2313] Usart a stabilizacja kwarcem

slawek-matyl 23 Paź 2008 20:36 2780 14
  • #1 23 Paź 2008 20:36
    slawek-matyl
    Poziom 11  

    Witam
    Testuje transmisje poprzez USART asynchroniczą, narazie na kablu, lecz nie każda ramka danych dochodzi(BAUDRATE=2400). Pytam się czy procki muszą być stabilizowane kwarcem, żeby poprawnie taka transmisja szła.
    Drugie pytanie dotyczy Attiny2310 w rej. UCSRC nie ma bitu URSEL, w atmedze jest, jednak jak wyłącze ten bit z atmegi8 to transmisja pada
    Pozdrawiam

    0 14
  • #2 24 Paź 2008 10:33
    Limonit
    Poziom 13  

    Dobry obyczaj nakazuje, aby stosowac kwarce o częstotliwości dającej łatwo uzyskac potrzebne szybkości transmisji. Praktyka jednak pokazuje że przewaznie działa z kwarcem wewnętrznym.
    Na stronie 138 dokumentacji Tiny2313 masz opisane, jakie szybkości da się uzyskac i z jakim błędem. Jeśli nie przekroczy on 1% to śmiało można stosować, raczej nie kwarc będzie przyczyną kłopotów.
    W okolicy tejże strony można róniez wyczytać, ze Tiny nie ma bitu URSEL.

    0
  • #3 24 Paź 2008 23:05
    slawek-matyl
    Poziom 11  

    Niestety nie mam analizatora stanów logicznych i nie wiem czy poprawnie nadajnik działa. Tylko czy za mała odległość nadajnika od odbiornika może spowodować błędne działanie transmisji bezprzewodowej. Stosuje RX/TX433N z Valeemana.
    Pozdrawiam

    0
  • #4 25 Paź 2008 01:48
    submariner
    Poziom 32  

    przejdz na wolniejsza transmisje - im wolniej tym bardziej tolerowane sa roznice czestotliwosci oscylatora.

    0
  • #5 25 Paź 2008 08:36
    mirekk36
    Poziom 42  

    slawek-matyl -> dopiero w drugim poście napisałeś, że chodzi ci o transmisję RS232 ale w torze radiowym 433MHz - a to robi wielką różnicę ;). A właśnie to jest twoim problemem a nie dobieranie kwarca zewnętrznego. Bo nawet przy stosowaniu kwarca "przyjaznego" dla RS232 - będziesz miał te same probelmy. Wynikają one z tego, że te proste i tanie pary nadajnik/dobiornik bez zastosowania kodowania sygnału np takiego jak bifazowe (Manchester) nie działają dobrze albo prawie w ogóle. Możesz do nich zaliczyć też nadajniki odbiorniki firmy Aurel - taka sama lipa do bezpośredniej transmisji RS232. Trzeba było przed zakupem poczytać troszkę nawet na tym formu na ten temat. Znalazłbyś wtedy np informację, że jeśli już chcesz koniecznie bez programowego kodowania działać tylko bezpośrednio przez RS to można spokojnie użyć kompletu firmy Telecontrolli. Cena jednak nie będzie taka niska jak tego Vellmana. Bo za komplet zapłacić trzeba chyba z 80zł. Jednak spokojnie, testowałem to sam i kilku ludzi z elektrody możesz używać transmisji RS232 bez błędów z prędkością 4800 a nawet 9600 chociaż trzeba wtedy zrobić sobie jakieś własne ramki danych i sprawdzanie ich poprawności. Jak będziesz zainteresowany to powiedz - poszukam i podam ci wtedy symbole tych konkretnych nadajników i odbiorników. (Na prawdę działają przy antence ze zwykłego drucika na ładnym dosyć zasięgu) Innym jeszcze bardziej pewnym sposobem na transmisję RS232 są moduły i to takie gotowe do BlueTooth ale tu 1szt kosztuje już ok 120zł. Można za to śmigać sobie bez najmniejszego problemu z prędkością 115200 i to w obie strony! odpadają też problemy z dobieraniem anten i zasięgiem.

    a odnośnie swoich Vellmanów zajrzyj do ich PDF'a

    http://www.velleman.be/downloads/7/tx433n_datasheet.pdf

    i zobacz, że tam w przykładowej aplikacji stosują wprawdzie nie programowy ale sprzętowy (scalak HT) koder i dekoder sygnału)

    0
  • #6 25 Paź 2008 12:56
    slawek-matyl
    Poziom 11  

    mirekk36 dziękuję za bardzo wyczerpującą odpowiedz!
    Przy transmisji(elementy na płytce stykowej) przy prędkości transmisji 1200 baudrate i wysyłaniu ramki co 50ms, coś już zaczyna działać, jak już kupiłem te moduły to będę męczył się z częścią programową, może coś z tego uda się wykombinować
    Pozdrawiam

    0
  • #7 25 Paź 2008 13:14
    mirekk36
    Poziom 42  

    jak pisałem wcześniej, musisz sobie zaprojektować programową ramkę danych z jakąś sumą kontrolną i np wysyałać kilka ramek jedna po drugiej. W odbiorniku muszą odebrać się np 2 ramki bez błędów i wtedy można przyjać, że nadleciały dobre dane. To pozwoli ci w jakiś sposób na pewno na przezwycieżenie problemu przy niedużych odległościach i przy transmisji "na żywca" RS232.

    ale wszystko też zależy - trzeba przemyśleć czy masz wielką potrzebę na przesyłanie większej ilości danych w małej jednostce czasu czy też potrzebujesz przesłać po prostu jakiś bajt aby po drugiej stronie coś tam włączyć lub wyłączyć a prędkość nie jest taka istotna. Wtedy możesz sobie zrobić tak, że nadajnik podłączasz do nóżki na którą generujesz dane w standardzie np RC5 dokładniuśko tak samo jakbyś chciał sterować diodę podczerwieni i pilota. RC5 zapewnia kodowanie bifazowa/Manchester właśnie. Natomiast w odbiorniku robisz kawałek programu, który odbiera polecenia IR tye że zamiast odbiornika podczerwieni podłączasz swój odbiornik radiowy. Masz wtedy do wykorzystania do własnych celow 11 bitów w jednej ramce . 5bitów adresu i 6bitów polecenia. To zawsze jest jakieś rozwiązanie na szybko ;) o ile wystarcza taka przepustowość jak w pilotach IR. A do zadań typu włącz/wyłącz zawsze wystarcza. Można później się nawet pokusić o zrobienie własnego protokołu bazującego na RC5 tak aby można było przesyłać kilkubajtowe dane i z nieco więszką prędkością. Ja właśnie opracowuję teraz powoli taki standardzik na swoje potrzeby ponieważ, zanim kupiłem te dobre moduły o których pisałem wcześniej też wkopałem się w różne aurele itp .... Jednak nie chcę aby one zakisiły się gdzieś w szufladach i zaprzęgnę je także do jakichś prostych zadań

    0
  • #8 25 Paź 2008 14:36
    slawek-matyl
    Poziom 11  

    mirekk36 ja to potrzebuje do sterowania autka RC, więc dane poprostu mogą bardzo wolno "płynąć". Wiem że przy sterowaniu silnika sygnałem PWM generowane są duże ilości zakłóceń (może znajdę coś jak dobrze zniwelować te zakłócenia), na początek wystarczyło by mi wysłanie instrukcji co 0,5s. Piszę w C kompilator avr-gcc, jak by miałeś gdzieś kod do RC5 to był bym wdzięczny, jeszcze nie bawiłem się IR więc za dużego pojęcia nie mam.
    Pozdro

    0
  • #9 25 Paź 2008 15:03
    mirekk36
    Poziom 42  

    Jako, że od niedawna sam uczę się dopiero C, to proszę bardzo poniżej, najpierw kod do odbiornika RC5. Sprawdzony, krótki i odporny na zakłócenia oraz kody z innych pilotów - działa wyśmienicie i w ciekawy sposób wykorzystuje bit TOGGLE:

    Code:
    // zmienne do obsługi kodów IR w standardzie RC5
    

    volatile uint8_t address;         // adres RC5
    volatile uint8_t command;         // komenda RC5
    volatile uint8_t toggle_bit;      // bit TOGGLE
    volatile uint8_t key_rep;         // = 1 gdy klawisz wciśnięty dłużej, = 0 gdy tylko raz
    volatile uint8_t key_time;         // ilość powtórzeń ramki przy wciąż wciśniętym klawiszu - repeat
    volatile uint8_t Ir_key_press_flag;   // flaga = 1 - informuje, że odebrany został nowy kod z pilota
                               // po odczytaniu danych ze zmiennych należy wyzerować flagę aby
                               // zostały przyjęte kolejne kody z pilota
                               //
                               // przykład zastosowania:
    /*

       if (Ir_key_press_flag)
       {
          if (address == 0)
          {
             // np: (gdy polecenie = "jakaś wartość" - wykonaj jakąś funkcję)
             if (command == something) .... make_something();

             // lub: (gdy polecenie = "jakaś wartość" i tryb repeat....)
             if (command == something && key_rep == 1) .... make_something();

             // albo: (gdy polecenie = "jakaś wartość" i tryb repeat oraz nastąpiło 10 powtórzeń ramki....)
             if (command == something && key_rep == 1 && key_time == 10) .... make_something();
          }

          // zawsze zerujemy na końcu flagę!!! aby odblokować bufor odbiorczy IR dla kolejnych danych
          Ir_key_press_flag = 0;
       }

    */


    // stałe i zmienne potrzebne na wewnętrzne cele procedury obsługi RC5

    //                stała czasowa i tolerancja




    #define TOLERANCE 200
    #define MIN_HALF_BIT    889    -       TOLERANCE
    #define MAX_HALF_BIT    889    +       TOLERANCE
    #define MAX_BIT      889+889    +       TOLERANCE

    volatile uint8_t rc5cnt;
    volatile uint8_t last_toggle;


    void ir_init()
    {
       DDR(IR_PORT) RESET IR_IN;      // pin jako wejście
       PORT(IR_PORT) SET IR_IN;      // podciągnięcie pinu do VCC
         TCCR1B SET (1<<CS11);            // Timer1 / 8
         TCCR1B RESET (1<<ICES1);        // Zbocze opadające na ICP
         TIMSK SET (1<<TICIE1);           // Przerwanie od ICP
       rc5cnt = 0;                  // zerowanie licznika występująych zboczy
       Ir_key_press_flag = 0;         // zerowanie flagi otrzymania kodu z pilota
    }


    SIGNAL(SIG_INPUT_CAPTURE1)
    {

       #define FRAME_RESTART 0
       #define FRAME_OK 1
       #define FRAME_END 2
       #define FRAME_ERROR 3


         static uint16_t LastCapture;
         uint16_t PulseWidth;
         static uint8_t IrPulseCount;
         static uint16_t IrData;
       static uint8_t frame_status;


         PulseWidth = ICR1 - LastCapture;
         LastCapture = ICR1;

       TCCR1B TOGGLE (1<<ICES1);         // zmiana zbocza wyzwalającego na przeciwne

       if (PulseWidth > MAX_BIT) rc5cnt = 0;

       if (rc5cnt > 0) frame_status = FRAME_OK;

       if (rc5cnt == 0)
       {
          IrData = 0;
          IrPulseCount = 0;
          TCCR1B SET (1<<ICES1);
          rc5cnt++;
          frame_status = FRAME_END;
       }

       if (frame_status == FRAME_OK)
       {
          if ( PulseWidth < MIN_HALF_BIT ) frame_status = FRAME_RESTART;    // gdy zakłócenia (szpilki) - RESTART
          if ( PulseWidth > MAX_BIT ) frame_status = FRAME_RESTART;       // gdy błąd ramki danych (może inny standard niż RC5) RESTART

          if (frame_status == FRAME_OK)
          {
             if (PulseWidth > MAX_HALF_BIT) rc5cnt++;

             if (rc5cnt > 1)
             if ( (rc5cnt % 2) == 0 )
             {
                IrData = IrData << 1;
                if ( (TCCR1B & (1<<ICES1)) ) IrData |= 0x0001;
                IrPulseCount++;

                if (IrPulseCount > 12)
                {
                   if (Ir_key_press_flag == 0)
                   {
                      command    = IrData & 0b0000000000111111;
                      address    = (IrData & 0b0000011111000000) >> 6;
                      toggle_bit    = (IrData & 0b0000100000000000) >> 11;
                      if (toggle_bit == last_toggle) key_time++;
                      else key_time = 0;
                      if (key_time) key_rep = 1;
                      else key_rep = 0;
                      last_toggle = toggle_bit;
                   }
                   frame_status = FRAME_RESTART;
                   Ir_key_press_flag = 1;
                }      
             }
             rc5cnt++;
          }
       }

       if (frame_status == FRAME_RESTART)
       {
          rc5cnt = 0;
          TCCR1B RESET (1<<ICES1);
       }
    }


    oczywiście słowo wyjaśnienia - (kod pisany dla ATmega8), czasy stałych i procedur dobrane są dla częstotliwości taktowania 8MHz tak więc jeśli więc ktoś chce inną lub inny procek AVR to musi sobie przerobić troszkę kodzik. Jeszcze nie ma "wszczepionego" uniwerslanego przeliczania w zależności od F_CPU. Poza tym program wykorzystuje jak widać w pełni Timer1 oraz wejście ICP mikrokontrolera - więc tylko do niego można podłączyć wejście z odbiornika podczerwieni lub radiowego.

    a tu jeszcze niżej kod nadajnika RC5. Tu kod pisany był dla ATtiny2313 także przy częstotliwości taktowania 8MHz. Tutaj też z kolei korzystamy z jednej nóżki OC0A - wyjście PWM Timera0 i przez tranzystor PNP sterujemy diodą IR lub nadajnikiem radiowym ;)

    Code:


        // gdzieś w main - inicjalizacja Timer0 oraz zmiennych
       OCR0A =  110;
       TCCR0A SET (1<<WGM01);
       TCCR0B SET (1<<CS00);

       uint8_t toggle_bit = 0;
       uint8_t address = 255;
       uint8_t command = 255;

    void send_rc5_one()
    {
       czekaj_us(889);
       TCCR0A SET (1<<COM0A0);
       czekaj_us(889);
       TCCR0A RESET (1<<COM0A0);
    }

    void send_rc5_zero()
    {
       TCCR0A SET (1<<COM0A0);
       czekaj_us(889);
       TCCR0A RESET (1<<COM0A0);
       czekaj_us(889);
    }

    void send_rc5()
    {

       uint16_t data = 0;

       // i musi być 16 bo transmisja zaczyna się od
       // najstarszego bitu
       uint8_t i = 16;

       data |= ( (address<<11)|(command<<5) );

       send_rc5_one();   

       #if IR_MODE == RC5
          send_rc5_one();
       #endif

       #if IR_MODE == RC6
          if (command & (1<<7)) send_rc5_one();
          else send_rc5_zero();   
          
       #endif

       if ( toggle_bit ) send_rc5_one();
       else send_rc5_zero();


       while (i>5)
       {
          i--;
          if ( !(data & (1<<i)) ) send_rc5_zero();
          else send_rc5_one();
       }

    }


    przykład użycia nadawania RC5:

    Code:
       toggle_bit ^= (1<<0); 
    
       address = 0;    // adres dla TV
       command = 1; // klawisz nr.1 z klawiaturki numerycznej pilota
       send_rc5;

    0
  • #10 25 Paź 2008 15:29
    slawek-matyl
    Poziom 11  

    wielkie dzięki, jak znajdę trochę czasu to od razu zabiorę się za testowanie, jak bym miał jeszcze jakieś pytanka to się odezwę. A mirekk36 z czego się uczysz C?? Kursy w necie, jakaś książka.
    Dzięki wielkie

    0
  • #11 25 Paź 2008 16:52
    mirekk36
    Poziom 42  

    kursów dobrych w necie to jakoś mało udaje mi się znaleźć, ale dorwalem artykuły o nauce C z EP i EdW - te z EdW trochę lepsze nawet.

    Właśnie, żeby była jakaś dobra książka ? to by było fajnie - najchętniej lubię mieć pod ręką jakąś dobrą książkę niż czytanie w kompie

    0
  • #12 25 Paź 2008 18:01
    Freddie Chopin
    Specjalista - Mikrokontrolery

    heh, twoj kod w C wciaz przypomina pewien 'jezyk' 'programowania' <: te makra i niektore patenty [;

    4\/3!!

    0
  • #13 25 Paź 2008 19:32
    mirekk36
    Poziom 42  

    Freddie Chopin -> wiem wiem ;) ale zapewne po jakimś czasie mi to przejdzie. Chociaż z drugiej strony czemu nie korzystać z "mocy" tworzenia makr i polecenia #define.

    .... w końcu czegoś takiego jak _BV() też na początku nie było ;)

    dla mnie najważniejsze, że w końcu coś mi w tym C wychodzi i to, że C daje mi GIGANTYCZNE możliwości ;)

    0
  • #14 25 Paź 2008 23:44
    Freddie Chopin
    Specjalista - Mikrokontrolery

    wiadomo [;

    do pewnego poziomu makra sprawe ulatwiaja, niemniej jednak ich nadmiar powoduje, ze nie wiadomo o co chodzi, a kod wymaga dlugiego czasu do analizy.

    4\/3!!

    0
  • #15 26 Paź 2008 15:25
    slawek-matyl
    Poziom 11  

    albo jestem ślepy, i nie widzę tego w kodzie, ale ze stronki Link (artykuł o TX/RX433) biorę kod. To co wysyła nadajnik to:

    Code:

    void USART_vSendByte(uint8_t u8Data)
    {
        // Wait if a byte is being transmitted
        while((UCSRA&(1<<UDRE)) == 0);
        // Transmit data
        UDR = u8Data;
    }
    void Send_Packet(uint8_t addr, uint8_t cmd)
    {
       USART_vSendByte(SYNC);//send synchro byte   
       USART_vSendByte(addr);//send receiver address
       USART_vSendByte(cmd);//send increment command
       USART_vSendByte((addr+cmd));//send checksum
    }

    int main(void)
    {
    USART_Init();
    while(1)
       {//endless transmission
       //send command to switch led ON
       Send_Packet(RADDR, LEDON);
       delayms(100);
       //send command to switch led ON
       Send_Packet(RADDR, LEDOFF);
       delayms(100);
       }
       return 0;
    }


    a kod odbiornika to:
    Code:

    uint8_t USART_vReceiveByte(void)
    {
        // Wait until a byte has been received
        while((UCSRA&(1<<RXC)) == 0);
        // Return received data
        return UDR;
    }
    ISR(USART_RXC_vect)
    {
       //define variables
       uint8_t raddress, data, chk;//transmitter address
       //receive destination address
       raddress=USART_vReceiveByte();
       //receive data
       data=USART_vReceiveByte();
       //receive checksum
       chk=USART_vReceiveByte();
       //compare received checksum with calculated
       if(chk==(raddress+data))//if match perform operations
       {
          //if transmitter address match
          if(raddress==RADDR)
             {
                if(data==LEDON)
                   {
                      PORTC&=~(1<<0);//LED ON
                   }
                else if(data==LEDOFF)
                   {
                      PORTC|=(1<<0);//LED OFF
                   }
                else
                {
                   //blink led as error
                   PORTC|=(1<<0);//LED OFF
                   _delay_ms(10);
                   PORTC&=~(1<<0);//LED ON   
                }
             }
       }
    }

    Problem w tym że dioda po stronie odbiorczej miga z częstotliwością 2x mniejszą, czyli tak jakby co druga ramka dochodziła. Proszę o jakąś pomoc.
    Pozdrawiam

    0