UBRR w Mikrokontrolerach - Konfiguracja, Obliczenia, Rozwiązywanie Błędów

Stefan Wysocki .

20 maja 2026

Oscyloskop Rigol DS1054 z wyświetlonym przebiegiem sygnału i danymi pomiarowymi.
Rejestr UBRR decyduje o tym, czy transmisja UART w AVR będzie stabilna, czy terminal zacznie pokazywać losowe znaki. W praktyce to jeden z tych parametrów, które łatwo ustawić źle, a potem bez potrzeby szukać problemu w kablach, konwerterze albo samym kodzie. Poniżej rozkładam temat na konkretne kroki: jak policzyć wartość dla swojego zegara, kiedy włączyć tryb podwójnej prędkości, jak wpisać ustawienia w kodzie i jak diagnozować typowe błędy.

Najważniejsze rzeczy, które trzeba ustawić poprawnie

  • UBRR jest preskalerem generatora baud rate, a nie „prędkością portu” samą w sobie.
  • Wartość zależy od F_CPU i wybranego baud rate, a wzór zmienia się dla trybu normalnego i U2X=1.
  • W wielu przypadkach lepszy wynik daje zaokrąglanie do najbliższej liczby całkowitej, a nie zwykłe obcięcie po dzieleniu.
  • Rejestr jest dzielony na część wysoką i niską, więc zapis trzeba wykonać w poprawnej kolejności.
  • Jeśli terminal pokazuje „krzaki”, najpierw sprawdzam zegar, fusy, preskaler i ustawienia programu terminalowego.

Jak działa rejestr i co naprawdę ustawia

W AVR rejestr UBRR steruje generatorem baud rate, czyli układem, który wylicza tempo transmisji dla USART. To ważne rozróżnienie: ten zapis nie „ustawia portu szeregowego” w całości, tylko określa, jak szybko ma pracować jego zegar komunikacyjny. W nowszych układach spotkasz nazwy typu UBRR0H i UBRR0L, a na starszych po prostu UBRRH i UBRRL, ale zasada pozostaje ta sama.

W dokumentacji Microchip widać jeszcze jedną istotną rzecz: w wielu AVR jest to rejestr 12-bitowy, więc jego wartość rozdziela się na część wysoką i niską. Dodatkowo zapis dolnego bajtu zwykle powoduje natychmiastową aktualizację preskalera, dlatego przy zmianie konfiguracji w locie trzeba zachować porządek i nie robić tego podczas aktywnej transmisji. Gdy to rozumiemy, policzenie właściwej wartości dla konkretnego zegara staje się dużo prostsze.

Jak obliczyć wartość dla swojego zegara

Podstawowy wzór jest prosty, ale łatwo tu popełnić błąd, jeśli pomylisz tryb pracy albo użyjesz nieaktualnej wartości F_CPU. Dla trybu asynchronicznego normalnego liczę tak: UBRR = F_CPU / (16 * BAUD) - 1. Dla trybu U2X=1 wzór zmienia się na UBRR = F_CPU / (8 * BAUD) - 1.

Ja zawsze robię jeszcze jeden krok: sprawdzam, jaki będzie rzeczywisty baud po zaokrągleniu wyniku do liczby całkowitej. To często ważniejsze niż sam wynik z wzoru, bo przy niektórych kombinacjach zegara i prędkości dopiero to pokazuje, czy komunikacja będzie stabilna.

F_CPU Baud Tryb UBRR Rzeczywista prędkość Błąd
16 MHz 9600 normal 103 9 615,38 +0,16%
16 MHz 57 600 U2X=1 34 57 142,86 -0,79%
8 MHz 115 200 U2X=1 8 111 111,11 -3,55%

W tabelach Microchip widać to bardzo wyraźnie: popularne kombinacje częstotliwości i baud rate są dobrane tak, żeby błąd był możliwie mały, a najlepiej poniżej 0,5%. To dobry punkt odniesienia również w praktyce, bo im większy błąd, tym szybciej pojawiają się problemy przy dłuższych ramach i mniej odpornym torze komunikacji. Sama arytmetyka jednak nie wystarczy, bo wybór trybu U2X potrafi zmienić wynik na lepszy albo gorszy.

Kiedy U2X=1 pomaga, a kiedy nie warto go wymuszać

