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] [c] [avr-gcc] problem

11 Paź 2009 20:27 1925 3
  • Poziom 11  
    Witam, mam problem z kodem ( no właśnie, to sie okaże :) ):
    Code:

    #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:
    Code:

    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:
    Code:

    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ą
    Code:

          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ż...
  • Pomocny post
    Specjalista - Mikrokontrolery
    Code:
    volatile char * rxbufptrwrite;
    
    volatile char * rxbufptrread;


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

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


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

    Code:
    uint32_t * volatile static ptr;
    


    ->

    Code:
    ../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!!