Skocz do zawartości

ATMega 8 USART Prędkość wysyłania, czemu tak wolno?


davidpi

Pomocna odpowiedź

Witam.

Próbuję opanować USART w ATMega 8. Wewnętrzny oscylator 1MHz. Z komunikacją nie mam większych problemów. Jednak zastanawia mnie ustawianie prędkości transmisji. W moim programie ustawiłem prędkość transmisji na 9600bps. Rozumiem że 9600 bps oznacza wysłanie 9600 bitów w ciągu sekundy (jeżeli źle rozumuję to proszę o poprawienie mnie), a więc niespełna 1000 liczb 8 bitowych.

Jednak z obserwacji w urządzeniu wynika, że pracuje ono dużo wolniej.Dlatego mam kilka pytań do bardziej doświadczonych kolegów.

Oto kod programu:

#include<avr\io.h>
#include<UART.c>
#include<HD44780.c>
#include<stdlib.h>

int dana=0;
char dana1=120;

void LCD()
{
char buf[5];
LCD_Clear();
itoa(dana,buf,10);
LCD_WriteText(buf);
}

int main()
{
LCD_Initalize();
UART_NadajnikInit();
while(1)
{
	UART_Wyslij(dana1);
	dana++;
	LCD();
}
return 0;
}

oraz kod obsługi USART

#include "UART.h"

void UART_NadajnikInit()
{
UBRRL = 6;
UBRRH = 0;
UCSRC |= (1<<UCSZ1) | (1<<UCSZ0);
UCSRB |= (1<<TXEN);
_delay_ms(100);
}

void UART_OdbiornikInit()
{
UBRRL = 6;
UBRRH = 0;
UCSRC |= (1<<UCSZ1) | (1<<UCSZ0);
UCSRB |= (1<<RXEN) | (1<<RXCIE);
}

void UART_Wyslij(char znak)
{
while(bit_is_clear(UCSRA,UDRE)) {}
UDR=znak;
}

void UART_WyslijTablice(char Tablica[], int Rozmiar)
{
for(int i=0;i<Rozmiar;i++)
{
	UART_Wyslij(Tablica[i]);
}
}

char UART_Odbierz()
{
return UDR;
}

Ogólnie zasada jest taka: wysyłam liczbę i po wysłaniu zwiększam licznik i wyświetlam.

Obserwując zmiany na wyświetlaczu zauważyłem, że jest wysyłanych ok 7 liczb na sekundę.

Więc najważniejsze pytanie.

Z jaką ja prędkością to w końcu wysyłam?? Czy na pewno 9600bps czy może coś pokręciłęm.

Proszę o pomoc i pozdrawiam

[ Dodano: 29-01-2012, 10:27 ]

Wyeliminowałem z programu niepotrzebne funkcje obsługo LCD. Do PC5 podpiąłem diodę led, która zmienia stan na przeciwny po każdym wysłaniu jednej liczby. Częstotliwość taktowania zmieniłem na 8MHz.

Program wygląda następująco:

#include<avr\io.h>

char dana1=120;

void UART_NadajnikInit()
{
UBRRH = 0;
UBRRL = 51;
UCSRC |= (1<<UCSZ1) | (1<<UCSZ0);
UCSRB |= (1<<TXEN);
}

void UART_Wyslij(char znak)
{
while(bit_is_clear(UCSRA,UDRE)) {}
UDR=znak;
}

int main()
{
DDRC=0xFF;
PORTC=0xFF;
UART_NadajnikInit();
while(1)
{
	UART_Wyslij(dana1);
	PORTC=0x00;
	UART_Wyslij(dana1);
	PORTC=0xFF;
}
return 0;
}

Prędkość ustawiona na 9600bps, a mimo to dioda miga z częstotliwością ok 15 razy na sekundę.

A więc układ wysyła 15 liczb w ciągu sekundy. To chyba trochę za mało na prędkość 9600bps??

Gdzie więc tkwi błąd??

A może tak ma być przy tej prędkości??

Proszę o pomoc bo sam już nie wiem co z tym zrobić.

Pozdrawiam

Link do komentarza
Share on other sites

Wysłany: 1 minutę temu     

Próbowałeś ustawić bit UX2?

Ustawiłem ten bit i prędkość się zwiększyła (zapewne dwukrotnie), jednak nadal zmiany diody są zauważalne gołym okiem.

