Atmega32 UART
Moderátor: Moderátoři
Atmega32 UART
#include <avr/io.h>
int main(void)
{
DDRB |= (1 << PINB1);
PORTB &= ~(1<<PINB0);
DDRB &= ~(1 <<PINB0);
PORTB |= (1 << PINB0);
int Pressed = 0;
int Pressed_Confidence_Level = 0;
int Released_Confidence_Level = 0;
int UBRR_Value = 25;
UBRRH = (unsigned char)(UBRR_Value >> 8 );
UBRRL = (unsigned char)UBRR_Value;
UCSRB = (1 << RXEN) | (1 << TXEN);
UCSRC |= (1 << USBS);
UCSRC |= (3 << UCSZ0);
while (1)
{
if (bit_is_clear(PINB,0))
{
Pressed_Confidence_Level ++;
Released_Confidence_Level = 0;
if (Pressed_Confidence_Level > 500)
{
if (Pressed ==0)
{
Pressed =1;
PORTB ^= (1 << PINB1);
while (! (UCSRA & (1 << UDRE)));
UDR = 0b11110000;
}
Pressed_Confidence_Level = 0;
}
}
else
{
Released_Confidence_Level++;
Pressed_Confidence_Level = 0;
if (Released_Confidence_Level > 500)
{
Pressed = 0;
Released_Confidence_Level = 0;
}
}
}
}
- JirkaRCK
- Příspěvky: 248
- Registrován: 25 dub 2010, 00:00
- Bydliště: Olomouc/Brno
- Kontaktovat uživatele:
přijde mi, že je to tlačítko řešeno příliš komplikovaně. Proč to pro základní test ve while smyčce neuděláš prostě následovně:
while 1{
Když je tlačítko stisknuto{
Zapsat byte do TX registru //Tím se hned i zahájí odesílání
delay cca 300ms //Provizorní ošetření zákmitu - aby se stisk nepřečetl 2x
while byte je odeslán; //Čekání na odeslaný packet
}
}
Dále bych doporučil i na TX stranu připojit na některý z volných pinů LEDku, nechat ji po resetu zhaslou, a postupně řádek od řádku zkusit posouvat příkaz, co ji rozsvítí. Až uvidíš, že nereaguje hned jak má, budeš přesně vědět, na jakém řádku to zůstává viset
Delay můžeš udělat například funkcí _delay_ms() z knihovny util/delay.h
http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__util__delay_1gad22e7a36b80e2f917324dc43a425e9d3.html
Teď nemám moc času se tvým kódem zabývat a omlouvám se za užití pseudojazyka, ale pokud na osciloskopu chodí packety se správným bitratem a už odcházejí zpožděně, měl by být UART nakonfigurovaný správně. UART na atmeze je velmi jednoduchá věc. Ještě možná zkontroluj, jestli máš správně nastavený směr a pull-up pinu s tlačítkem.
Jinak k tomu tlačítku, možná je to složité, ale zase mi to přijde elegantnější, že nemusím nikde čekat, ale jak říkám teprve začínám, takže si rád nechám poradit.
Níže ještě přidávám kod pro RX čip, jelikož to teďka vypadá, že bude chyba spíše tam. Kdyby měl někdo nápad budu vděčný.
{
DDRB |=(1 <<PINB0);
int UBRR_Value = 25;
UBRRH = (unsigned char)(UBRR_Value >> 8);
UBRRL = (unsigned char)UBRR_Value;
UCSRB = (1 << RXEN) | (1 << TXEN);
UCSRC |= (1 << USBS);
UCSRC |= (3 << UCSZ0);
unsigned char receiveData;
while (1)
{
while (! (UCSRA & (1 << RXC)));
receiveData = UDR;
if (receiveData == 0b11110000) PORTB ^= (1 << PINB0);
}
}
while ( !(UCSRA & (1 << RXC)));
Přidal jsem si tam ledku která se bude přepínat při každém průchodu kodu. Přidal jsem ji právě před while ( !(UCSRA & (1 << RXC))); , ale je taky zpožděná. Když ten řádek s while zakomentuji tak bliká jak má.
status = UCSRA; // read data and status
rchar = UDR;
// -------------- check RX status -----------------------
if((status & (_BV(FE) | _BV(DOR) | _BV(PE))) != (u08)0)
{
. . . obsluha chyby
}
. . . jinak zpracování dat
Pokud se RXC nenahazuje, pravděpodobně nepřicházejí na přijímač USARTu korektní rámce.
- JirkaRCK
- Příspěvky: 248
- Registrován: 25 dub 2010, 00:00
- Bydliště: Olomouc/Brno
- Kontaktovat uživatele:
Dále zkus v makefilu úplně vypnout optimalizace. U AVR mi optimalizování už několikrát udělalo dost velké peklo, když narazilo na pro kompilátor zdánlivě nesmyslný cyklus/if, který ale měl své opodstatnění. Může to tak být právě v případě whilu čekajícího na byte.
Pro jistotu doporučuji také nespoléhat se na to, že se při povolení UARTu nastaví i směr GPIO, ale přes DDRx registr na začátku kódu nastavovat ručně TX jako výstupní a RX jako vstupní - možná to není třeba, ale já to tak vždycky raději dělal.
Při zápisu do registru UCSRC bych možná zkusil hodnotu vždy orovat hodnotou 10000000b (bit URSEL registru UCSRC). Nepamatuji si, že bych to takto dělal při konfiguraci UARTu na atmeze8, ale u 32ky píší v datasheetu "This bit selects between accessing the UCSRC or the UBRRH Register. It is read as one when
reading UCSRC. The URSEL must be one when writing the UCSRC."
Jinak mi na tvé konfiguraci nepřipadne nic zásadně chybného. Zkoušel jsem si ji dosadit do popisu v datasheetu a měla by symbolizovat 8 bitů dat, 1 stop bit, bez parity, baud rate 2403.
Kód: Vybrat vše
#define BAUDRATE ((u16)(F_CPU/(16L * 38400L) - 1)) // 38400 bps on given F_CPU clock
. . .
usartInit(BAUDRATE);
. . .
/** Function initializes the USART HW */
void usartInit(u16 baud_rate)
{
UBRRH = (u08)(baud_rate>>8);
UBRRL = (u08)baud_rate; // set the baud rate
UCSRB = _BV(RXEN) | _BV(TXEN) |
_BV(TXCIE)|_BV(RXCIE); // Enable receiver and transmitter and interrupts
UCSRC = _BV(URSEL) | (0<<USBS) | (3<<UCSZ0); // Set frame format: 8data, 1stop bit
}
Bez nastavení bitu URSEL se bude přepisovat UBRRH (sdílí společnou adresu), čímž se zmastí přenosová rychlost. Také si nejsem jist, že vnitřní hodiny jsou dostatečně přesné pro správné časování UARTu.
Buď můžeš zkusit nějaký obecný, třeba modbus, ale s tím se budeš zabývat dlouho a zbytečně, pokud jej dále nevyužiješ.
Nebo si vytvoříš svůj. Třeba:
Pošleš nejdříve identifikátor např: 01h
Na druhé straně budeš vědět, že budou následovat data první proměnné.
Pak pošleš hodnotu.
A tak dál.
- JirkaRCK
- Příspěvky: 248
- Registrován: 25 dub 2010, 00:00
- Bydliště: Olomouc/Brno
- Kontaktovat uživatele:
Druhou možností je binární komunikace (neposíláš srozumitelný text, ale přímo obsah proměnných). Výhodou je kratší program, menší zátěž kontroléru a efektivnější přenos linky (bytovou proměnnou pošlu jako byte či dva, ne jako tři v případě ASCII řetězců). Nevýhodou je horší debug - data nejsou na terminálu v PC srozumitelná.
Když už se bavíme o binární komunikaci, tak osmibitová binární čísla v čisté podobě, nebo jak to nazvat, prostě byte dat = byte na uartu, nemám moc rád, protože když bych zvolil hlavičku zprávy např. 0xAA, nikde nemám zaručeno, že tuto hodnotu za běhu programu nenabude přenášená proměnná a nespletu si data s hlavičkou. Když už bych komunikoval binárně, přenášel bych jeden byte proměnné dvěma byty na uartu (4 významnější ("vyšší") byty pak můžeš použít pro označení, o co jde, 4 "nižší" pro přenos poloviny informace.)
Binární komunikace přenášející jeden byte (například číslo 0-255) dvěma byty by mohla vypadat následovně:
Číslo 0xAB rozdělím na dvě - na číslo 0x0A pomocí cisloA=proměnná>>4 a 0x0B pomocí cislo b=proměnná&0x0F.
Následně provedu binární OR s hlavičkou. Pro první půlku proměnné třebas 0xC0, pro druhou 0xD0.
Tím získám čísla 0xCA a 0XDB. Tato čísla pošlu po UARTu.
Na druhé straně - přijímací - vím, že 0xCA přenáší významnější čtveřici bitů proměnné cislo a tyto bity jsou 0xA0. Dále vím, že 0xDB přenáší méně významnější čtveřici a tyto bity jsou 0x0B. Když s hodnotami provedu OR, získám původní číslo 0xAB
Pokud budu chtít přenášet víc různých proměnných, tak stejně, jak jsem si tuto označil C a D, mohu jinou označit třeba 1 a 2...snad je to alespoň trochu srozumitelné. Jestli najdu chvíli, pokusím se to napsat jako kód.