Tryb podwójnej prędkości nie jest magicznym przyciskiem „napraw UART”. Ja traktuję go jako narzędzie do poprawy dokładności wtedy, gdy normalny tryb daje zbyt duży błąd. Najczęściej przydaje się przy wyższych prędkościach, niższym zegarze albo wtedy, gdy zwykły podział przez 16 kończy się słabym dopasowaniem do żądanego baud rate.

  • Włączam U2X=1, gdy zmniejsza błąd i daje wynik bliższy docelowemu baud.
  • Zostaję przy trybie normalnym, gdy oba warianty są podobne albo gdy prostsza konfiguracja jest wystarczająca.
  • Nie wybieram trybu „na oko”, tylko porównuję rzeczywisty błąd po obu stronach.
  • Sprawdzam też zegar układu, bo przy wewnętrznym RC i źle ustawionych fusach sam U2X nie uratuje transmisji.

Jeżeli projekt dopiero powstaje, często lepiej dobrać taki kwarc lub rezonator, który naturalnie „lubi się” z popularnymi prędkościami transmisji, niż później walczyć z marginalnym błędem. To szczególnie ważne w urządzeniach, które mają działać bez ręcznego strojenia po stronie użytkownika. Po wyborze trybu trzeba to jeszcze wpisać do rejestrów tak, żeby sprzęt nie dostał przypadkowej wartości po drodze.

Jak ustawić rejestry w kodzie AVR

Najprostszy zapis ręczny wygląda tak: najpierw liczysz wartość, potem wpisujesz starszy bajt, a na końcu młodszy. To ważne, bo zapis do dolnego bajtu uruchamia aktualizację preskalera. W praktyce robię to tak:

uint16_t ubrr = 103;
UBRR0H = (uint8_t)(ubrr >> 8);
UBRR0L = (uint8_t)ubrr;

Jeśli nie chcę liczyć tego ręcznie, korzystam z AVR-LibC i pliku setbaud.h. To wygodny wariant, bo makra same wyliczają wartość, zaokrąglają wynik i sprawdzają tolerancję baud rate. Domyślnie biblioteka pracuje z tolerancją 2%, więc od razu odcina kombinacje, które są zbyt odległe od celu.

#define F_CPU 16000000UL
#define BAUD 9600
#include 

void usart_init(void) {
    UBRR0H = UBRRH_VALUE;
    UBRR0L = UBRRL_VALUE;
#if USE_2X
    UCSR0A |= _BV(U2X0);
#else
    UCSR0A &= ~_BV(U2X0);
#endif
    UCSR0B = _BV(TXEN0) | _BV(RXEN0);
    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
}

Właśnie taki układ kodu lubię najbardziej: najpierw deklaruję realny zegar, potem baud rate, a dopiero na końcu pozwalam bibliotece wyliczyć resztę. Jeśli mimo tego terminal dalej sypie znakami, przyczyna zwykle leży w konfiguracji całego toru, nie tylko w samym rejestrze.

Dlaczego terminal pokazuje krzaki

„Krzaki” prawie zawsze oznaczają brak zgodności między tym, co zakłada mikrokontroler, a tym, co widzi druga strona. Najczęstszy scenariusz jest banalny: wartość w programie zakłada 16 MHz, a układ realnie pracuje z inną częstotliwością albo z włączonym podziałem zegara. Drugi klasyk to rozjazd ustawień terminala, na przykład inny baud, inna liczba bitów stopu albo zła parzystość.

  • Sprawdzam F_CPU w projekcie i porównuję je z realnym zegarem układu.
  • Weryfikuję fusy i preskaler, bo CKDIV8 lub zły wybór źródła zegara potrafią zmienić wszystko.
  • Porównuję ustawienia terminala z konfiguracją USART, zwłaszcza baud, 8N1 i parzystość.
  • Oceniając błąd, nie ufam samemu wynikowi z wzoru, tylko sprawdzam rzeczywisty baud po zaokrągleniu.
  • Zmniejszam prędkość testową, jeśli tor jest długi, adapter jest słaby albo zegar ma większą tolerancję.

Jeżeli problem znika po obniżeniu baud rate, to nie jest przypadek. Taka próba szybko mówi mi, czy problem wynika z błędu obliczeń, granicznych parametrów zegara, czy może z samego połączenia sprzętowego. W praktyce najlepiej mieć prostą, powtarzalną procedurę startu, zamiast liczyć na szczęście.

