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

[Atmega 16][C/WinAVR], problem z modbus, USART

16 Maj 2010 12:41 2401 2
  • Poziom 11  
    Chciałbym skomunikować 2 atmegi przez modbusa i używam do tego modułu USART. Walczę z tym już kilka dni i nie mogę dojść do ładu.
    Nadawanie skonfigurowane, odbiór również, bo klocki się komunikują, ale nie chcą wysłać (lub odebrać) wszystkiego co jest do przesłania. Próbuję nadać np 8-elementową tablicę liczb (unsigned char) i dochodzi tylko ich część (2-3 liczby). Kiedy próbuję nadać dłuższa tablicę dochodzi ich proporcjonalnie więcej.

    Druga sprawa to ustawianie i kasowanie bitów TXC i RXC. Po co to robić skoro w dokumentacji jest napisane, ze bity te kasują i ustawiają się same po zapisaniu czy też odczycie bufora.

    Code:

    void putchar (char c)
    {
      UDR=c;
      loop_until_bit_is_set(USR,TXC);
      sbi(USR,TXC);                         // ??
    }
    char getchar (void)
    {
      loop_until_bit_is_set(USR,RXC);
      cbi(USR,RXC);                        // ??
      return UDR;
    }
  • Poziom 42  
    No to jeszcze długa droga i walka przed tobą, skoro robisz coś niezgodnie z dokumentacją w PDF ;) a potem niewinnie pytasz:

    broda997 napisał:
    Druga sprawa to ustawianie i kasowanie bitów TXC i RXC. Po co to robić skoro w dokumentacji jest napisane, ze bity te kasują i ustawiają się same po zapisaniu czy też odczycie bufora.

    Code:

    void putchar (char c)
    {
      UDR=c;
      loop_until_bit_is_set(USR,TXC);
      sbi(USR,TXC);                         // ??
    }
    char getchar (void)
    {
      loop_until_bit_is_set(USR,RXC);
      cbi(USR,RXC);                        // ??
      return UDR;
    }


    Poza tym zastanów się dokładnie, którą flagę chcesz wykorzystywać przy nadawaniu? czy TXC czy UDRE bo to jednak jest pewna różnica, z której warto sobie zdawać sprawę i doczytać o tym
  • Poziom 11  
    A co robię niezgodnie z dokumentacją? Poniższe funkcje znalazłem na stronie internetowej, która wyglądała całkiem poważnie.
    Obojętne mi z której flagi będę korzystał byle działało :P A skoro w większości przykładów natknąłem się właśnie na wykorzystanie tych flag to tego się na razie trzymam.

    ----------------------------------------------
    W sumie to zapomniałem zaznaczyć, że ja u siebie pominąłem te linie ze znakami zapytania - więc na moje oko robię tak jak instrukcja każe.
    W dodatku zmieniłem funkcje putchar na:
    Code:

    void putchar (char c)
    {
      UDR=c;
      loop_until_bit_is_set(USR,UDRE);
    }

    I ruszyło :DD
    Już wiem czym różni się UDRE od TXC, ale nie rozumiem dlaczego poprzednia konstrukcja nie działała. Skoro TXC jest ustawiany po nadaniu ramki to znaczy, że zrobiło się miejsce dla następnej - to dlaczego nie chciał jej przyjmować?

    --------------------------------
    Poniżej zamieszczam część moich wypociny odnośnie realizacji Modbusa na module USART.
    Jeżeli komuś się przyda to proszę korzystać. Dodam tylko, że funkcja licząca CRC jest nie moja.
    Program zawierał jeszcze obsługę przycisków i LCD, ale je pominąłem, bo strasznie dużo miejsca zajmowało. Poniższe funkcje działają na Atmega16 innych nie sprawdzałem.
    Code:

    /*-------------------------OPOZNIENIA---------------------------------*/
    void delay_us(int us)
       {
       volatile long unsigned int i;
       for(i=0;i<(us*(F_CPU)/35000000);i++);
       }

    void delay_ms(int ms)
       {
       volatile long unsigned int i;
       for(i=0;i<(ms*(F_CPU)/35000);i++);

    /*  ------------ Organizacja pamieci urzadzenia -------------------*/
    unsigned char pamiec[256];
    unsigned char ramka[260];
    unsigned char rejestr=0;
    int dl_ramki=0;

    /* -------------- Konfiguracja USART ----------------------------- */
    void usart_init(void)
    {
    UBRRL = 25;             // predkosc transmisji na 2400bps, dla F=1MHz, 1 bajt = 3.3ms
    UCSRB &= ~_BV(UCSZ2);  // zeruj - dlugosc slowa na 8
    UCSRC |= _BV(UCSZ1);   // ustaw - dlugosc slowa na 8
    UCSRC |= _BV(UCSZ0);   // ustaw - dlugosc slowa na 8
    UCSRB |= _BV(RXEN);      // wlacz modul odbiorczy
    UCSRB |= _BV(TXEN);    // wlacz modul nadawczy
    }

    /* ------- Funkcje USARTA ---------------------- */
    unsigned char putchar(unsigned char dana)
    {
       UDR=dana;
       loop_until_bit_is_set(UCSRA,UDRE);
       return(0);
    }


    unsigned char getchar (void)
    {
       unsigned char dana;
       loop_until_bit_is_set(UCSRA,RXC);
       dana=UDR;
       return dana;
    }

    /* -------- Obliczanie CRC -------------------*/
    unsigned short ModbusCRC(unsigned char * buf, int size)
    {
       unsigned short crc = 0xffff;     
       int i;
         
       while(size--)   
       {     
          crc ^= *buf;
          buf++;
          for(i=0; i<8; i++)   
           {               
             if(crc & 1)
             {
                crc >>= 1;
                crc ^= 0xA001;
             }
             else
             {
                crc >>= 1;
             }
          }     
       }     
       return crc;       
    }

    /* ----------- Konwersja CRC do dwoch liczb 8bitowych --------------------- */
    void konwertuj_16(unsigned short crc, unsigned char *msb, unsigned char *lsb)
    {
    *lsb = crc;    // podstaw mniej znaczacy bajt
    crc >>= 8;    // przesun o 8 bitow w prawo
    *msb = crc;   // podstaw bardziej znaczacy bit
    }

    /* ------------- Odbior ramki -------------------- */
    int odbierz_ramke(unsigned char *ramka, int *dl_ramki)     // jezeli rozpocznie sie transmisja to kolejne
    {                                                                             // bajty musza przychodzic w odstepach <20ms
    *dl_ramki=0;
    int brak_bajtu=0;
    while (1)                             // petla nieskonczona
       {
       if (bit_is_set(UCSRA,RXC))      // jezeli rozpoczeta transmisja
          {
          while (brak_bajtu <= 200)   // brak transmisji na mniej niz 20ms
             {
             if (bit_is_set(UCSRA,RXC))  // jezeli przyszedl nowy bajt
                {
                ramka[*dl_ramki]=UDR;   //  to go zapisz do ramki
                ++(*dl_ramki);
                brak_bajtu=0;         //  zresetuj czas oczekiwania na bajt
                }
             delay_us(100);             //  razem z <200 w while daje 20ms
             ++brak_bajtu;
             }
          return 0;      // transmisja zakonczona
          }
       }
    }

    int sprawdz_ramke(unsigned char *ramka, int dlugosc)  // zwraca 0 dla poprawnej ramki
    {                                                                         // zwraca 1 dla niepoprawnej ramki
    unsigned short crc;
    unsigned char msb,lsb;

    crc = ModbusCRC(ramka, dlugosc-2);
    konwertuj_16(crc, &msb, &lsb);

    if (ramka[dlugosc-2]==msb)            // wyzszy bajt CRC poprawny
       {
       if (ramka[dlugosc-1]==lsb)     // nizszy bajt CRC poprawny
          {
          return (0);
          }
       else
          {
          return (1);
          }
       }
    else
       {
       return (1);
       }
    }