Skocz do zawartości

Problem z UART atmega 128


Mateusz

Pomocna odpowiedź

Witam.

Mam wydaje mi się dość nietypowy problem.

Oto fragmenty mojego kodu:


//**************************************
//procedura transmisji SPI
//**************************************
void Send_SPI(void)
{

SPDR = 0b00000000;
while(!(SPSR & (1<<SPIF)));

bufor1_SPI = SPDR;

SPDR = 0b00000000;
while(!(SPSR & (1<<SPIF)));

bufor2_SPI = SPDR;

SPDR = 0b00000000;
while(!(SPSR & (1<<SPIF)));

bufor3_SPI = SPDR;

SetBit(PORTD,7); //wyłączenie przetwornika U6

buforH_SPI = ((bufor1_SPI<<4)|(bufor2_SPI>>4));
while(!(UCSR1A&(1<<5)));
UDR1 = buforH_SPI;   // wysłanie jednego bufora
buforL_SPI = ((bufor2_SPI<<4)|(bufor3_SPI>>4));
while(!(UCSR1A&(1<<5)));
UDR1 = buforL_SPI;   // wyslanie 2-go b

}

int main(void)
{
//**************************************
//ustawienie USART1
//**************************************
SetBit(PORTD,2); //ustawienie portu USART1 w stan wysokiej impedancji
SetBit(PORTD,3);
UCSR1B = 0b00011000; //ustawienie 1 na 3 i 4 bicie powoduje załącznie TXD i RXD
UCSR1C = 0b00000110; //ustawienie 1 na 2 i 3 bicie oznacza, że bedzie 8 bitow w ramce danych
UBRR1L = 36; //prędkość transmisji 19200
SetBit(UCSR1B,7); //włączenie przerwania od USART1 RX

sei(); //zgoda na globalne przerwanie

while(1)
{

if(flaga&(2<<1) && flaga&(3<<1))
{


for (int k=0; k<1 ; k++)
{

	while(!(UCSR1A&(1<<5)));
	_delay_us(100);
	UDR1 = 0b00110000;
	ClrBit(PORTD,7); //włączenie przetwornika U4
	Send_SPI();

	while(!(UCSR1A&(1<<5)));

	_delay_us(400);   // TUTAJ między innymi jest problem.
	UDR1 = 0b00001111;
}

}
}}

A więc chodzi o to, że po "while(!(UCSR1A&(1<<5)));" muszę czekać minimalnie 400us bo w innym przypadku zawsze (jeżeli bezpośrednio przed tą funkcją było coś wysyłane po USART) pierwszy bit wysyłanego bajtu jest jedynką.

W programie ogólnie chodzi o to że procek sczytuje dane z przetwornika DA i przesyła je do PC po UART.

Wydawało mi się, że sprawdzenie tej flagi while(!(UCSR1A&(1<<5))); w 100% wystarczą do tego żeby nie było żadnych śmieci podczas kolejnego wysyłania.

Czy coś robię źle czy tak ma po prostu być ? 😃

Link do komentarza
Share on other sites

Mam jeszcze jedno pytanie. W programie mam coś takiego, że uruchamiam licznik -> wykonuje jakieś operacje następnie sczytuje ilość zliczeń na liczniku. Posiadając tą liczbę muszę obliczyć ilość obr/min ale do tego potrzebuje czas przez jaki zbierałem dane z wejścia licznika.

W jaki sposób najlepiej zrobić pomiar tego czasu?

Link do komentarza
Share on other sites

Tak jak napisał Bobby, musisz na 1 timerze zliczać impulsy o znanej częstotliwości (impulsy zegarowe)a na 2 timerze, który będzie licznikiem, zliczać impulsy pochodzące z jakiegoś enkodera.

Jest też może troszkę mniej dokładny sposób, ale używający tylko 1 timera. Jeśli będziesz włączał licznik na ściśle określony czas to problem się sam rozwiązuje. Jeśli mikrokontroler wykonuje za każdym razem te same operacje to można założyć, że czas wykonywania jest mniej więcej taki sam, jeśli wcześniej go zmierzysz za pomocą timera, to potem możesz go przyjąć za stałą.

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

Dzięki za pomoc 🙂 Wykorzystałem jeden z timerów który generuje przerwanie co 0.1ms w przerwaniu dodaje 1 do zmiennej "time" po sczytaniu z niej wartości przed zaczęciem zliczania impulsów i po zakończeniu znam czas operacji 🙂

Teraz mam pytanie w jaki sposób przesłać liczby rzędu 20000 po usart ? Znacie może jakieś proste metody? Zależy mi na tym aby czas wysyłania był jak najmniejszy więc najlepiej używać jak najmniejszej liczby wysyłanych ramek 🙂.

Link do komentarza
Share on other sites

Najszybciej to można wysłać najpierw górne 8bitów liczby, później dolne 8b. Czyli:

 unsigned int dane = adc_val();

 uart_send(dane>>8);
 uart_send(dane);

Problem w takiej sytuacji to po pierwsze wykrywanie błędów, po drugie wykrycie początku danych.

Jeśli coś mogę polecać, to transmisję tekstową i zwiększenie prędkości uart (np. do 115200).

Link do komentarza
Share on other sites

Co masz na myśli pisząc transmisję tekstową ? Chodzi o to aby liczbę np 100 wysłać w trzech bajtach? Czyli każdą cyfrę osobno ?

Link do komentarza
Share on other sites

Tak, nawet w 4 bajtach - bo na końcu znak nowej linii.

Dużo łatwiej jest takie dane odczytać, wystarczy hyperterminal, błędy widać o tyle, że wszystko co nie jest liczbą trzeba odrzucać, nie ma problemu z wykrywaniem początku ramki, bo znaki końca linii oddzielają dane.

Żeby było łatwiej można użyć standardowego printf - wystarczy przekierować wyjście na uart i kod:

 printf("%d\n", dane);

załatwia sprawę.

Do tego akwizycję danych można dać na przerwaniach i program działa pięknie i prosto.

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

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.