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

[atmega] [c] [avr-gcc] problem

staviq 11 Paź 2009 20:27 2117 3
REKLAMA
  • #1 7116887
    staviq
    Poziom 12  
    Witam, mam problem z kodem ( no właśnie, to sie okaże :) ):
    
    #define F_CPU 16000000UL
    #include <stdio.h>
    #include <ctype.h>
    #include <stdlib.h>
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    #include <avr/pgmspace.h>
    #define UART_BAUD   115200         //prędkość transmisji
    #define UART_CONST   (F_CPU/((16*UART_BAUD)-1))
    
    #define rxbufsize 64
    char * rxbuf;
    volatile char * rxbufptrwrite;
    volatile char * rxbufptrread;
    
    void USART_Transmit( unsigned char data )
    {
    	/* Wait for empty transmit buffer */
    	while ( !( UCSRA & (1<<UDRE)) );
    	/* Put data into buffer, sends the data */
    	UDR = data;
    }
    
    unsigned char USART_Receive( void )
    {
    	while( rxbufptrwrite == rxbufptrread );
    	
    	char c = *rxbufptrread;
    	
    	++rxbufptrread;
    	
    	if( rxbufptrread == rxbufptrwrite )
    	{
    		rxbufptrwrite = rxbuf;
    		rxbufptrread = rxbuf;
    	}
    	
    	return c;
    }
    
    void USART_Init( unsigned int ubrr)
    {
    	/* Set baud rate */
    	UBRRH = (unsigned char)(ubrr>>8);
    	UBRRL = (unsigned char)ubrr;
    	/* Enable receiver and transmitter / rx interrupt */
    	UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
    	/* Set frame format: 8data, 2stop bit */
    	UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
    }
    
    ISR( USART_RXC_vect ) // USART RX interrupt
    {
    	if( (rxbufptrwrite - rxbuf) < rxbufsize )
    	{
    		USART_Transmit('z');
    		
    		*rxbufptrwrite = UDR;
    		++rxbufptrwrite;
    		
    		USART_Transmit( *rxbufptrread );
    		USART_Transmit( *(rxbufptrwrite-1) );
    	}
    	else
    	{
    		//ignoring input
    		char c = UDR;
    	}
    	
    }
    
    void mshort()
    {
    	PORTC |= ( 1 << PC5 ); // dioda on
    	_delay_ms( 70 );
    	PORTC &= !( 1 << PC5 ); // dioda off
    	_delay_ms( 50 );
    }
    
    void mlong()
    {
    	PORTC |= ( 1 << PC5 ); // dioda on
    	_delay_ms( 200 );
    	PORTC &= !( 1 << PC5 ); // dioda off
    	_delay_ms( 50 );
    }
    
    void moff()
    {
    	PORTC &= !( 1 << PC5 ); // dioda off
    	_delay_ms( 250 );
    }
    
    int main(void)
    {
    	DDRD=0x02;
    	PORTD=0x00;
    	
    	USART_Init( UART_CONST );
    	
    	rxbuf = malloc( rxbufsize );
    	rxbufptrwrite = rxbuf;
    	rxbufptrread = rxbuf;
    	
    	FILE mystdout = FDEV_SETUP_STREAM( USART_Transmit, NULL, _FDEV_SETUP_WRITE );
    	FILE mystdin = FDEV_SETUP_STREAM( NULL, USART_Receive, _FDEV_SETUP_READ );
    	
    	stdout = &mystdout;
    	stdin = &mystdin;
    	
    	sei();
    	
    	for(;;)
    	{
    		static char c;
    		
    		while ( c = fgetc( stdin ) )
    		{
    			switch( c )
    			{
    				case 'a': { mshort(); mlong(); break; }
    				case 'b': { mlong(); mshort(); mshort(); mshort(); break; }
    				case 'c': { mlong(); mshort(); mlong(); mshort(); break; }
    				case 'd': { mlong(); mshort(); mshort(); break; }
    				case 'e': { mshort(); break; }
    				case 'f': { mshort(); mshort(); mlong(); mshort(); break; }
    				case 'g': { mlong(); mlong(); mshort(); break; }
    				case 'h': { mshort(); mshort(); mshort(); mshort(); break; }
    				case 'i': { mshort(); mshort(); break; }
    				case 'j': { mshort(); mlong(); mlong(); mlong(); break; }
    				case 'k': { mlong(); mshort(); mlong(); break; }
    				case 'l': { mshort(); mlong(); mshort(); mshort(); break; }
    				case 'm': { mlong(); mlong(); break; }
    				case 'n': { mlong(); mshort(); break; }
    				case 'o': { mlong(); mlong(); mlong(); break; }
    				case 'p': { mshort(); mlong(); mlong(); mshort(); break; }
    				case 'q': { mlong(); mlong(); mshort(); mlong(); break; }
    				case 'r': { mshort(); mlong(); mshort(); break; }
    				case 's': { mshort(); mshort(); mshort(); break; }
    				case 't': { mlong(); break; }
    				case 'u': { mshort(); mshort(); mlong(); break; }
    				case 'v': { mshort(); mshort(); mshort(); mlong(); break; }
    				case 'w': { mshort(); mlong(); mlong(); break; }
    				case 'x': { mlong(); mshort(); mshort(); mlong(); break; }
    				case 'y': { mlong(); mshort(); mlong(); mlong(); break; }
    				case 'z': { mlong(); mlong(); mshort(); mshort(); break; }
    			}
    			
    			if( 0 /*isalpha( c )*/ )
    			{
    				fputc( (((c - 'a')+13)%('z'-'a'))+'a', stdout );
    			}
    			else
    			{
    				fputc( c, stdout );
    			}
    			
    			moff();
    		}
    	}
    	
    	return 0;
    }
    


    problem polega na tym, że w części:
    
    unsigned char USART_Receive( void )
    {
    	while( rxbufptrwrite == rxbufptrread );
    

    warunek jest zawsze prawdziwy ( zmienne zawsze są równe / wskaźniki wskazują na to samo miejsce ) pomimo zwiększenia "rxbufptrwrite" tutaj:
    
    ISR( USART_RXC_vect ) // USART RX interrupt
    {
    	if( (rxbufptrwrite - rxbuf) < rxbufsize )
    	{
    		USART_Transmit('z');
    		
    		*rxbufptrwrite = UDR;
      ------->  ++rxbufptrwrite;
    		
    		USART_Transmit( *rxbufptrread );
    		USART_Transmit( *(rxbufptrwrite-1) );
    	}
    


    czyli w kolejności wykonania kodu:

    w pętli main prosimy o znak ( fgetc ), który pozyskiwany jest przez "USART_Receive()"
    a w tejże funkcji zatrzymujemy się na "while( rxbufptrwrite == rxbufptrread );"

    do tego miejsca jest ok. Ale gdy przez UART przychodzi znak i trafia do przerwania "ISR( USART_RXC_vect )" zmienna "rxbufptrwrite" jest zwiększana a wspomniana pętla while tego nie zauważa i dla niej "rxbufptrwrite" jest cały czas równe "rxbufptrread" natomiast w bloku przerwania ta zmienna się ładnie przesuwa i wskazuje na kolejne znaki co widać za pomocą
    
    		USART_Transmit( *rxbufptrread );
    		USART_Transmit( *(rxbufptrwrite-1) );
    


    Prawdopodobnie zrobiłem jakiś strasznie głupi błąd, bo tylko z takimi mam problem ponad cały dzień :)

    kod miał buforować znaki przychodzące z UART ponieważ są one bardzo wolno przetwarzane... Dodam że kod działał na 100% bez przerwania ze zwyczajnym oczekiwaniem na znak w "USART_Receive"...

    Pomóżcie bo mi ręce opadają już...
  • REKLAMA
  • Pomocny post
    #2 7117134
    michalko12
    Specjalista - Mikrokontrolery
    volatile char * rxbufptrwrite;
    volatile char * rxbufptrread;
    


    To nie wskaźniki są volatile tylko obszar pamięci na który wskazują.

    Spróbuj:
    volatile char * volatile rxbufptrwrite;
    volatile char * volatile rxbufptrread;
    


    ale w tym przykładzie powinno też Ci wystarczyć
    char * volatile rxbufptrwrite;
    char * volatile rxbufptrread;
    
  • REKLAMA
  • #3 7117782
    staviq
    Poziom 12  
    Dzięki wielkie, to było to.
  • #4 7117784
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Fajne nie? Prawdziwa jazda zaczyna się jednak dopiero wtedy, gdy takie wskaźniki mają być jeszcze statyczne [;

    uint32_t * volatile static ptr;
    


    ->

    ../main.cpp:49: error: expected unqualified-id before 'static'
    ../main.cpp:49: error: expected initializer before 'static'
    


    Ktoś mi to wytłumaczy skoro już przy tym jesteśmy? Czemu "const" i "volatile" działają "na prawo", a static "globalnie"? No dobra - w pewnej pokrętnej logice można by to zrozumieć, w końcu cel takiego wskaźnika nie może być static, ale jak dla mnie w takim wypadku lokalizacja tego słówka mogłaby być dowolna. Czy nie lepsza byłaby odrobina konsekwencji?

    4\/3!!
REKLAMA