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

[ATtiny2313] [C] Dziwaczny błąd

ADI-mistrzu 14 Cze 2009 20:44 1433 7
REKLAMA
  • #1 6656173
    ADI-mistrzu
    Poziom 30  
    Witam!
    Chciałem dziś "pogadać" z układem scalonym przez SDIO w ten sposób że wysyłam informacje przez RS232 do µC a on "rozmawia" z urządzeniem peryferyjnym i odsyła z powrotem do PC otrzymane informacje.
    Niby zadanie proste, tym bardziej że ATtiny2313 posiada wbudowaną obsługę szeregową.
    Ale widocznie los nie jest tak łaskawy...

    W pewnym momencie pisząc program postanowiłem go przetestować i zobaczyć czy połączy się z urządzeniem peryferyjnym. W tym momencie pojawił się problem taki, że kontroler odbiera informacje które mu wysyłam ale nic z nimi nie robi.

    Kod:
    #include <avr/io.h> //główna biblioteka
    #include <avr/interrupt.h> //biblioteka od przerwań
    
    #define F_CPU 8000000UL //taktowanie wew. zegara 8MHz
    #include <util/delay.h> //biblioteka od przerwań
    
    #define UART_BAUD 9600 //prędkość transmisji szeregowej
    #define UART_CONST (F_CPU/(16ul*UART_BAUD)-1) //obliczanie kodu
    
    #define LED_ON PORTD |= _BV(3) //włącz diode sygnalizacyjną
    #define LED_OFF PORTD &= ~_BV(3) //wyłącz diodę sygnalizacyjną
    
    #define CAM1 0 //pin od urządzenia peryferyjnego 
    #define ON_CAM1 DDRB |= _BV(CAM1); PORTB &= ~_BV(CAM1) //włącz je
    #define OFF_CAM1 DDRB &= ~_BV(CAM1); PORTB |= _BV(CAM1) //wyłącz je
    
    unsigned int i, znak=2; //deklaracja zmiennych
    //----------------------------------------------------------------------------------------------
      void Init_RS232(void){ //Funkcja włączająca transmisję RS232
        UBRRH = (unsigned char)(UART_CONST>>8); //wpisanie prędkości transmisji
        UBRRL = (unsigned char)UART_CONST;
        UCSRB = _BV(RXEN) | _BV(RXCIE) | _BV(TXEN); //transmisja w obydwie strony z obsługą przerwania od pobierania informacji
        UCSRC = ~_BV(UMSEL); // transmisja asynchroniczna
      }
    
      void Init_Synchronics(void){ // Funkcja od transmisji SDIO
        UBRRH = (unsigned char)(UART_CONST>>8); //wpisanie prędkości transmisji
        UBRRL = (unsigned char)UART_CONST;
        UCSRB = _BV(RXEN) | _BV(TXEN); //transmisja w obydwie strony
        UCSRC = _BV(UMSEL) | _BV(UCSZ0) | _BV(UCSZ1) | ~_BV(USBS); //synchroniczna, 8bitów i 1bit stopu
      }
    
       SIGNAL(SIG_USART0_RECV) //przerwanie od pobierania danych z RS232
       {
          while( !(UCSRA & (1<<RXC)) ); //czekaj aż zakończona zostanie transmisja
          znak = UDR; //wpisz otrzymaną daną do zmiennej "znak"
       }
    
      void wyslij(unsigned char data){ //funkcja od wysyłania informacji
        while( !(UCSRA & (1<<UDRE)) );
        UDR = data;
      }
    
      unsigned char odbior(void){ //funkcja od odbioru informacji
        while( !(UCSRA & (1<<RXC)) );
        return UDR;
      }
    
    
    int main(void) //--------------------------------------------------------------------
    {
    
    DDRD = 0x08; //pin 4 w stanie wysokiem
      PORTD= 0xF7;
    
    DDRB = 0xFF;
      PORTB = 0xFE;
    
    Init_RS232(); //inicjacja RS232
    
    OFF_CAM1; //wyłącz urządzenie peryferyjne
    
     sei(); //włącz przerwania
    
     while(1){
    
    wyslij(znak); //wyślij przez RS232 otrzymany znak
    _delay_ms(255);
    _delay_ms(255);
    _delay_ms(255);
    
    }
    }

    I owy program powinien zadziałać tak, że gdy wysyłam powiedzmy liczbę 23 przez RS232 to taką także powinienem otrzymać. Efekt jest taki że otrzymuję liczbę 2 (czyli liczbę którą przypisałem przy deklarowaniu zmiennej).

    Próbowałem to zrobić nawet za pomocą wskaźnika:
    
    ...
    int *wektor = &znak;
    ...
       SIGNAL(SIG_USART0_RECV)
       {
          while( !(UCSRA & (1<<RXC)) );
          *wektor = UDR;
       }
    ...

    Ale efekt jest ten sam.
    Siedzę nad tym niemal cały dzień i już skończyły mi się pomysły.

    Programuję w środowisku Linux za pomocą AVRDUDE.

    Pozdrawiam
  • REKLAMA
  • #2 6656246
    _Robak_
    Poziom 33  
    Jakis przedziwny zapis z tym
    UCSRC = _BV(UMSEL) | _BV(UCSZ0) | _BV(UCSZ1) | ~_BV(USBS)

    Odwrociles sobie polaryzacje clocka, daj tak
    UCSRC =_BV(UMSEL) | _BV(UCSZ0) | _BV(UCSZ1);


    Dalej, w nowych projektach nie uzywaj SIGNAL, tylko ISR, wiecej na
    http://www.gnu.org/savannah-checkouts/non-gnu...-libc/user-manual/group__avr__interrupts.html

    Dalej
    Cytat:
    [..]//inicjacja RS232

    Inicjacja to wiesz jaka moze byc ;) To jest inicjalizacja ;)

    Zamiast
    while( !(UCSRA & (1<<UDRE)) );

    stosuj funkcje
    loop_until_bit_is_clear(UDRE,UCSRA)

    Funkcja odwrotna to (przyklad dla IO):
    
    loop_until_bit_is_set(PORTB,PB3)
    

    Jak dalej nie bedzie dzialalo to bedziemy wlaczyc dalej :P
  • REKLAMA
  • #3 6656390
    arrevalk
    Poziom 25  
    Może się mylę ale po kodzie który pokazałeś nie widać aby program co kolwiek robił z danymi odebranymi po rs poza odesłaniem ich do nadawcy.
    Niestety nieważne jak cudowny jest procesor, sam niczego nie zrobi ;)
  • #4 6656483
    ADI-mistrzu
    Poziom 30  
    Jak odwróciłem polaryzacje ? USBS służy chyba do ustawiania czy ma być 1 bit spotu czy 2. Po za tym czy przypadkiem nie dawanie go w ogóle w formule a wpisanie przez ~_BV to nie to samo ?

    Popoprawiałem resztę i w tej chwili to wygląda tak:
    ...
    unsigned int znak=2;
    int *wektor = &znak;
    unsigned int i;
    
      void Init_RS232(void){
        UBRRH = (unsigned char)(UART_CONST>>8);
        UBRRL = (unsigned char)UART_CONST;
        UCSRB = _BV(RXEN) | _BV(RXCIE) | _BV(TXEN);
        UCSRC = ~_BV(UMSEL);
      }
    
      void Init_Synchronics(void){
        UBRRH = (unsigned char)(UART_CONST>>8);
        UBRRL = (unsigned char)UART_CONST;
        UCSRB = _BV(RXEN) | _BV(TXEN);
        UCSRC = _BV(UMSEL) | _BV(UCSZ0) | _BV(UCSZ1);
      }
    
       ISR(USART_RX_vect)
       {
         loop_until_bit_is_set(UCSRA,RXC);
         *wektor = UDR;
       }
    
      void wyslij(unsigned char data){
        loop_until_bit_is_set(UCSRA,UDRE);
        UDR = data;
      }
    
      unsigned char odbior(void){
        loop_until_bit_is_set(UCSRA,RXC);
        return UDR;
      }
    
    int main(void)
    {
    
    DDRD = 0x08;
      PORTD= 0xF7;
    
    DDRB = 0xFF;
      PORTB = 0xFE;
    
    OFF_CAM1;
    Init_RS232();
     sei();
    LED_OFF;
    
     while(1){
    
    LED_ON;
    wyslij(znak);
    _delay_ms(255);
    _delay_ms(255);
    LED_OFF;
    _delay_ms(255);
    _delay_ms(255);
    
    }}

    I efekt jest taki sam, nic się nie zmieniło, dalej same 2 lecą bez znaczenia co wyślę przez RS.

    Do arrevalk:
    ADI-mistrzu napisał:
    I owy program powinien zadziałać tak, że gdy wysyłam powiedzmy liczbę 23 przez RS232 to taką także powinienem otrzymać. Efekt jest taki że otrzymuję liczbę 2 (czyli liczbę którą przypisałem przy deklarowaniu zmiennej).

    Tak na razie ma zadziałać a jednak tak się nie dzieje.
  • REKLAMA
  • #5 6657029
    arrevalk
    Poziom 25  
    Bo w pętli wysyłasz zmienną znak:
    ADI-mistrzu napisał:

    
    unsigned int znak=2;
    int *wektor = &znak;
    //CIACH
    ISR(USART_RX_vect)
       {
         loop_until_bit_is_set(UCSRA,RXC);
         *wektor = UDR;
       } 
    //CIACH
     while(1){
    
    LED_ON;
    wyslij(znak);
    _delay_ms(255);
    _delay_ms(255);
    LED_OFF;
    _delay_ms(255);
    _delay_ms(255);
    
    }}


    a w przerwaniu odebrane dane zachowujesz na wskaźniku wektor. I zmień typ zmiennych znak i wektor na char lub unsigned char, przecież to 8bit znaki są. Nie rozumiem tez dlaczego zmiennej wektor przypisujesz adres zmiennej znak nie prościej zostawić jedną z nich?
  • Pomocny post
    #6 6657330
    Dr.Vee
    VIP Zasłużony dla elektroda
    Po co ten wskaźnik na dane? Zrób:
    volatile unsigned char znak;
    
    ISR(USART_Rx_vect) {
        znak = UDR;
    }

    Po co czekanie na RXC == 1 w przerwaniu uarta? Przecież jest to warunek wygenerowania przerwania....

    Zapis:
    UCSRC = ~_BV(UMSEL)
    oznacza, że przypisujesz do UCSRC wartość 10111111. Chyba nie o to Ci chodziło.

    Pozdrawiam,
    Dr.Vee
  • REKLAMA
  • #7 6657698
    ADI-mistrzu
    Poziom 30  
    Wskaźnika już później użyłem, myślałem że może traktuje go bardziej jak funkcje i wpisuje jako zmienną lokalną przez co na zewnątrz nic nie widać.
    Z tym UCSRC faktycznie zapomniałem... usunąłem w ogóle tą linijkę.

    Lecz efekt ten sam, nadal jest zwracana tylko 2.

    Jeśli do przerwania wrzucę opóźnienie i włączanie diod:
       ISR(USART_RX_vect)
       {
    LED_ON;
         znak = UDR;
       _delay_ms(255);
       _delay_ms(255);
       _delay_ms(255);
       _delay_ms(255);
    LED_OFF;
    }

    To zapali się dłuższy czas po wysłaniu znaku czyli niby przerwanie działa.
    A czemu mimo to nic jak by nie odbiera ?

    --EDIT----------------------------------------------------------------------

    Dodałem jeszcze volatile do deklaracji zmiennej znak na char, no i to pomogło. Nigdy nie czytałem o tym przydomku, nawet bym się nie spodziewał że to przez optymalizacje kodu :|.

    Dziękuję bardzo za pomoc.
  • Pomocny post
    #8 6657720
    _Robak_
    Poziom 33  
    Jak zadeklarujesz zmienna znak jako volatile unsigned char to powinno byc lepiej ;)
REKLAMA