Rozumiem, że przy prędkości 9600bps układ powinien wysyłać blisko 1000 liczb na sekundę? Czy dobrze rozumuję??

Link do komentarza
Share on other sites

Sam zaczynam pisać w C i mam na razie dużo problemów z UART'em, ale wydaje mi się, że nie jesteś w stanie osiągnąć takiej prędkości jaką ustawiasz, ponieważ pomiędzy kolejnymi wysyłkami mija pewna ilość cykli procesora. Ta prędkość jest już raczej zadeklarowana dla przesyłu, czyli tą twoją zmienną wysyła w tempie 9600bps, więc skoro to char i ma 8 bitów, to zajmie ci to 0,0008s, a nie wiadomo ile czasu minie do następnego przesyłu.

[ Dodano: 29-01-2012, 11:18 ]

Poza tym, robisz chyba tak:

-wysyłasz

-włączasz diodę

-wysyłasz

-wyłączasz diodę

więc na jedno mignięcie diody wysyłasz dwie zmienne.

dioda miga z częstotliwością ok 15 razy na sekundę.

A więc układ wysyła 15 zmiennych w ciągu sekundy.

Skoro miga 15 razy, to wysyłasz 30 zmiennych.

Do tego napisałeś, że po ustawieniu UX2 zwiększyła się dwukrotnie, więc jest to 60 zmiennych.

60*9 = 540 (9, bo 8 bitów ma zmienna, ale masz stop bita jeszcze).

To wg mnie tak źle nie jest.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Problem rozwiązałem, choć nie do końca rozumiem. Ustawiłem bit URSEL w rejestrze UCSRC. Teraz działa jak należy, tzn. przy prędkości 9600bps wysyła kilkaset liczb na sekundę. Doczytałem, że ten bit służy do wyboru rejestru UCSRA lub UBRRH. Czy ktoś mógłby mi wyjaśnić na chłopski rozum, do czego służy ten bit??

Bo w tym momencie program działa, ale sam nie rozumiem do końca swojego programu.

  • Lubię! 1
Link do komentarza
Share on other sites

Ustawiłem bit URSEL w rejestrze UCSRC. Teraz działa jak należy, tzn. przy prędkości 9600bps wysyła kilkaset liczb na sekundę. Doczytałem, że ten bit służy do wyboru rejestru UCSRA lub UBRRH. Czy ktoś mógłby mi wyjaśnić na chłopski rozum, do czego służy ten bit??

Rejestry UCSRC i UBRRH mają ten sam adres w przestrzeni adresowej rejestrów. Dlatego w zależności na którym z nich chcesz operować musisz dodatkowo korzystać z bitu URSEL. Przeczytaj rozdział: Accessing UBRRH/UCSRC Registers

Zobacz pokazane tam przykłady kodu C zarówno dla odczytu jak i zapisu rejestrów UCSRC i UBRRH i popraw swój program.

Link do komentarza
Share on other sites

Oki. Już rozumiem o co chodzi z tym bitem URSEL. Musi być ustawiony gdy wpisujemy do UCSRC. Gdy URSEL=0, to wpisujemy do UBRRH. Dzięki za pomoc

czyli takim kodem:

void UART_NadajnikInit() 
{ 
   UBRRH = 0; 
   UBRRL = 51; 
   UCSRC |= (1<<UCSZ1) | (1<<UCSZ0); 
   UCSRB |= (1<<TXEN); 
} 

faktycznie wpisywałeś do UBRRH =6 a nie 0, a do UBRRL = 51, czyli spowalniałeś transmisję 6x, ponieważ zamiast zapiać do UCSRC zapisywałeś do UBRRH.

Natomiast bity UCSZ1 i UCSZ0 w UCSRC miałeś ustawione poprawnie dlatego, że to domyślny stan bitów UCSZ czyli przypadek 🙂

Link do komentarza
Share on other sites

Malutka poprawka: wpis wartości 6 do UBRRH dawał podzielnik (6*256)+51+1=1588 w porównaniu do 51+1 przy UBRRH=0 co zwalniało prędkość transmisji 1588/52 czyli ok 30.5 raza.

I jeszcze to, że wysyłany przez UART znak ma oprócz bitów danych (zwykle 8) dodatkowe bity STARTu i STOPu czyli typowo jest ich 10 - łatwiej liczy się w pamięci liczbę znaków na sekundę 🙂

