Skocz do zawartości
MilordGibon

[C][ATMEGA32A] Buetooth przez UART i wyświetlacz LCD

Pomocna odpowiedź

Witajcie Panowie, to mój pierwszy post i mam pewien problem - chcę wysyłany znak wyświetlić na wyświetlaczu LCD, ale niezbyt mi to wychodzi. Dzieje się to tak:

1) Wysyłam znak: a

2) Jest mi on poprawnie odsyłany

3) Na wyświetlaczu pojawia się znak(na zielono, co powinno się pojawić, a na czerwono, co wyświetla)

Drugi przykład, przy wysłaniu znaku q:

Tutaj jest mój kod, powiem, że wyświetlanie znaku z nadaną zmienną (np. char a = "a";) - działa poprawnie:

#include <avr/io.h>
#include <avr/delay.h>
#include <stddef.h>
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE 6
#include "hd44780.h"
int main (void)
{
/* Funkcja inicjalizuje wyświetlacz*/
lcd_init();
/* Włącza wyświetlanie */
LCD_DISPLAY(LCDDISPLAY);         

char ReceivedByte;
UCSRB = (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1) | (1 << USBS); // Use 8- bit character sizes
UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8- bits of the baud rate value into the high byte of the UBRR register
UBRRL = BAUD_PRESCALE ; // Load lower 8- bits of the baud rate value into the low byte of the UBRR register
for (;;) // Loop forever
{
	while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
	ReceivedByte = UDR; // Fetch the received byte value into the variable " ByteReceived "
	while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data tobe written to it
	UDR = ReceivedByte; // Echo back the received byte back to the computer
	        /* Ustawia kursor w pozycji:
       pierwszy wiersz, szósta kolumna */
       LCD_LOCATE(0,0);
	LCD_CLEAR;
	LCD_WRITE_DATA(ReceivedByte);		
}
}

Będę wdzięczny za opinie i pomoc 😅

Udostępnij ten post


Link to post
Share on other sites

Moim zdaniem masz problem z niedopasowaniem prędkości. Jeżeli pracujesz z zegara 1MHz to dostajesz:

1000000/16/7=8930

co jest dość dużą odchyłką w stosunku do wymaganych 9600 (7%). Jeżeli dodasz do tego tolerancję zegara procesora, możesz być daleko poza granicą akceptowalnej różnicy prędkości. UART nadaje znaki "od tyłu" czyli LSB przodem. Jeśli narysujesz sobie kod znaku "a" czyli 0b01100001 od tyłu oraz uzupełnisz go bitem stopu = 1 dodawanym na końcu (za MSB) a potem spróbkujesz to wolniej np. o 10% to zauważysz, że dostajesz 0b10100001 co jest własnie kodem tego dziwnego cosia jaki widzisz na LCD. Ponieważ z tą samą dziwną prędkością nadajesz, przy odrobinie szczęścia PC odbiera to dobrze i pokazuje prawidłowe 'a".

Przy transmisjach przez UART warto używać wysokich zegarów procesora, bo wtedy jest z czego dzielić. W twoim przypadku możesz się poratować przełączeniem UARTa w tryb 2X, wtedy dla 9600 podzielnik wychodzi prawie dokładnie 13, czyli UBRR=12. Najlepiej jednak podkręcić procesor do 8MHz a dla naprawdę dużych prędkości używać specjalnych kwarców, np. 3.6864MHz lub 7.3728MHz dopasowanych specjalnie do transmisji asynchronicznych.

  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites
Moim zdaniem masz problem z niedopasowaniem prędkości. Jeżeli pracujesz z zegara 1MHz to dostajesz:

1000000/16/7=8930

co jest dość dużą odchyłką w stosunku do wymaganych 9600 (7%). Jeżeli dodasz do tego tolerancję zegara procesora, możesz być daleko poza granicą akceptowalnej różnicy prędkości. UART nadaje znaki "od tyłu" czyli LSB przodem. Jeśli narysujesz sobie kod znaku "a" czyli 0b01100001 od tyłu oraz uzupełnisz go bitem stopu = 1 dodawanym na końcu (za MSB) a potem spróbkujesz to wolniej np. o 10% to zauważysz, że dostajesz 0b10100001 co jest własnie kodem tego dziwnego cosia jaki widzisz na LCD. Ponieważ z tą samą dziwną prędkością nadajesz, przy odrobinie szczęścia PC odbiera to dobrze i pokazuje prawidłowe 'a".

