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

[C] atmega8 + UART = sypanie krzaków

Cosicek 20 Lis 2009 20:47 4393 17
REKLAMA
  • #1 7287279
    Cosicek
    Poziom 16  
    Witam, mam problem, z odbieraniem informacji od atmegi na komputer, próbowałem różnej kombinacji prędkości i częstotliwości, ale cały czas jest to samo, pokazuje się cały czas ten sam znak. Informacje z AVRa odbieram przez program gtkterm, poniżej zamieszczam kod, na którym testuje UARTa, pochodzi on z avrfreaks

    #include <avr/io.h> 
    #include <avr/io.h> 
    
    #define USART_BAUDRATE 9600 
    #define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) 
    
    int main (void) 
    { 
       char ReceivedByte; 
    
       UCSRB |= (1 << RXEN) | (1 << TXEN);   // Turn on the transmission and reception circuitry 
       UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes 
    
       UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register 
       UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register 
    
       while(1) // Loop forever 
       { 
          while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been recieved and is ready to be read from UDR 
          ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ByteReceived" 
    
          while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it 
          UDR = ReceivedByte; // Echo back the received byte back to the computer 
       }    
    }


    nie wiem czy to jeszcze ma znaczenie, ale układ jest podpięty pod taki konwerter RS232->USB
    [C] atmega8 + UART = sypanie krzaków

    PS. przepraszam, jeżeli pozostawienie loga narusza regulamin, ale nie wiem czy mogę je wyciąć
  • REKLAMA
  • #2 7287384
    Skyttop
    Poziom 11  
    A gdzie instrukcja sei(); odblokowująca obsługę przerwań?
  • #4 7287457
    Skyttop
    Poziom 11  
    W tutorialu jest obsługa USART bez wykorzystania przerwań, a ty próbujesz odebrać znak w przerwaniu. Wstaw instrukcję sei(); przed pętlą while i sprawdź co się dzieje. Jeśli nie pomoże, w poniedziałek podeślę działający kod na przerwaniach.
  • REKLAMA
  • #5 7287492
    Cosicek
    Poziom 16  
    #include <avr/io.h> 
    #include <avr/interrupt.h> 
    
    #define USART_BAUDRATE 9600 
    #define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) 
    
    int main (void) 
    { 
       UCSRB |= (1 << RXEN) | (1 << TXEN);   // Turn on the transmission and reception circuitry 
       UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes 
    
       UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register 
       UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register 
    
       UCSRB |= (1 << RCXIE); // Enable the USART Recieve Complete interrupt (USART_RXC) 
       sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed 
    
       for (;;) // Loop forever 
       { 
             // Do nothing - echoing is handled by the ISR instead of in the main loop 
       }    
    } 
    
    ISR(USART_RXC_vect) 
    { 
       char ReceivedByte; 
       ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ByteReceived" 
       UDR = ReceivedByte; // Echo back the received byte back to the computer 
    }


    Próbowałem też również tą wersje z przerwaniami jak pisałeś, ale ona skutkuje dalej tym samym.
  • #6 7287617
    Skyttop
    Poziom 11  
    Jeśli dobrze zrozumiałem, to chcesz wysyłać informację z uC do komputera? Ale ten kod powyżej wygląda mi na działający w drugą stronę, czyli z komputera do uC. Nie mam w tej chwili niestety jak to sprawdzić, bo wszystkie projekty zostawiłem na dysku w pracy, ale ja to już kiedyś robiłem i działa w obie strony, więc podeślę, jak tylko będę mógł. Na razie popróbuj, ale wydaje mi się, że przykład ze strony 140 i 141 noty katalogowej ATmga8 powinien pomóc. Informację wysyłaj najlepiej bez przerwań, a przerwania wykorzystuj gdy to uC odbiera. Uzasadnienie jest takie, że o ile mamy kontrolę nad wysyłaniem danych to nie zawsze mamy kontrolę nad odbieraniem. To dotyczy zarówno uC jak i komputera. Dlatego najlepiej wykorzystać wektor głównie z przerwań danych nadchodzących.
    Kod z noty katalogowej:

    
    void USART_Transmit( unsigned int data )
    {
    /* Wait for empty transmit buffer */
    while ( !( UCSRA & (1<<UDRE)) )
    ;
    /* Copy ninth bit to TXB8 */
    UCSRB &= ~(1<<TXB8);
    if ( data & 0x0100 )
    UCSRB |= (1<<TXB8);
    /* Put data into buffer, sends the data */
    UDR = data;
    }
    


    Dodano po 3 [minuty]:

    Albo ten przykład:
    
    
    void USART_Transmit( unsigned char data )
    {
    /* Wait for empty transmit buffer */
    while ( !( UCSRA & (1<<UDRE)) )
    ;
    /* Put data into buffer, sends the data */
    UDR
    
    


    Porównaj to z tutorialem opisanym na AVRFreaks

    Dodano po 9 [minuty]:

    sorry, poprawka przykładu 2:

    
    void USART_Transmit( unsigned char data )
    {
    /* Wait for empty transmit buffer */
    while ( !( UCSRA & (1<<UDRE)) )
    ;
    /* Put data into buffer, sends the data */
    UDR = data;
    }
    
  • #8 7287806
    Skyttop
    Poziom 11  
    To jest definicja funkcji którą należy użyć, np jeśli ma to być tekst, używasz pętli w której funkcja ta wysyła znak po znaku. Przykład podeślę po weekendzie, bo robiłem to dawno. Podeślę już coś sprawdzonego. Na razie spróbuj np. tak:
    1. wstaw
     #include <util/delay.h> 

    2. wstaw definicję funkcji przykładu 2 przed funkcją main();
    3. w środku pętli wstaw

    
    USART_Transmit('a');
    _delay_ms(250);
    


    Odpal jakiś terminal z ustawieniami 9600, 7 bitów danych, bez parzystości i powinieneś otrzymać literę a co 250 ms.
  • #9 7289269
    Cosicek
    Poziom 16  
    ustawiłem, i przy 7 bitach, i 1 bicie stopu nie odbiera nic lub śmieci, losowe znaki, natomiast przy ośmiu bitach dalej śmieci, przy ustawionym widoku na hex, widać, że wysyła cały czas znak 0x80


    No i co ciekawsze, to wysyła cały czas po dwa znaki

    Dodano po 34 [minuty]:

    Hmmm, tak przeglądałem forum, i zauważyłem, że do tych konwerterów ludzie podpinają kwarc, może to być przyczyną błędu??
  • REKLAMA
  • #10 7289706
    Skyttop
    Poziom 11  
    Może być, ale niekoniecznie. Ja używałem wewnętrzny oscylator i było ok.
  • #12 7290321
    Sh44dow
    Poziom 16  
    Nie masz lub nie będziesz miał w najbliższym czasie przypadkiem dostępu do PC z COMem? U mnie też sypie krzaczkami na 2 przejściówkach - jedna - PL2303, druga to chyba właśnie FT232, a po podłączeniu do komputera z portem COM wszystko działa jak należy.
  • #13 7293062
    Cosicek
    Poziom 16  
    szczerze to nie mam w ogóle COMa w żadnym kompie :( ale może uda mi się z kumplem pogadać i pożyczy, a co do kwarcu to nie pomógł też :(

    Dodano po 3 [godziny] 20 [minuty]:

    no to tak, kumpel nie ma COMa jednak, a sprawdzałem też przejściówkę zwierając TxD i RXD i działa normalnie, ale po podłączeniu do atmegi dalej lecą głupoty
  • #14 7296686
    Sh44dow
    Poziom 16  
    Sprawdzałem na PL2303 i też znaki wracają poprawnie a pomimo tego również lecą krzaczki. Tą z FT232 już niestety oddałem.
  • Pomocny post
    #15 7298000
    Skyttop
    Poziom 11  
    Obiecałem działający programik. Działa na 100%. Jest to progrtam, który wysyła stan temperatury z DS18B20 do kompa, ale dla Ciebie najistotniejszy jest sposób komunikacji. Jest wysyłane zapytanie i uC zwraca odpowiedź. Jak uporasz się z krzaczkami, to program Ci się przyda. Można zrobić bardzo prosty protokół wymiany informacji.

    
    #include <avr/io.h>
    #include <avr/delay.h>
    #include <avr/interrupt.h>
    #include <string.h>
    #include <avr/pgmspace.h>
    
    #define F_CPU 8000000UL
    #define UART_BAUD 19200
    #define UART_CONST (F_CPU/(16ul*UART_BAUD)-1)
    #define LOOP_CYCLES 8 //Number of cycles that the loop takes
    #define us(num) (num/(LOOP_CYCLES*(1/(F_CPU/1000000.0))))
    
    
    /* Thermometer Connections (At your choice) */
    #define THERM_PORT PORTD
    #define THERM_DDR DDRD
    #define THERM_PIN PIND
    #define THERM_DQ 5
    /* Utils */
    #define THERM_INPUT_MODE() THERM_DDR&=~(1<<THERM_DQ)
    #define THERM_OUTPUT_MODE() THERM_DDR|=(1<<THERM_DQ)
    #define THERM_LOW() THERM_PORT&=~(1<<THERM_DQ)
    #define THERM_HIGH() THERM_PORT|=(1<<THERM_DQ)
    
    #define THERM_CMD_CONVERTTEMP 0x44
    #define THERM_CMD_RSCRATCHPAD 0xbe
    #define THERM_CMD_WSCRATCHPAD 0x4e
    #define THERM_CMD_CPYSCRATCHPAD 0x48
    #define THERM_CMD_RECEEPROM 0xb8
    #define THERM_CMD_RPWRSUPPLY 0xb4
    #define THERM_CMD_SEARCHROM 0xf0
    #define THERM_CMD_READROM 0x33
    #define THERM_CMD_MATCHROM 0x55
    #define THERM_CMD_SKIPROM 0xcc
    #define THERM_CMD_ALARMSEARCH 0xec
    #define THERM_DECIMAL_STEPS_12BIT 625 //.0625
    
    prog_char zapytanie1[5]={'*','I','D','N','?'};
    prog_char zapytanie2[5]={'C','D','A','T','?'};
    prog_char ID[]={'T','e','r','m','o','m','e','t','r',' ','A','.','K'};
    volatile unsigned char *odebrane_znaki;
    volatile unsigned char start1=0,start2=0,licznik;
    volatile char znak;
    uint16_t digit;
    uint16_t decimal;
    
    char buffer[11];
    inline __attribute__((gnu_inline)) void therm_delay(uint16_t delay)
    {
    	while(delay--) asm volatile("nop");
    }
    
    SIGNAL(SIG_USART_RECV) 
    {
    	znak = UDR;
    																	//Zapytanie 1
    	if(znak=='*')
    	{
    		start1=1;
    		licznik=0;
    	}
    	if(start1)
    	{
    		odebrane_znaki[licznik]=znak;
    		if(znak!=pgm_read_byte(&zapytanie1[licznik]))
    		{
    			licznik=0;
    		}
    		else
    			licznik++;
    		if(licznik==5)
    		{
    			for(uint8_t i=0;i<strlen_P(ID);i++)
    				USART_Transmit(pgm_read_byte(&ID[i]));				//odpowiedz ID
    			start1=0;
    			licznik=0;
    		}
    	}
    																	//Zapytanie 2
    	if(znak=='C')
    	{
    		start2=1;
    		licznik=0;
    	}
    	if(start2)
    	{
    		odebrane_znaki[licznik]=znak;
    		if(znak!=pgm_read_byte(&zapytanie2[licznik]))
    			licznik=0;
    		else
    			licznik++;
    		if(licznik==5)
    		{
    				USART_Transmit(digit);				//odpowiedz pomiar
    				USART_Transmit(decimal);
    			start2=0;
    			licznik=0;
    		}
    	}
    } 
    
    
    
    uint8_t therm_reset()
    {
    	uint8_t i;
    	//Pull line low and wait for 480uS
    	THERM_LOW();
    	THERM_OUTPUT_MODE();
    	therm_delay(us(480));
    	//Release line and wait for 60uS
    	THERM_INPUT_MODE();
    	therm_delay(us(60));
    	//Store line value and wait until the completion of 480uS period
    	i=(THERM_PIN & (1<<THERM_DQ));
    	therm_delay(us(420));
    	//Return the value read from the presence pulse (0=OK, 1=WRONG)
    	return i;
    }
    
    void therm_write_bit(uint8_t bit)
    {
    	cli();
    	//Pull line low for 1uS
    	THERM_LOW();
    	THERM_OUTPUT_MODE();
    	therm_delay(us(1));
    	//If we want to write 1, release the line (if not will keep low)
    	if(bit) THERM_INPUT_MODE();
    	//Wait for 60uS and release the line
    	therm_delay(us(60));
    	THERM_INPUT_MODE();
    	sei();
    }
    
    uint8_t therm_read_bit(void)
    {
        cli();
    	uint8_t bit=0;
    	//Pull line low for 1uS
    	THERM_LOW();
    	THERM_OUTPUT_MODE();
    	therm_delay(us(1));
    	//Release line and wait for 14uS
    	THERM_INPUT_MODE();
    	therm_delay(us(14));
    	//Read line value
    	if(THERM_PIN&(1<<THERM_DQ)) bit=1;
    	//Wait for 45uS to end and return read value
    	therm_delay(us(45));
    	sei();
    	return bit;
    }
    
    uint8_t therm_read_byte(void)
    {
    	uint8_t i=8, n=0;
    	while(i--)
    	{
    		//Shift one position right and store read value
    		n>>=1;
    		n|=(therm_read_bit()<<7);
    		}
    		return n;
    	}
    void therm_write_byte(uint8_t byte)
    {
    	uint8_t i=8;
    	while(i--)
    	{
    		//Write actual bit and shift one position right to make
    	//	the next bit ready
    		therm_write_bit(byte&1);
    		byte>>=1;
    	}
    }
    
    void therm_read_temperature()
    {
    	// Buffer length must be at least 12bytes long! ["+XXX.XXXX C"]
    	uint8_t temperature[2];
    	char licznik=0;
    	//Reset, skip ROM and start temperature conversion
    	therm_reset();
    	therm_write_byte(THERM_CMD_SKIPROM);
    	therm_write_byte(THERM_CMD_CONVERTTEMP);
    	//Wait until conversion is complete
    	while(!therm_read_bit());
    	//Reset, skip ROM and send command to read Scratchpad
    	therm_reset();
    	therm_write_byte(THERM_CMD_SKIPROM);
    	therm_write_byte(THERM_CMD_RSCRATCHPAD);
    	//Read Scratchpad (only 2 first bytes)
    	temperature[0]=therm_read_byte();
    	temperature[1]=therm_read_byte();
    	therm_reset();
    	//Store temperature integer digits and decimal digits
    	digit=temperature[0]>>4;
    	digit|=(temperature[1]&0x7)<<4;
    	//Store decimal digits
    	decimal=temperature[0]&0xf;
    //	decimal*=THERM_DECIMAL_STEPS_12BIT;
    	//Format temperature into a string [+XXX.XXXX C]
    //	sprintf(buffer, "%+04u.%04u C", digit, decimal);
    
    }
    
    //port szeregowy
    void USART_Transmit( unsigned char data )
    {
    											/* Wait for empty transmit buffer */
    	while ( !( UCSRA & (1<<UDRE)));
    											/* Copy 9th bit to TXB8 */
    		UCSRB &= ~(1<<TXB8);
    		if ( data & 0x0100 )
    			UCSRB |= (1<<TXB8);
    											/* Put data into buffer, sends the data */
    	UDR= data;
    }
    
    int main(void)
    {
    
    	UBRRH = (unsigned char)(UART_CONST>>8);
    	UBRRL = (unsigned char)UART_CONST;
    													/* Enable receiver and transmitter */
    	UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
    													/* Set frame format: 8data, 2stop bit */
    	UCSRC = 1<<URSEL | 1<<UCSZ1 | 1<<UCSZ0;			//ramka 8bit, 1 bit stopu 
    	sei();
    		while(1)
    		{
    		therm_read_temperature();
    		}
    		return 0;
    }
    


    Dodano po 6 [minuty]:

    Dodam jeszcze, że program był pisany docelowo na ATmega16 i nie pamiętam, czy są jakieś różnice w obsłudze UART'a pomiędzy nim a ATmega8.
    Zapytanie1 i Zapytanie2 - tu zapisany jest ciąg znaków, które powinien otrzymać uC z aplikacji komputerowej (np. z terminala). Ja dodatkowo sprawdzam, czy to co przyszło zgadza sie z tym, co ma przyjść. Najlepiej zrobić to w przerwaniu. Jeśli uC odebrał znak, od razu porównuje go ze znakiem z tablicy. Jeśli 5 znaków z rzędu było zgodnych, wówczas jesteśmy pewni, że wysłano właściwe zapytanie. Jeśli któryś ze znaków był nieprawiudłowy, licznik się zeruje.
  • #17 7374852
    sweter_007
    Poziom 14  
    Witam. Nie chciałem tworzyć nowego tematu więc podepnę się tutaj.
    Mam problem z komunikacją atmega 8 - PC. W stronę uC sypało jakieś krzaki, w stronę Pc wogóle nie reagowało. Wtyczkę do komputera( połączenia 6-4, 7-8, 5) mam jak na schemacie: http://www.serasidis.gr/circuits/RS232interface/images/Schematic.jpg

    Używam Ubuntu, i dla testów odłączyłem mikrokontroler oraz zwarłem piny(wtyczki) RX/TX.
    Konfiguracja portu:
    > stty -F /dev/ttyS1 speed 9600 cstopb -crtscts
    > stty -F /dev/ttyS1 -a
    speed 9600 baud; rows 0; columns 0; line = 0;
    intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
    eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
    werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
    -parenb -parodd cs8 hupcl cstopb cread clocal -crtscts
    -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
    -iuclc -ixany -imaxbel -iutf8
    opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
    isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
    echoctl echoke

    Dane wysyłam przykładowo takie:
    > echo w > /dev/ttyS1
    A otrzymuję:
    > cat /dev/ttyS1 | more
    > w
    >
    > w
    >
    >
    >
    > w
    >
    >
    >
    >
    >
    >
    >
    > w
    i tak dalej...

    Jest tak samo z użyciem max232 ( tzn zwieram TX/RX tego układu)

    Co może być nie tak? Proszę o pomoc.
  • REKLAMA
  • #18 7375342
    gigipawel
    Poziom 15  
    Witma.
    Podłącze się do kolega mnie zainspirował. Bałem się czy poprawnie wykonałem układ z Maxem. Jeżeli dobrze zrozumiałem zwierając końcówki T1in i R1out od strony mikrokontrolera i wysyłając jakieś znaki można zabserować jak się układ zachowuje ?
    Oto wynik z programu Realterm.
    [C] atmega8 + UART = sypanie krzaków

    Czyli mój układ jest Ok ?
REKLAMA