No i nie ma sensu dwa razy inicjować zawartości rejestrów UBRRL/H jak to było w pierwotnej wersji programu. Podzielnik jest wspólny więc i szybkości nadawania i odbioru są zawsze takie same. Osobne funkcje inicjalizacji nadajnika i odbiornika mogą mieć sens gdy pracując w half-dupleksie chcemy mieć dwie różne prędkości lub formaty danych ale to bardzo wyuznany przypadek, np. gdy odbieramy dane z jednego urządzenia a wysyłamy coś do zupełnie innego.

Acha, i nieprawdą jest, że "pomiędzy kolejnymi wysyłkami mija pewna ilość cykli procesora". Nadajnik UARTa jest buforowany i zgłasza swoją gotowość do załadowania nowego znaku zanim do końca zostanie nadany bit stopu. Tak więc znaki są "przyklejone" do siebie bez żadnych przerw chyba, że spóźnimy się z podesłaniem następnych danych. Dlatego warto obsługiwać UARTa na przerwaniach.

Coś takiego nie działa niestety w SPI w ATmegach - tam nie ma buforowania i czas reakcji procesora wlicza się do przerw w transmisji 🙁 co widać szczególnie przy szybszych transferach. Dla zegara SCK rzędu kilku MHZ nawet obsługa SPI w przerwaniu robi dziury pożerające np. 1/4 szybkości.

EDIT: dopisałem zdanie o dwóch szybkościach transmisji.

Link do komentarza
Share on other sites

Malutka poprawka: wpis wartości 6 do UBRRH dawał podzielnik (6*256)+51+1=1588 w porównaniu do 51+1 przy UBRRH=0 co zwalniało prędkość transmisji 1588/52 czyli ok 30.5 raza.

Celna poprawka 🙂

Link do komentarza
Share on other sites

Oj mieszacie chłopaki. Przypisujac do UBRRL wartość 51 otrzymacie max 2400bps

Prawidłowy kod inicjujacy na 9600 dla atmegi pracującej przy 1 MHz wyglada tak

UBRRH = 0;

UBRRL = 0x33;

UCSRC = (1<

UCSRA &= ~(1<

UCSRB = (1<

ramka 8 bitów bez parzystosci 2 bity stopu. UBRRL przypisujesz 12 i podciagasz bit U2X

Acha i to jest max jaki możesz wyciągnąć z tego procka przy takim taktowaniu. Potem przesunięcia zegara są zbyt wielkie. Bez bitu U2X możesz max wyciągnąć 4800.

Jak chcesz więcej musisz dodać kwarc.

Link do komentarza
Share on other sites

Oj mieszacie chłopaki. Przypisujac do UBRRL wartość 51 otrzymacie max 2400bps

Oj, zanim zarzucisz komuś "mieszanie" najpierw dokładnie przeczytaj, co napisałem: https://www.forbot.pl/forum/postlink/59126.htm#59126

Autor tematu nie ustawiał URSEL, przez co zapisywał do UBRRH najpierw zero, by zaraz później wpisać tam wartość (1<

Link do komentarza
Share on other sites

Tak znalazłeś błąd w UBRRH ale wartość UBRRL była nieprawidłowa. Bez bitu U2X to około 1200bps.

O tym na samym początku napisał KD93: https://www.forbot.pl/forum/postlink/59118.htm#59118

Próbowałeś ustawić bit UX2?

Autor prosił o tłumaczenia, a nie gotowce, a patrząc na jego słownictwo, ładnie pisany kod i umiejętność czytania datasheetów sądzę, że sobie radzi bez nich.

Więc następnym razem zanim coś napiszesz kol. SeerKaza, czytaj proszę ze zrozumieniem całość tematu.

Bo gdybyś czytał dokładnie to byś doczytał, że:

Częstotliwość taktowania zmieniłem na 8MHz.
Link do komentarza
Share on other sites

Fakt masz racje nie zauważyłem że zmienił częstotliwość taktowania. A co do czytania. Kilka osob znajduje jakiś błąd każda inny. A wartość 51 w UBRRL była także w 1MHz. Widać ktoś się lubi kłócić. I atakować za jeden żartobliwy zwrot.

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.