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

Odbiór całej ramki RS232 za pomocą przerwania w SIGNAL (SIG_UART_RECV)

Chivo 25 Lip 2009 15:03 2217 27
REKLAMA
  • #1 6819956
    Chivo
    Poziom 27  
    Posty: 1326
    Pomógł: 81
    Ocena: 130
    Witam

    Mam taki problem, ze za pomoca przerwania chce odebrac z rs232 cala ramke a nie pojedynczy znak i na podstawie jakiegos pola cos robic.
    SIGNAL (SIG_UART_RECV) 
    {
        Bufor[i]=UDR;
        i++;
             if(Bufor[0]==0x31)
             {
                 for(k=0; k<6; k++)
                 {
                    USART_Transmit(k);
                }
             }
    }

    Moj problem polega na tym ze procek nie reaguje na wyslanie do niego 0x31. Dopiero jak wisze Bufor[0]=UDR to dziala ale nieo to chodzi.

    Pozdrawiam
  • REKLAMA
  • #2 6820036
    Konto nie istnieje
    Konto nie istnieje  
  • REKLAMA
  • #3 6820049
    Chivo
    Poziom 27  
    Posty: 1326
    Pomógł: 81
    Ocena: 130
    Procek odbiera takie dane:
    1.poczatek ramki
    2.dane 0x31
    3.koniec ramki

    Jezeli poczatek i koniec ramki sa ok to ma przetworzyc dana(0x31) czyli cos wyslac

    Dodano po 6 [minuty]:

    Dane odebrane z rs232 chce zapisac do tablicy i sprawdzac ja tak:
    bufor[0]=poczatek
    bufor[1]=dane
    bufor[2]=koniec
  • #4 6820079
    Konto nie istnieje
    Konto nie istnieje  
  • #5 6820085
    Chivo
    Poziom 27  
    Posty: 1326
    Pomógł: 81
    Ocena: 130
    A mozesz mi to napisac w postaci kodu?????
  • #6 6820120
    Konto nie istnieje
    Konto nie istnieje  
  • #7 6820164
    Chivo
    Poziom 27  
    Posty: 1326
    Pomógł: 81
    Ocena: 130
    Wielkie dzieki

    Dodano po 26 [minuty]:

    Jak do procka wysle 0x30 0x31 0x32 to nie dziala:


    
    SIGNAL (SIG_UART_RECV) //przerwanie generowane w momencie odebrania znaku
    {
       Bufor[i++]=UDR;
       if(i>=3)
       {
         i=0;
         if(Bufor[0]==0x30)
         {  
    	    if(Bufor[1]==0x31)
    		{
    		  if(Bufor[2]==0x32)
    		  {
    		    for(int k=0; k<6; k++)
    	        {
    		       USART_Transmit(k);
                }
              }       
            }
         }
       }
    }
  • #8 6820293
    Konto nie istnieje
    Konto nie istnieje  
  • #9 6820314
    Chivo
    Poziom 27  
    Posty: 1326
    Pomógł: 81
    Ocena: 130
    Niestety nic nie wysyła
  • #10 6820352
    Konto nie istnieje
    Konto nie istnieje  
  • REKLAMA
  • #11 6820359
    Chivo
    Poziom 27  
    Posty: 1326
    Pomógł: 81
    Ocena: 130
    Komunikacja jest dobra bo wczesniejszy program działał (ten co sprawdzal tylko bufor[1]). Jak dodałem sprawdzanie bufora[0] i bufora[2] to przestało działac.

    Dodano po 1 [godziny] 45 [minuty]:

    Problem jest w tym ze jak do procka wysle 0x30 0x31 0x32 i kaze mu odeslalc to co wpisalem to odsyla cos innego. Moze to jakies zaklocenia??
  • #12 6820896
    GrEG0
    Poziom 14  
    Posty: 65
    Pomógł: 8
    Po pierwsze ja bym wywalił wysyłanie po RS232 z obsługi przerwania odbioru RS232.

    Po drugie odbierz najpierw całą paczkę, a potem analizuj co odebrałeś.
    Jak odbierzesz znak końca danych to ustaw sobie jakąś flagę i potem w programie głównym przeanalizujesz całą odebraną paczkę. Ja tak zawsze robię i działa bez problemu.

    Pozdr.
  • #13 6820953
    Chivo
    Poziom 27  
    Posty: 1326
    Pomógł: 81
    Ocena: 130
    A mozesz podeslac fragment kodu bo walcze z tym juz od poludnia

    Dodano po 9 [minuty]:

    Zrbiłem tak i dalej nic nie wysyla:
    
    SIGNAL (SIG_UART_RECV) 
    { 
       znak=UDR;
    } 
    W programie głównym mam:
    while(1)
    { 
      if(znak==0x31)
      {
        USART_Transmit(6);
      } 
    }
  • #14 6820989
    Konto nie istnieje
    Konto nie istnieje  
  • #15 6821001
    Chivo
    Poziom 27  
    Posty: 1326
    Pomógł: 81
    Ocena: 130
    Tak jest volatile i dziala ale ja chce cala paczke a nie jeden znak

    Dodano po 1 [minuty]:

    Jak dam bufor[i]=udr to nie dziala a jak jest zna =udr to dziala
  • #17 6822118
    Chivo
    Poziom 27  
    Posty: 1326
    Pomógł: 81
    Ocena: 130
    OK moj problem jest taki ze po wyslaniu do procka sekwencji 0x30 0x31 0x32 powinien on wysylac 6 ale nic mi nie wysyla
    
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    
    #define WR            PD6
    #define A1            PD5
    #define A0            PD4
    #define predkosc      600
    #define czestotliwosc 1000000
    #define MYUBRR        czestotliwosc/16/predkosc-1 
    
    volatile unsigned char Bufor[10];
    volatile unsigned int i = 0;
    
    
    //inicjalizacja RS232 
    void USART_Init(unsigned int UBRR)      
    { 
       UBRRH = (unsigned char) (UBRR>>8);    
       UBRRL = (unsigned char) UBRR; 
       UCSRB = (1<<RXEN) |(1<<TXEN)|(1<<RXCIE); // transmisja dwukierunkowa, odbieranie/nadawanie 
       UCSRC = (1<<URSEL)|(0<<USBS)|(3<<UCSZ0); // ustawienie 8 bitów danych i 1 bity stopu
       sei(); 
    }
    //nadawanie przez rs232
    void USART_Transmit(unsigned char data)     
    { 
       while (!(UCSRA & (1<<UDRE)))
       ; 
       UDR = data; 
    } 
    //odbior RS232 ramka ma 3 bajty
    SIGNAL (SIG_UART_RECV) 
    { 
       Bufor[i]=UDR;
       i++;
       if(i>=3)
       {
          i=0;
       }
    } 
    //-------------------------------
    int main(void)
    {
    
    USART_Init(MYUBRR);
    
    while(1)
    { 
      if(Bufor[0]==0x30 && Bufor[1]==0x31 && Bufor[2]==0x32)
      {
        USART_Transmit(6);
      } 
    }
    return 0;
    }
    
    


    Dodano po 32 [minuty]:

    Zauwazylem cos takiego ze jesli wpisze w petli if tylko jeden warunek np: na bufor[0] ==0x30 to dziala. Czy to mozliwe ze w bufor sa jakies smieci???
  • #18 6822433
    GrEG0
    Poziom 14  
    Posty: 65
    Pomógł: 8
    Wycinek kodu z mojego programu:

    
    #define F_CPU 8000000UL
    #define MAX_LEN	60
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    
    #define	CD_TRANS_START		0x01
    #define	CD_TRANS_STOP		0x04
    #define     CD_TRANS_BLOCK_STOP	0x05
    #define	CD_EVENT		                0x13
    
    volatile unsigned char buf_event[MAX_LEN+1];   //buf_event[0] - zawiera iloœæ znaków w buforze, pierwszy znak jest w buf_event[1]
    
    volatile unsigned char count,f1,f2, data_ready;
    
    //UART INIT  (RS232)  Baud 38400, BITS 8, STOP 1
    void usart_init(void)
    {
    	UBRRL = 25;  //38400
    	UBRRH = 0;
    	UCSRB = (1<<RXEN) | (1<<RXCIE) | (0<<UDRIE);
    	UCSRA = (1<<U2X);
    	UCSRC = (1<<URSEL) | (0<<USBS) | (3<<UCSZ0);
    
    }
    
    
    // UART interrupt
    //SIGNAL(SIG_UART_RECV)
    ISR(USART_RXC_vect)
    {
    	unsigned char buf;
    
     	buf=UDR;	
    	switch(buf)
    	{
    		case CD_EVENT: f1=buf; count=0; break;
    		case CD_TRANS_START: count=0;f2=buf;break;
    		case CD_TRANS_STOP: f2=buf; count=0; data_ready=1; break;
    		//case CD_TRANS_BLOCK_STOP: f2=buf; count=0; break;
    		case CD_TRANS_BLOCK_STOP: 
    				{
    					switch (f1)
    					{
    						case CD_EVENT:  
    									buf_event[0]=count; 
    									count=0;
    									f1=0;
    								break;
    					}
    				} // end of CD_TRANS_BLOCK_STOP
    		
    		default: {
    				switch (f1)
    				{
    					case CD_EVENT:
    						if (count<MAX_LEN)
    						{
    							count++;
    							buf_event[count]=buf;
    						}
    						break;
    				  }
    				}
    	}
    
    } 
    
    void delay_ms(unsigned int ms)
    {
      unsigned int t;
      for(t=0; t<=ms; t++)
      _delay_ms(1);
    }
    
    int main(void)
    {
    	count = 0;
    	data_ready = 0;
    	
    	usart_init();
    	sei();
    	while (1)
    
       	{
    	if (data_ready)
    		{
    			/*
    	         	tutaj twoj kod
    			*/
    		}
    	}
       return(0);
    } 
    


    Przesyłanie u mnie wygląda następująco:

    CD_TRANS_START
    CD_EVENT
    "dane do przesłania" ( u mnie dane nie mogą zawierać znaków sterujących)
    CD_BLOCK_STOP
    CD_TRANS_STOP

    Ja odrazu usuwam w przerwaniu znaki sterujące transmisją i ładuję do odpowiedniego bufora dane, a do buf_event[0] ładuję ilość odebranych danych. Wszystko oczywiście zależy od tego jak szybko ma być przerwanie obsługiwane. Jeżeli szybko to ładujesz wszystko do jednego bufora i dopiero w pętli głównej dokonujesz analizę danych.
  • REKLAMA
  • #20 6822680
    Chivo
    Poziom 27  
    Posty: 1326
    Pomógł: 81
    Ocena: 130
    Dzieki GREGO za kod a mozesz mi go przerobic tak zeby nie wyrzucac tych znaków sterujących i wszystko zapisywac do tablicy a w programie głównym je sprawdzac????????
  • #22 6822729
    Chivo
    Poziom 27  
    Posty: 1326
    Pomógł: 81
    Ocena: 130
    Jeszcze pytanie: obrobka danych jest w bloku default????

    Dodano po 44 [minuty]:

    Wysłałem do procka sekwencje: 0x01 0x13 0xff(dane) 0x05 0x04 i dalej nic nie wysyła a powinno odbierac 6
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    
    #define MAX_LEN 60
    #define predkosc      600
    #define czestotliwosc 1000000
    #define MYUBRR        czestotliwosc/16/predkosc-1 
    
    #define   CD_TRANS_START       0x01 
    #define   CD_TRANS_STOP        0x04 
    #define   CD_TRANS_BLOCK_STOP  0x05 
    #define   CD_EVENT             0x13 
    
    volatile unsigned char buf_event[MAX_LEN+1];   
    volatile unsigned char count,f1,f2, data_ready; 
    
    
    //inicjalizacja RS232 
    void USART_Init(unsigned int UBRR)      
    { 
       UBRRH = (unsigned char) (UBRR>>8);    
       UBRRL = (unsigned char) UBRR; 
       UCSRB = (1<<RXEN) |(1<<TXEN)|(1<<RXCIE); // transmisja dwukierunkowa, odbieranie/nadawanie 
       UCSRC = (1<<URSEL)|(0<<USBS)|(3<<UCSZ0); // ustawienie 8 bitów danych i 1 bity stopu
       sei(); 
    }
    //nadawanie przez rs232
    void USART_Transmit(unsigned char data)     
    { 
       while (!(UCSRA & (1<<UDRE)))
       ; 
       UDR = data; 
    } 
    //odbior RS232 
    ISR(USART_RXC_vect) 
    { 
       unsigned char buf; 
    
        buf=UDR;    
       switch(buf) 
       { 
          case CD_EVENT: f1=buf; count=0; break; 
          case CD_TRANS_START: count=0;f2=buf;break; 
          case CD_TRANS_STOP: f2=buf; count=0; data_ready=1; break; 
          case CD_TRANS_BLOCK_STOP: 
                { 
                   switch (f1) 
                   { 
                      case CD_EVENT:  
                               buf_event[0]=count; 
                               count=0; 
                               f1=0; 
                            break; 
                   } 
                } 
           
          default: { 
                switch (f1) 
                { 
                   case CD_EVENT: 
                      if (count<MAX_LEN) 
                      { 
                         count++; 
                         buf_event[count]=buf; 
                      } 
                      break; 
                  } 
                } 
       } 
    
    } 
    
    //-------------------------------
    int main(void)
    {
    
    USART_Init(MYUBRR);
    count=0;
    data_ready=0;
    
    while(1)
    { 
      if(data_ready)
      {
         USART_Transmit(6); 
      }
    }
    return 0;
    }
    
    
  • #23 6823178
    GrEG0
    Poziom 14  
    Posty: 65
    Pomógł: 8
    Przed USART_TRansmit powiniens jeszcze dać data_ready=0.

    Jaki procesor używasz i jaki prędkość transmisji ?
  • #24 6823216
    Chivo
    Poziom 27  
    Posty: 1326
    Pomógł: 81
    Ocena: 130
    Procesor atmega32 wew. kwarc 1MHz baud: 600
  • #25 6823238
    GrEG0
    Poziom 14  
    Posty: 65
    Pomógł: 8
    Akurat mam taki pod ręką :)
    Wieczorem przerobie to i ci podeślę ;)
  • #26 6823241
    Chivo
    Poziom 27  
    Posty: 1326
    Pomógł: 81
    Ocena: 130
    Wpisalem przed usart transmit data_ready=0 ale to nie pomaga
    Mozesz mi napisac to przerwanie tak ze wszystkie bajty(np3) z udr bedzie mi wpisywac kolejno do tablicy a potem w main bedzie je powornywac ze wzocowymi. Dałbym ci za to punkty bo bardzo jest mi to potrzebne do dyplomu

    Dodano po 12 [minuty]:

    bufor[0]=1 wartosc udr
    bufor[1]=druga wartosc udr
    bufor[2]=trzecia wartosc udr

    potem w main ma sprawdzic bufor z wartosciami wzorcowymi 0x30 0x31 0x32 i jesli sie zgadza to ma wyslac np:4
  • #27 6824439
    GrEG0
    Poziom 14  
    Posty: 65
    Pomógł: 8
    Tak wygląda przykładowy kod.
    Przetestowany na wew. 8MHz i 38400 baudrate.

    Mam nadzieję, że zrozumienie kodu nie będzie trudne. :)

    
    #define F_CPU 8000000UL
    
    #define MAX_LEN	10
    
    #include <stdbool.h>
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    #include <avr/pgmspace.h>
    #include <util/delay.h>
    
    
    volatile unsigned char buffer[MAX_LEN];
    volatile unsigned char counter, data_ready;
    
    
    //UART INIT  (RS232)  Baud 38400, BITS 8, STOP 1
    void usart_init(void)
    {
    	UBRRL = 25;  //38400
    	UBRRH = 0;
    //włączenie odbiornika
    //włączenie nadajnika
    //włączenie przerwania odbiornika (dane odebrane)
    
    	UCSRB = (1<<RXEN) | (1<<RXCIE) | (0<<UDRIE) | (1<<TXEN);
    	UCSRA = (1<<U2X);
    	UCSRC = (1<<URSEL) | (0<<USBS) | (3<<UCSZ0);
    
    	//return;
    }
    
    
    // UART interrupt
    ISR(USART_RXC_vect)
    {
    	unsigned char buf;
    
     	buf=UDR;	
    	
    	if (data_ready == 0) // jezeli nie odczytano w main poprzednich danych to pomin nowe
    	{
    		if (buf==0x30)
    		{
    			counter = 0;
    			buffer[counter] = buf;
    		} else
    			{
    				counter++;
    				buffer[counter] = buf;
    				
    				if (counter==2) data_ready = 1;
    			}
    	}
    
    } 
    
    void USART_Transmit(unsigned char Data)
    {
    
    	while( (UCSRA & (1<<UDRE) ) == 0);
    
    	UDR = Data;
    }
    
    
    void delay_ms(unsigned int ms)
    {
      unsigned int t;
      for(t=0; t<=ms; t++)
      _delay_ms(1);
    }
    
    
    /*
    *********************************************
    ******************** MAIN *******************
    *********************************************
    */
    int main(void)
    {
    
    	
    	counter = 0;		// char counter
    	data_ready = 0;
    	
    	usart_init();	// init UART
    	sei();			// enable interrupt 
    //-------------------------------------------------------------	
    
    	while (1)	
    	{
    		if (data_ready == 1 )
    		{
    			if ((buffer[0]==0x30) && (buffer[1]==0x31) && (buffer[2]==0x32))
    			{
    				USART_Transmit('4');
    				buffer[0]=0;
    				buffer[1]=0;
    				buffer[2]=0;
    			}
    
    			counter = 0;
    			data_ready = 0;
    		}
    
    	}
      
       return(0);
    } 
    
    
  • #28 6825243
    Mirek Z.
    VIP Zasłużony dla elektroda
    Posty: 21870
    Pomógł: 1132
    Ocena: 531
    Regulamin - p.8.1 i p.16.

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy problemu odbioru całej ramki danych z interfejsu RS232 za pomocą przerwania w funkcji obsługi sygnału SIG_UART_RECV (lub ISR USART_RXC_vect) na mikrokontrolerze AVR, w szczególności na modelu ATmega32 z wewnętrznym kwarcem 1 MHz i prędkością transmisji 600 baud. Autor chce odbierać wielobajtową ramkę (np. 3 bajty: początek, dane, koniec), zapisywać ją do bufora i dopiero po odebraniu całej ramki analizować jej zawartość w głównej pętli programu, a nie reagować na pojedynczy znak w przerwaniu. W dyskusji podkreślono, że przerwanie powinno jedynie odbierać kolejne bajty i zapisywać je do tablicy, a przetwarzanie danych powinno odbywać się poza przerwaniem, po ustawieniu flagi informującej o gotowości danych. Zwrócono uwagę na konieczność deklaracji zmiennych współdzielonych z przerwaniem jako volatile oraz na poprawne inicjalizowanie indeksu bufora. Zaproponowano przykładowe implementacje przerwania odbioru, które inkrementują licznik bajtów i po osiągnięciu oczekiwanej długości ramki lub po odebraniu znaku końca ramki ustawiają flagę gotowości danych. Wskazano także, że wysyłanie danych przez USART nie powinno odbywać się bezpośrednio w przerwaniu odbioru. Podano fragmenty kodu inicjalizacji USART i obsługi przerwania dla różnych prędkości i konfiguracji. Ostatecznie zaproponowano wzorcowy kod, w którym przerwanie odbiera kolejne bajty do bufora, a w pętli głównej następuje porównanie odebranych danych z wzorcem i ewentualne wysłanie odpowiedzi.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA