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

[Atmega16][C] Problem z odbiorem ramki NMEA z GPS

golas17 24 Paź 2009 13:35 1988 2
REKLAMA
  • #1 7168754
    golas17
    Poziom 16  
    Witam,
    W celach testowych napisałem następujący kod:

    #include <stdlib.h>
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #define F_CPU 8000000L
    #include <util/delay.h>
    #include "lcd.h"
    
    
    const unsigned char OkToSend[]={"$PSRF150,1*3F"};
    const unsigned char DisableGPGGA[]={"$PSRF103,00,00,00,01*24rn"};
    const unsigned char DisableGPGSA[]={"$PSRF103,02,00,00,01*26rn"};
    const unsigned char DisableGPGSV[]={"$PSRF103,03,00,00,01*27rn"};
    const unsigned char DisableGPVTG[]={"$PSRF103,05,00,00,01*21rn"};
    
    const unsigned char sum[]={"PSRF103,03,00,00,01"};
    
    volatile unsigned char buf[100],j,k,zapis;
    volatile unsigned char i;
    
    //--------------------------------------------------------------------------------
    SIGNAL(USART_RXC_vect)
    {
    	if(UDR=='$')    zapis=1;	
    
    	if((i<14)&&(zapis))  
    	{
    		buf[i]=UDR;
    		i++;
    	}
    	
    	if(i>=14)
    	{
    		k=1;
    		zapis=0;
                    i=0;
    	}
    }
    
    
    //--------------------------------------------------------------------------------
    void USART_Transmit( unsigned char data )
    {
    /* Wait for empty transmit buffer */
    while ( !( UCSRA & (1<<UDRE)) )
    ;
    /* Put data into buffer, sends the data */
    UDR = data;
    }
    
    void uart_puts(const char *s )
    {
        while (*s) 
          USART_Transmit(*s++);
    
    }/* uart_puts */
    
    
    //--------------------------------------------------------------------------------
    int main()
    {
    		lcd_init(LCD_DISP_ON);		
    		
    		
       		UBRRL=103;
       		UCSRB|=_BV(RXEN)|_BV(TXEN)|_BV(RXCIE);
       		UCSRC|=_BV(URSEL)|_BV(UCSZ1)|_BV(UCSZ0); 
    		
    
    		sei();	
    				
    
    		uart_puts(DisableGPGGA);
    		uart_puts(DisableGPGSA);
    		uart_puts(DisableGPGSV);
    		uart_puts(DisableGPVTG);
    
    		while(1)
    		{
    			if((k)&&(!j))
    			{
    				j++;	
    				lcd_puts(buf);
    			}
    		}
    }
    


    Okazuje się, że nic się nie wyświetla... Odrobina dalszych testów pokazała, że np. kod autora ostatniego postu w tym temacie: Link działa. I mój problem jest podobny. Też zapisuje do bufora dopiero od drugiego znaku. Wie ktoś co to może być?
  • REKLAMA
  • Pomocny post
    #2 7168866
    arrevalk
    Poziom 25  
    Problem leży tu:
    SIGNAL(USART_RXC_vect)
    {
       if(UDR=='$')    zapis=1;   
    
       if((i<14)&&(zapis)) 
       {
          buf[i]=UDR;
          i++;
       }
       
       if(i>=14)
       {
          k=1;
          zapis=0;
                    i=0;
       }
    } 

    Otóż odczyt z rejestru UDR powoduje jego wyzerowanie a następnie załadowanie następnego odebranego znaku (jeżeli coś zostało odebrane). Więc dodaj zmienną lokalną w przerwaniu do której z rejestru UDR załadujesz odebrany znak, i potem tą zmienną wykorzystuj w przerwaniu. Właściwie to możesz ładować bezpośrednio do tablicy buf tylko pamiętać żeby nie zwiększać licznika gdy nie odebraliśmy znaku początku ramki.
    Druga sprawa to warto wykorzystać dwa bufory jeden do którego odbieramy dane i po zakończeniu kopiujemy go bufora roboczego, na którym działamy w programie. Zapobiegnie to sytuacji w której w trakcie pracy nad buforem nadpisujemy sobie dane.
  • #3 7169297
    golas17
    Poziom 16  
    Faktycznie pomogło. Poprawiłem kod tak jak poniżej:

    SIGNAL(USART_RXC_vect)
    {
    	odebrane=UDR;
    
    	if(odebrane=='$')    zapis=1;	
    
    	if((i<14)&&(zapis))  
    	{
    		buf[i]=odebrane;
    		i++;
    	}
    
    	
    	if(i>=14)
    	{
    		k=1;
    		zapis=0;
    	}
    	
    }


    Następnym razem będę bardziej wnikliwie czytał datasheety. Dziękuję za pomoc.
REKLAMA