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

ATMEGA USART na przerwaniach się wiesza

DJ.TRoX 11 Cze 2010 08:32 1485 2
  • Poziom 17  
    Witam forumowiczów,

    Sytuacja wygląda tak, że z jednostki nadrzędnej słane są ramki danych,
    Po każdej ramce jest szczelina czasowa tak aby nasza ATmega zdążyła odpowiedzieć,
    Mamy Atmega16 kwarc 16MHz i transmisje 57600 (w przybliżeniu),
    Gadamy przez RS485 tak, że między ramkami jeszcze przełączam linie bufora,
    Steruje równocześnie buforem wejścia i wyjścia tak, że kiedy nadajemy to nic nie wraca z powrotem,
    Z grubsza działa to tak, że przy inicjacji włączam w UCSRB bity RXCIE, TXEN, RXEN,
    No i z każdym odebranym bajtem zgłasza się przerwanie od RX,
    Kiedy przyjdzie cała ramka, zgodzą się znaczki początku i końca oraz suma kontrolna to przechodzę na odbiór,
    Przełączam linie bufora oraz włączam UDRIE w UCSRB,
    W tym momencie kiedy rejestr wyjściowy UDR będzie pusty (czyli od razu) program skacze do przerwania SIG_UART_DATA,
    Wysyłam sobie całą ramkę a po ostatnim bajcie wyłączam UDRIE oraz włączam TXCIE,
    Kiedy przychodzi przerwanie SIG_UART_TRANS ustawiam linie RS na odbiór i wyłączam TXCIE,

    Wszystko działa dobrze ale krótko,
    Po kilkuset ramkach program się zachowuje tak jak by po kolejnym wysłanym bajcie nie przychodziło przerwanie i nie ma co popędzać programu do przodu,
    Przepełnienie stosu? niby jak?
    Reszta programu działa bez zarzutów mimo, że komunikacja stoi,
    Procedury odbioru i zapisu osobno też działają bez zarzutu,

    Program wygląda tak:

    Code:

    SIGNAL(SIG_UART_RECV){
        char data,cs;
       unsigned char a;

        data=UDR;
       
        if (rx_pos){
            rx_buffer[rx_pos]=data;
            rx_pos++;

          if (rx_pos==3){
             rx_len=data;
             if ((rx_len+5)>rs_buffer_len){
                rx_len=0;
                rx_pos=0;
                sbi(rs_status, reciving_error);
             }
          }
        }else{
            if (data==master_frame_begin_sign){
                rx_buffer[0]=data;
                rx_pos=1;
            }
        }   
        if ((rx_pos>4) && (rx_pos>=rx_len+5)){
            rx_pos=0;
          if (rx_buffer[rx_len+4]==frame_end_sign){
             cs=cs_base_sign;
             for (a=0; a<rx_len+3; a++){
                cs^=rx_buffer[a];
             }
             if (cs==rx_buffer[rx_len+3]){
                if ( (rx_buffer[1]==0) && (rx_buffer[2]==2) ){
                   sbi(rs_status, recived_valid_frame);
                   if ( (output_prv[0]==rx_buffer[3]) && (output_prv[1]==rx_buffer[4]) ){
                      output[0]=rx_buffer[3];
                      output[1]=rx_buffer[4];
                   }
                   output_prv[0]=rx_buffer[3];
                   output_prv[1]=rx_buffer[4];

                   DIR_W;        //------------------------------------ PRZECHODZIMY NA TRANSMISJE
                   sbi(UCSRB, UDRIE);    // int empty buffer enable               
                }
             }else{
                sbi(rs_status, reciving_error);
             }
          }else{
             sbi(rs_status, reciving_error);
          }
        }
    }



    SIGNAL(SIG_UART_DATA){
       unsigned char a,cs;
       if (tx_pos){
          UDR=tx_buffer[tx_pos];
          if (tx_pos>=6){            // last byte in frame --> go to transmiting
             cbi(UCSRB, UDRIE);      // int tx ready disable
             sbi(UCSRA, TXC);      // clear transmit int flag
             sbi(UCSRB, TXCIE);       // int tx finish enabled

    //         while(!(UCSRA&(1<<TXC)));
    //         sbi(UCSRA, TXC);      // clear transmit int flag
    //         DIR_R;

             tx_pos=0;
          }else{
             tx_pos++;
          }
       }else{
          UDR=slave_frame_begin_sign;
          tx_pos=1;
          tx_buffer[1]=0;
          tx_buffer[2]=2;
          tx_buffer[3]=input[0];
          tx_buffer[4]=input[1];
          cs=cs_base_sign^slave_frame_begin_sign;
          for (a=1; a<5; a++){
             cs^=tx_buffer[a];
          }
          tx_buffer[5]=cs;
          tx_buffer[6]=frame_end_sign;
       }
    }



    SIGNAL(SIG_UART_TRANS){
       DIR_R;
       cbi(UCSRB, TXCIE);
    }




    inicjacja USARTA:
    Code:

       UBRRH=0;
       UBRRL=34;            // 57.143bps (57.600)
       UCSRA=0b00000010;      // double speed
       UCSRB=0b10011000;      // int Rx enabled
       UCSRC=0b10001110;      // 8bit 2 stop




    Jeśli ktoś ma pomysł to z góry dziękuję.
  • Użytkownik usunął konto  
  • Poziom 17  
    Znalazłem błąd,
    Jak to zwykle bywa był zupełnie gdzie indziej niż szukałem,
    Inny proces mi śmiecił po linii sterującej buforem RS,
    Dość złośliwy zbieg okoliczności,
    Tak czy siak dzięki za pomoc.