Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[ATmega16][C]Odbieranie danych od procesora po RS232

NeooeN 16 Gru 2008 18:31 2346 6
  • #1 16 Gru 2008 18:31
    NeooeN
    Poziom 13  

    Witam!
    Mam problem z odbieraniem danych wysłanych przez ATmege po RS232. Program na ATMedze jest następujący

    Code:
    // Sterownie diodą LED podłączoną do dowolnej linii mikrokontrolera
    
    // za pomocą dowolnego znaku odebranego z portu szeregowego
    // mikrokontrolera i wysyłanie jej stanu na port szeregowy

    #include <avr/io.h>                // dostęp do rejestrów

    // Zmieniając poniższe definicje można dostosować program do potrzeb

    #define F_CPU                8000000ul         // częstotliwość zegara w Hz
    #define UART_BAUD        19200ul                // prędkość transmisji bit/s

    #define LED_PORT        PORTD                // port diody LED
    #define LED_BIT                4                // bit diody LED

    #define DDR(x) _SFR_IO8(_SFR_IO_ADDR(x)-1) // adr. rej. kier. PORTx
    #define PIN(x) _SFR_IO8(_SFR_IO_ADDR(x)-2) // adr. rej. wej. PORTx

    #define LED_PORT_O        LED_PORT             // rejestr wyjściowy
    #define LED_PORT_D        DDR(LED_PORT)   // rejestr kierunkowy
    #define LED_PORT_I        PIN(LED_PORT)   // rejestr wejściowy

    #define UART_CONST        (F_CPU/(16ul*UART_BAUD)-1)

    #define cbi(sfr, b) (sfr &= ~(1<<b)) // bit 0 na pin portu
    #define sbi(sfr, b) (sfr |= (1<<b))  // bit 1 na pin portu

    // _UCR_

    #ifdef        UCR
    #define _UCR_        UCR
    #endif

    #ifdef        UCSRB
    #define _UCR_        UCSRB
    #endif

    #ifdef        UCSR0B
    #define _UCR_        UCSR0B
    #endif

    // _USR_

    #ifdef        USR
    #define _USR_        USR
    #endif

    #ifdef        UCSRA
    #define _USR_        UCSRA
    #endif

    #ifdef        UCSR0A
    #define _USR_        UCSR0A
    #endif

    // Definicje funkcji

    // inicjalizacja portu szeregowego
    unsigned char UBRR = (unsigned char)UART_CONST;
    void UART_init(void)
    {
      UBRR = (unsigned char)UART_CONST;         // ustaw prędkość transmisji




      _UCR_ = _BV(RXEN)|_BV(TXEN);                // załącz tx, rx
    }

    // wysyła znak podany jako parametr na port szeregowy
    void UART_putchar (char c)
    {
      UDR = c;                                // wpisz c do rejestru UDR
      loop_until_bit_is_set(_USR_,TXC);        // czekaj na zakończenie transmisji
      sbi(_USR_,TXC);                                // ustaw bit TXC w rej. USR
    }

    // odbiera znak z portu szeregowego i zwraca go jako wartość funkcji
    char UART_getchar (void)
    {
      loop_until_bit_is_set(_USR_,RXC);        // czekaj na zakończenie odbioru
      cbi(_USR_,RXC);                                // skasuj bit RXC w rej. USR
      return UDR;                                // zwróć zawartość rejestru UDR
    }

    int main(void)                        // program główny
    {
      UART_init();                        // inicjalizacja portu szeregowego

      sbi(LED_PORT_D,LED_BIT);        // użyj linii jako wyjścia

      while(1)                        // pętla nieskończona
      {
        cbi(LED_PORT_O,LED_BIT);        // zapal diodę LED
        UART_putchar('1');                // wyślij '1' na port szeregowy
        UART_getchar();                // czekaj na znak z portu szeregowego
        sbi(LED_PORT_O,LED_BIT);        // zgaś diodę LED
        UART_putchar('0');                // wyślij '0' na port szeregowy
        UART_getchar();                // czekaj na znak z portu szeregowego
      }
    }
    Ma on za zadanie gasić i zapalać diodę po każdym odebranym znaku i odesłać znak '1' lub '0' w zależności od tego czy dioda świeci czy nie. Dioda zapala się lub gaśnie przy wysłaniu znaku przez terminal ale do terminala dochodzą tylko krzaczki. Próbowałem już zmieniać parametry transmisji na mniejsze prędkości ale zawsze jeżeli uda mi się zmusić diodę do poprawnego działania to i tak nie dostaję poprawnej odpowiedzi. Czy ma ktoś jakiś pomysł dlaczego tak się dzieje i jak jak to naprawić?

    0 6
  • Pomocny post
    #2 17 Gru 2008 02:05
    kasaidolar
    Poziom 19  

    Jak pojawiaja sie krzaczki to jest problem z predkoscia. W jakim programie piszesz? Jaki masz kwarc?

    Dodano po 11 [minuty]:

    Zobacz czy dziala Ci to:

    Code:

    // Sterownie diodą LED podłączoną do dowolnej linii mikrokontrolera
    // za pomocą dowolnego znaku odebranego z portu szeregowego
    // mikrokontrolera i wysyłanie jej stanu na port szeregowy

    #include <avr/io.h>                // dostęp do rejestrów

    // Zmieniając poniższe definicje można dostosować program do potrzeb

    #define F_CPU                8000000ul         // częstotliwość zegara w Hz

    #define LED_PORT        PORTD                // port diody LED
    #define LED_BIT                4                // bit diody LED

    #define DDR(x) _SFR_IO8(_SFR_IO_ADDR(x)-1) // adr. rej. kier. PORTx
    #define PIN(x) _SFR_IO8(_SFR_IO_ADDR(x)-2) // adr. rej. wej. PORTx

    #define LED_PORT_O        LED_PORT             // rejestr wyjściowy
    #define LED_PORT_D        DDR(LED_PORT)   // rejestr kierunkowy
    #define LED_PORT_I        PIN(LED_PORT)   // rejestr wejściowy


    #define cbi(sfr, b) (sfr &= ~(1<<b)) // bit 0 na pin portu
    #define sbi(sfr, b) (sfr |= (1<<b))  // bit 1 na pin portu



    // Definicje funkcji

    // inicjalizacja portu szeregowego
    void UART_Init( unsigned int baud )
    {
       /* Set baud rate */
       UBRRH = (F_CPU/(baud*16L)-1) >> 8; //(unsigned char)(baud>>8);
       UBRRL = (unsigned char)(F_CPU/(baud*16L)-1); //(unsigned char)baud;
       /* Enable receiver and transmitter */
       UCSRB = (1<<RXCIE)|(1<<TXEN)|(1<<RXEN);
          /* Set frame format: 8data, 1stop bit */
       UCSRC = (1<<URSEL)|(3<<UCSZ0);
    }

    // wysyła znak podany jako parametr na port szeregowy
    void UART_putchar (unsigned char c)
    {
         /* Wait for empty transmit buffer */
       while ( !( UCSRA & _BV(UDRE)) )
       ;
       
       /* Put data into buffer, sends the data */
       UDR = c;
    }

    // odbiera znak z portu szeregowego i zwraca go jako wartość funkcji
    unsigned char UART_getchar (void)
    {
         /* Wait for data to be received */
       while ( !(UCSRA & (1<<RXC)) )
       ;
       /* Get and return received data from buffer */
       return UDR;
    }

    int main(void)                        // program główny
    {
      UART_Init(19200);                        // inicjalizacja portu szeregowego

      sbi(LED_PORT_D,LED_BIT);        // użyj linii jako wyjścia

      while(1)                        // pętla nieskończona
      {
        cbi(LED_PORT_O,LED_BIT);        // zapal diodę LED
        UART_putchar('1');                // wyślij '1' na port szeregowy
        UART_getchar();                // czekaj na znak z portu szeregowego
        sbi(LED_PORT_O,LED_BIT);        // zgaś diodę LED
        UART_putchar('0');                // wyślij '0' na port szeregowy
        UART_getchar();                // czekaj na znak z portu szeregowego
      }
    }



    Dodano po 17 [minuty]:

    To w ogole w przerwaniu powinno byc :)

    0
  • #3 17 Gru 2008 03:35
    NeooeN
    Poziom 13  

    Zmieniłem linię z F_CPU na

    Code:
    #define F_CPU                16000000ul
    bo mam kwarc 16MHz, zamieszczam jeszcze zrzut ze swoimi fuse bitami bo nie wiem czy wszystko jest tak jak być powinno. Co prawda z tym programem krzaki są trochę inne ale nadal krzaki.

    0
  • Pomocny post
    #4 17 Gru 2008 11:03
    kasaidolar
    Poziom 19  

    Fusy wygladaja ok. Napisz w jakim programie programujesz. Ustawiles w terminalu tez odpowiednia predkosc? Sprawdzales ten moj program?

    0
  • Pomocny post
    #5 17 Gru 2008 11:18
    slawek-matyl
    Poziom 11  

    Witam
    kod do nadajnika może wyglądać tak:

    Code:

    #include <avr/io.h>
    #define F_CPU 1000000UL
    #include <util/delay.h>
    #include <avr/interrupt.h>


    //set desired baud rate
    #define BAUDRATE 1200
    //calculate UBRR value
    #define UBRRVAL    ((F_CPU/(BAUDRATE*16UL))-1)
    //define receive parameters
    #define SYNC 0XAA// synchro signal
    #define RADDR 0x44
    #define LEDON 0x11//switch led on command
    #define LEDOFF 0x22//switch led off command

    void USART_Init(void)
    {
       //Set baud rate
       UBRRL=(uint8_t)UBRRVAL;      //low byte
       UBRRH=(UBRRVAL>>8);   //high byte
       //Set data frame format: asynchronous mode,no parity, 1 stop bit, 8 bit size
       UCSRC=(1<<URSEL)|(0<<UMSEL)|(0<<UPM1)|(0<<UPM0)|
          (0<<USBS)|(0<<UCSZ2)|(1<<UCSZ1)|(1<<UCSZ0);   
       //Enable Transmitter and Receiver and Interrupt on receive complete
       UCSRB=(1<<TXEN);
    }
    void USART_vSendByte(uint8_t u8Data)
    {
        // Wait if a byte is being transmitted
        while((UCSRA&(1<<UDRE)) == 0);
        // Transmit data
        UDR = u8Data;
    }
    void Send_Packet(uint8_t addr, uint8_t cmd)
    {
       USART_vSendByte(SYNC);//send synchro byte   
       USART_vSendByte(addr);//send receiver address
       USART_vSendByte(cmd);//send increment command
       USART_vSendByte((addr+cmd));//send checksum
    }
    void delayms(unsigned int t)//delay in ms
    {
    unsigned int i;
    for(i=0;i<t;i++)
       _delay_ms(1);
    }
    int main(void)
    {
    USART_Init();
    while(1)
       {//endless transmission
       //send command to switch led ON
       Send_Packet(RADDR, LEDON);
       delayms(1000);
       //send command to switch led ON
       Send_Packet(RADDR, LEDOFF);
       delayms(1000);
       }
       return 0;
    }

    a odbiornika
    Code:

    #include <avr/io.h>
    #define F_CPU 1000000UL
    #include <util/delay.h>
    #include <avr/interrupt.h>



     void czekaj10ms(int a)
    {
       
       for(;a>0;--a)
       _delay_ms(10);
    }




    #define BAUDRATE 1200
    //calculate UBRR value
    #define UBRRVAL  ((F_CPU/(BAUDRATE*16UL))-1)
    //define receive parameters
    #define SYNC 0XAA// synchro signal
    #define RADDR 0x44
    #define LEDON 0x11//LED on command
    #define LEDOFF 0x22//LED off command

    void USART_Init(void)
    {
       //Set baud rate
       UBRRL=(uint8_t)UBRRVAL;      //low byte
       UBRRH=(UBRRVAL>>8);   //high byte
       //Set data frame format: asynchronous mode,no parity, 1 stop bit, 8 bit size
       UCSRC=(1<<URSEL)|(0<<UMSEL)|(0<<UPM1)|(0<<UPM0)|
          (0<<USBS)|(0<<UCSZ2)|(1<<UCSZ1)|(1<<UCSZ0);   
       //Enable Transmitter and Receiver and Interrupt on receive complete
       UCSRB=(1<<RXEN)|(1<<RXCIE);//|(1<<TXEN);
       //enable global interrupts

    }
    uint8_t USART_vReceiveByte(void)
    {
        // Wait until a byte has been received
        while((UCSRA&(1<<RXC)) == 0);
        // Return received data
        return UDR;
    }
    ISR(USART_RXC_vect)
    {
          PORTB&=~(1<<1); //test
       
       //define variables
       uint8_t raddress, data, chk;//transmitter address
       //receive destination address
       raddress=USART_vReceiveByte();
       //receive data
       data=USART_vReceiveByte();
       //receive checksum
       chk=USART_vReceiveByte();
       //compare received checksum with calculated
       if(chk==(raddress+data))//if match perform operations
       {
             
          //if transmitter address match
          if(raddress==RADDR)
             {
                if(data==LEDON)
                   {
                      PORTC&=~(1<<0);//LED ON
                   }
                else if(data==LEDOFF)
                   {
                      PORTC|=(1<<0);//LED OFF
                   }
                else
                {
                   //blink led as error
                   PORTC|=(1<<0);//LED OFF
                   _delay_ms(10);
                   PORTC&=~(1<<0);//LED ON   
                }
             }
       }
    }
    void Main_Init(void)
    {
       PORTC|=(1<<0);//LED OFF
       DDRC=0X001;//define port C pin 0 as output;
       //enable global interrupts
       DDRB=1<<1;
       PORTB&=~(1<<1);
       PORTC&=~(1<<0);
       czekaj10ms(200);
       PORTB=1<<1;
       PORTC|=(1<<0);
       czekaj10ms(200);
       
       sei();
    }
    int main(void)
    {

       Main_Init();
       USART_Init();
       while(1)
       {

       }
       //nothing here interrupts are working
       return 0;
    }

    działa napewno, testowałem to w transmisji bezprzewodowej do zdalnego sterowania autkiem. Możesz go oczywiście skrócić nie wysyłać adresu i sprawdzenia. Jest to transmisja jednokierunkowa, trochę zmienisz i będzie w dwie strony
    Pozdro

    0
  • #7 17 Gru 2008 22:43
    NeooeN
    Poziom 13  

    Po wielu próbach z różnymi parametrami transmisji na PC nadal nic nie wychodziło, dopiero w desperacji zmieniłem prędkość na 2x mniejszą i zadziałało. Podaje działający kod:

    Code:
    // Sterownie diodą LED podłączoną do dowolnej linii mikrokontrolera
    
    // za pomocą dowolnego znaku odebranego z portu szeregowego
    // mikrokontrolera i wysyłanie jej stanu na port szeregowy

    #include <avr/io.h>                // dostęp do rejestrów

    // Zmieniając poniższe definicje można dostosować program do potrzeb

    #define F_CPU                16000000ul         // częstotliwość zegara w Hz

    #define LED_PORT        PORTD                // port diody LED
    #define LED_BIT                4                // bit diody LED

    #define DDR(x) _SFR_IO8(_SFR_IO_ADDR(x)-1) // adr. rej. kier. PORTx
    #define PIN(x) _SFR_IO8(_SFR_IO_ADDR(x)-2) // adr. rej. wej. PORTx

    #define LED_PORT_O        LED_PORT             // rejestr wyjściowy
    #define LED_PORT_D        DDR(LED_PORT)   // rejestr kierunkowy
    #define LED_PORT_I        PIN(LED_PORT)   // rejestr wejściowy


    #define cbi(sfr, b) (sfr &= ~(1<<b)) // bit 0 na pin portu
    #define sbi(sfr, b) (sfr |= (1<<b))  // bit 1 na pin portu



    // Definicje funkcji

    // inicjalizacja portu szeregowego
    void UART_Init( unsigned int baud )
    {
       /* Set baud rate */
       UBRRH = 0;
       UBRRL = 51;
       /* Enable receiver and transmitter */
       UCSRB = (1<<RXCIE)|(1<<TXEN)|(1<<RXEN);
          /* Set frame format: 8data, 1stop bit */
       UCSRC = (1<<URSEL)|(3<<UCSZ0);
    }

    // wysyła znak podany jako parametr na port szeregowy
    void UART_putchar (unsigned char c)
    {
         /* Wait for empty transmit buffer */
       while ( !( UCSRA & _BV(UDRE)) )
       ;

       /* Put data into buffer, sends the data */
       UDR = c;
    }

    // odbiera znak z portu szeregowego i zwraca go jako wartość funkcji
    unsigned char UART_getchar (void)
    {
         /* Wait for data to be received */
       while ( !(UCSRA & (1<<RXC)) )
       ;
       /* Get and return received data from buffer */
       return UDR;
    }

    int main(void)                        // program główny
    {
      UART_Init(19200);                        // inicjalizacja portu szeregowego

      sbi(LED_PORT_D,LED_BIT);        // użyj linii jako wyjścia

      while(1)                        // pętla nieskończona
      {
        cbi(LED_PORT_O,LED_BIT);        // zapal diodę LED
        UART_putchar('1');                // wyślij '1' na port szeregowy
        UART_getchar();                // czekaj na znak z portu szeregowego
        sbi(LED_PORT_O,LED_BIT);        // zgaś diodę LED
        UART_putchar('0');                // wyślij '0' na port szeregowy
        UART_getchar();                // czekaj na znak z portu szeregowego
      }
    }
    Dziękuje serdecznie za pomoc!

    0