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

Atmega32 rs232 krzaki, program w C. Transmisja szeregowa.

klinski 15 Mar 2006 14:09 3418 7
REKLAMA
  • #1 2417161
    klinski
    Poziom 10  
    Posty: 41
    Ocena: 13
    Witam

    Zaczelem sie bawic transmisja szeregowa miedzy atmega a komptuerem.
    Mam taki problem, ze jak pisze w asemblerze to wszystko dziala, a jak ten kod przerobie na C to wychodza jakies krzaki, czy ktos moze wie gdzie popelnilem blad

    program asm:


    .INCLUDE "m32def.inc"

    ldi r17, high ((16000000 / (9600 * 16)) - 1)
    ldi r16, low ((16000000 / (9600 * 16)) - 1)

    out ubrrh, r17
    out ubrrl, r16

    ldi r16, (1<<ursel) | (1<<ucsz1) | (1<<ucsz0) | (1<<upm1)
    out ucsrc, r16

    ldi r16, (1<<rxen) | (1<<txen)
    out ucsrb, r16

    czekaj:
    sbis ucsra, udre
    rjmp czekaj

    ldi r18, 'a'
    out udr, r18

    rjmp czekaj


    Program w C:



    #include <avr/io.h>
    #include <avr/pgmspace.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>

    #define FCPU 16000000
    #define VUART 19200
    #define VUBRR (FCPU/(VUART*16))-1

    #define sbi(port,bit) port |= (1<<bit)
    #define cbi(port,bit) port &= ~(1<<bit)


    void USART_Transmit( unsigned char data )
    {
    /* Wait for empty transmit buffer */
    while (bit_is_clear(UCSRA,UDRE));//!( UCSRA & (1<<UDRE)) );
    /* Put data into buffer, sends the data */
    UDR = data;
    }



    int main(void)
    {

    UBRRH= (unsigned char) (VUBRR>>8);
    UBRRL= (unsigned char) VUBRR;


    UCSRC |= (1<<URSEL) | (1<<UCSZ1) |(1<<UCSZ0) | (1<<UPM1);
    UCSRB |= (1<<RXEN) | (1<<TXEN);

    while(1)
    {
    USART_Transmit('6');
    }
    return 0;
    }



    Bede bardzo wdzieczny za wskazowki
    pozdrawiam

    Dodano po 4 [minuty]:

    Przy testowaniu oczywiscie przdkosci transmisji tu i tu ustawilem takiem same czyli 9600
  • REKLAMA
  • #2 2417397
    _eM_
    Poziom 12  
    Posty: 66
    Pomógł: 5
    Czesc
    Nie znam C, ani Asemblera bo programuje od niedawna i tylko w Bascomie jak narazie. Troche ten Twój program skomplikowany wygląda, czy to najprostsze co można zrobić żeby sprawdzić transmisje?
    Jesli wychodzą krzaki to najpierw proponuje zrobić prostą petle w stylu:
    Do
    Print "i = " ; licz
    licz=licz+1
    Waitms 300
    Loop
    End

    Pewnie ktos rozwiaze Twoj problem, bo fachowcow tu nie brakuje, ale moim zdaniem lepiej do sprawdzania prosty program zrobic, a jak juz bedziesz pewny ze dziala dopiero zaczynasz kombinowac :)

    Jesli chodzi o sama transmisje to u mnie byly krzaki jesli zle dobralem predkosci. Ktos mi doradzil zeby po kolei sprawdzac kazda i tak tez robilem. Za ktoryms razem sie udalo i teraz ladnie juz pracuje. Proponuje tez tak poprobowac.

    Daj znac czy sie udalo.
  • REKLAMA
  • #3 2417443
    klinski
    Poziom 10  
    Posty: 41
    Ocena: 13
    Caly czas siedze nad tym i dowiedzialem sie ze jezeli do rejestru UBRR wpisze konktretna wartosc (tu 103) to trasmisja jest ok, na monitorze pokazuje sie to co chce, wnioskuje ze cos jest zle liczone w wyrazeniu

    #define VUBRR (FCPU/(VUART*16))-1

    czy moze ktos mi wytlumaczyc dlaczego tak sie dzieje?

    Pozdrawiam
  • #4 2417552
    _Matik_
    Poziom 19  
    Posty: 390
    Pomógł: 25
    Ocena: 7
    Mialem podobny problem podczas programowania w assemblerze w AVRSTUDIO. Zdefiniowalem sobie stala wedlug wzoru ktora kompilator automatycznie przelicza na wartosc (tak jak #DEFINE u Ciebie)

    Okazało sie w wyniku obliczen kompilatora wychodzila liczba troszke mniejsza od calkowitej (np. 7.98) i on to zaokraglal do 7 co dawalo oczywiscie kilkunastoprocentowy blad ktory objawial sie pojawiajacymi sie losowo bledami i rozsypywaniem sie transmisji bez zadnej wyraznej reguly ktora moznaby latwo rozpoznac.

    Po spedzeniu kilku bezsennych godzin wpisalem mu na sztywno wartosc i zaczelo dzialac... troszke sie wtedy wkurzylem ;D.
  • REKLAMA
  • #5 2417604
    klinski
    Poziom 10  
    Posty: 41
    Ocena: 13
    Okazalo sie ze on cos zle mnozy, wyrazenie

    VUART*16

    jest zle wyliczane ponieaz jak ten wynik wpisze na sztywni to dziala bardzo dobrze

    Dodano po 20 [minuty]:

    Czy ktos mi wytlumaczy dlaczego w asemblerze liczy dobrze a w C sie sypie?:)

    Pozdrawiam
  • #6 2419015
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    Dodaj w każdej definicji "stand alone number" UL np.
    #define F_CPU 4000000UL // 4MHz zegar procesora
    #define UART_BAUD 19200UL
    #define _UBBR_ ((F_CPU/(16*UART_BAUD))-1)
    Następny poziom trudności to porównywanie wartości po dodaniu 1/2 i wybieraniu wiekszej całkowitej... (typowe zaokrąglanie)
    Prosty kod generujący echo (to co przyszło, odsyła z powrotem) :
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    #include <inttypes.h>
    #define PARITY_NONE 0
    #define PARITY_EVEN (1<<UPM1)
    #define PARITY_ODD ((1<<UPM1)|(1<<UPM0))
    #define STOP_BITS_1 0
    #define STOP_BITS_2 (1<<USBS)
    #define DATA_BITS_5 0
    #define DATA_BITS_6 (1<<UCSZ0)
    #define DATA_BITS_7 (1<<UCSZ1)
    #define DATA_BITS_8 ((1<<UCSZ1)|(1<<UCSZ0))
    #define DATA_BITS_9 ((1<<UCSZ2)|(1<<UCSZ1)|(1<<UCSZ0))
    
    #define F_CPU 4000000UL // 4MHz zegar procesora
    #define UART_BAUD 19200UL
    #define _UBBR_ ((F_CPU/(16*UART_BAUD))-1)
    unsigned char byte;
    
    
    int USART_Transmit( unsigned char data )
    {
    while ( !( UCSRA & (1<<UDRE)) );/* Wait for empty transmit buffer */
    UDR = data;/* Put data into buffer, sends the data */
    return 0;
    }
    
    
    void USART_Init( unsigned int baud_reg )
    	{
    	UBRRH = (unsigned char)(baud_reg>>8);
    	UBRRL = (unsigned char)baud_reg;
    	UCSRB = (1 << RXCIE) | (1 << RXEN) | (1 << TXEN);
    	UCSRC = (1 << URSEL) | DATA_BITS_8 | PARITY_NONE | STOP_BITS_1;
    	sei();
    	}
    
    int main (void)
    	{
    	USART_Init(_UBBR_);
    	DDRB |= (1 << PB1);
    
    	while(1)
    		{
    		}
    	return 0;
    	}
    
    
    SIGNAL (SIG_UART_RECV)
    	{
    	PORTB ^= (1 << PB1);
    	byte = UDR;
    	USART_Transmit(byte);
    	}
    kompilowane pod crossavr-gcc (PLD Linux 2.0) generuje prawidłową wartość - 12 dla UBRRH:UBRRL w pliku .lss
    [...]
            USART_Init(_UBBR_);
      86:   8c e0           ldi     r24, 0x0C       ; 12
      88:   90 e0           ldi     r25, 0x00       ; 0
  • REKLAMA
  • #7 2419713
    klinski
    Poziom 10  
    Posty: 41
    Ocena: 13
    Wielkie dzieki, teraz dziala

    Pozdrawiam
  • #8 2423696
    wisnia_82
    Poziom 12  
    Posty: 19
    Pomógł: 1
    Ocena: 11
    Warto jeszcze przestawić zegar procka z domyślnego 1MHz na twój. FUSE bits. Może to być również przyczyna złego działania UARTa
    Moderowany przez Light-I:

    Nie nabijaj postów - autor wyraźnie napisał, że problem jest softwarowy, a nie ustawień sprzetowych i został rozwiązany.

Podsumowanie tematu

✨ Dyskusja dotyczy problemów z transmisją szeregową UART między mikrokontrolerem Atmega32 a komputerem, gdzie kod w asemblerze działa poprawnie, natomiast jego odpowiednik w języku C generuje nieczytelne znaki ("krzaki"). Główną przyczyną problemu okazało się błędne obliczanie wartości rejestru UBRR, odpowiedzialnego za ustawienie prędkości transmisji. Wzór użyty w definicji makra (#define VUBRR (FCPU/(VUART*16))-1) w C powodował błędy zaokrągleń i niepoprawne mnożenie, co skutkowało nieprawidłową konfiguracją UART. Rozwiązaniem było użycie stałych typu unsigned long (np. 16000000UL) w definicjach oraz ręczne wpisanie poprawnej wartości UBRR (np. 103) zamiast polegania na wyrażeniu. Dodatkowo zasugerowano sprawdzenie ustawień fuse bits mikrokontrolera, aby zegar procesora był zgodny z założonym taktowaniem, co ma wpływ na poprawność transmisji UART. Wskazano także na konieczność stosowania odpowiedniego zaokrąglania podczas obliczeń prędkości transmisji w C.
Wygenerowane przez model językowy.
REKLAMA