Skocz do zawartości

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


MilordGibon

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 😅

Link do komentarza
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
Link do komentarza
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 😃

Link do komentarza
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
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

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?

Link do komentarza
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.

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.