Przy transmisjach przez UART warto używać wysokich zegarów procesora, bo wtedy jest z czego dzielić. W twoim przypadku możesz się poratować przełączeniem UARTa w tryb 2X, wtedy dla 9600 podzielnik wychodzi prawie dokładnie 13, czyli UBRR=12. Najlepiej jednak podkręcić procesor do 8MHz a dla naprawdę dużych prędkości używać specjalnych kwarców, np. 3.6864MHz lub 7.3728MHz dopasowanych specjalnie do transmisji asynchronicznych.

Mógłbyś mi pokazać, jak to powinno wyglądać? Tylko, proszę, zaznacz miejsca zmian 🙂 mi najłatwiej jest się uczyć na przykładach 😃

Udostępnij ten post


Link to post
Share on other sites
   UCSRB |= (1 << RXEN ) | (1 << TXEN );
  UCSRC |= (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 );
  UBRRH = ( 51 >> 8);
  UBRRL = 51;
  UCSRB |= (1 << RXCIE );

Prawidłowa konfiguracja dla 8 MHz (zmień Fusebity oraz w kodzie projektu).

Przy zachowaniu prędkości 9600 błąd wyniesie 0.2%

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Panowie, dziękuję, działa w 100%.

Dziękuję za teorię, ale też i za praktykę, na pewno przyda się w nauce 😃

EDIT: Mam prośbę - powiesz mi, skąd się wzięła tam ta liczba "51" przy UBRLH? Istnieje na to jakiś wzór?

Udostępnij ten post


Link to post
Share on other sites

Oczywiście, przecież to żadna magia. Zwykle UART musi dostać zegar 16 razy szybszy niż żądana prędkość transmisji, tak więc:

UBRR = (F_CPU/16/BAUD)-1

gdzie:

F_CPU to zegar procesora,
BAUD to szybkość nadawania/odbioru

no a -1 bierze się ze specyfiki działania podzielnika w UARTach procesorów AVR.

Do rejestru UBRR możesz wpisać tylko liczbę całkowitą (maksymalnie 12-bitową) więc jeżeli w wyniku obliczeń wyjdzie mała liczba z ułamkiem - jak w przypadku zegara 1MHz i prędkości 9600, to niedobrze. Błąd zaokrąglenia może spowodować zbyt dużą różnicę prędkości dwóch współpracujących UARTów i podobne problemy na jakie już nadepnąłeś. Oczywiście w przypadku współpracy dwóch procesorów będących pod Twoją kontrolą, prędkości mogą być dowolnie dziwne, byle by były takie same. Przy współpracy z czymś zewnętrznym nie wychodź poza błąd rzędu 2-3%. Odbiornik UARTa próbkuje linię 3 razy (dla pewności) w teoretycznym środku czasu nadawania bitu, więc po obu stronach ma margines tylko na pół tego czasu. To niewiele, a synchronizacja następuje tylko raz - od bitu START czyli na początku ramki znaku. Już 4-5% różnicy powoduje, że na 10 bicie (a tyle trwa cała ramka) zaczynasz mylić się o pół czasu bitu a do tego dochodzą tolerancje zegarów obu stron. Jeżeli masz kwarc to jest OK, ale jeśli korzystasz z generatora RC to zmiany temperatury i poziomu zasilania potrafią rozwalić transmisję UART doskonale działającą w warunkach laboratoryjnych.

BTW: PC ma w sobie UART z podobnym dzielnikiem częstotliwości (np. jądro scalaka 16550) i teoretycznie można tam wpisać dowolny podział, ale systemowe API żądają podania jednej z typowych prędkości i tylko dla nich prawidłowo programują rejestry układu.

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.


×
×
  • Utwórz nowe...