Najkrótsza droga do stabilnego UART-u w AVR

Gdy uruchamiam nowy projekt, zaczynam od trzech rzeczy: realnego zegara, sensownego baud rate i poprawnego zaokrąglenia wartości. Dopiero potem patrzę na sam kod transmisji. To oszczędza czas, bo w wielu przypadkach problem nie leży w funkcjach wysyłających znaki, tylko w tym, że jeden element toru pracuje na innych założeniach niż reszta.

Jeśli mam wpływ na hardware, wybieram częstotliwość zegara, która dobrze dzieli się przez popularne prędkości, a jeśli nie mam takiej swobody, korzystam z obliczeń i testuję wynik na realnym terminalu. Przy pierwszych uruchomieniach nie podkręcam od razu prędkości do maksimum, tylko zaczynam od ustawienia, które daje wyraźny margines błędu. Potem, gdy komunikacja jest stabilna, dopiero zwiększam tempo. W praktyce właśnie to podejście daje najmniej niespodzianek i najlepiej porządkuje pracę z UBRR.

Źródło:

[1]

https://forbot.pl/forum/topic/20433-wartosc-ubrr/

FAQ - Najczęstsze pytania

UBRR (USART Baud Rate Register) to rejestr w mikrokontrolerach AVR, który kontroluje generator prędkości transmisji (baud rate) dla interfejsu szeregowego USART. Określa tempo, w jakim dane są wysyłane i odbierane, wpływając na stabilność komunikacji.
Wartość UBRR zależy od częstotliwości zegara mikrokontrolera (F_CPU) i wybranej prędkości transmisji (BAUD). Dla trybu normalnego (U2X=0) wzór to: UBRR = F_CPU / (16 * BAUD) - 1. Dla trybu podwójnej prędkości (U2X=1): UBRR = F_CPU / (8 * BAUD) - 1.
Tryb U2X=1 (podwójna prędkość) jest przydatny, gdy tryb normalny generuje zbyt duży błąd prędkości transmisji. Pomaga poprawić dokładność przy wyższych prędkościach lub niższych częstotliwościach zegara, ale zawsze należy sprawdzić rzeczywisty błąd po zaokrągleniu.
"Krzaki" w terminalu najczęściej oznaczają niezgodność ustawień. Sprawdź F_CPU w kodzie i porównaj z rzeczywistym zegarem układu, zweryfikuj fusy i preskaler, porównaj ustawienia terminala (baud rate, bity danych, stopu, parzystość) z konfiguracją USART w mikrokontrolerze.
Najpierw oblicz wartość UBRR. Następnie zapisz starszy bajt do UBRRH (np. UBRR0H = (uint8_t)(ubrr >> 8);), a potem młodszy bajt do UBRRL (np. UBRR0L = (uint8_t)ubrr;). Zapis do UBRRL aktualizuje preskaler.

Oceń artykuł

Średnia: 0.0 / 5 · 0 ocen

Tagi

ubrr obliczanie wartości ubrr konfiguracja uart avr ubrr błędy transmisji szeregowej ubrr wzór na ubrr f_cpu baud rate
Autor Stefan Wysocki
Stefan Wysocki
Jestem Stefan Wysocki, doświadczonym analitykiem branżowym z wieloletnim zaangażowaniem w tematykę technologii. Od ponad pięciu lat piszę o najnowszych trendach, innowacjach oraz wpływie technologii na codzienne życie. Moje zainteresowania obejmują zarówno rozwój oprogramowania, jak i nowinki w dziedzinie sprzętu komputerowego, co pozwala mi na dostarczanie rzetelnych i wszechstronnych informacji. Specjalizuję się w analizie danych oraz w ocenie wpływu technologii na różne sektory gospodarki. Moim celem jest uproszczenie skomplikowanych zagadnień technologicznych, aby były one zrozumiałe dla każdego, niezależnie od poziomu wiedzy. Wierzę, że obiektywna analiza i dokładne sprawdzanie faktów są kluczowe dla budowania zaufania wśród czytelników. Dążę do tego, aby moja praca dostarczała aktualnych i wiarygodnych informacji, które pomogą moim czytelnikom lepiej zrozumieć świat technologii i podejmować świadome decyzje.

Komentarze (0)

Dodaj komentarz