ATMEGA: USART komunikácia-Súčasný príjem dát niekoľkých MCU

Dobry den,

prosim Vas o pomoc. Riesim komunikaciu viacerych CPU cez USART (vid. schema). Cez komunikaciu vzdy posielam len jeden byte (8-bitove cislo [0-255]).

evtom.707.cz/AVR/SchemaUSART.jpg

Moje riesenie bolo taketo:
CPU6 je hlavny CPU pre komunikaciu, ktorý prijme znak od jedneho z CPU a nasledne ho odosle pre ostatne CPU.
CPU1 az CPU5 ovladaju vlastne vstupy a vystupy a posielaju do CPU6 vzdy po jednom 8-bitovom cisle.
CPU4 a CPU5 zatial nie su zapojene.
CPU1 a CPU6 su vzdialene cca 2m ostatne CPU maju vzdialenost do 1m.
Napajacie napatie je z jedneho zdroja a pri kazdom CPU je napajanie stabilozovane cez L7805CV.

Problem je v tom, ze ak napr. CPU1 posle cislo, tak CPU6 ho sice prijme, no ostatne CPU ho neziskaju. Pravdepodobne som zle pochopil komunikaciu. Viete mi prosim pomoct ako riesit takuto komunikaciu s viacerymi CPU?

Este k pripojeniu CPU3. Ak som ho pripojil ako je zakreslene na scheme, tak CPU6 neprijal ziadny znak. Ked som prehoril TX a RX, tak CPU6 primal znaky.

Dakujem velmi pekne za akukolvek radu.

Prikladam linky na cast zdrojoveho kodu jednotlivych CPU tykajucich sa komunikacie USART:

:arrow_right: administrator: přejmenováno z “ATMEGA a komunikacia USART”

:arrow_right: administrator: příspěvek byl upraven

:arrow_right: administrator: přiloženy externí soubory
SchemaUSART.jpg
CPU6_len USART.c (2.76 KB)
CPU3_len USART.c (3.08 KB)
CPU2_len USART.c (3.19 KB)
CPU1_len USART.c (3.19 KB)

Možná by bylo nejlepší ke každýmu cpu dát převodník na RS485 například gme.cz/75176-p433-014 a pak to funguje tak že všichni jsou na poslechu a každý může vysílat (je třeba ohlídat kolize nějakým protokolem)

Na krátkou vzdálenost by měla udělat stejnou službu sběrnice s otevřeným kolektorem (na větší RS485). Měly by se ale řešit kolize vysílání (pokud to není řešeno jiným způsobem), aby vysílal vždy jen jeden procesor. Např. master procesor řídí komunikaci a dotazuje se cyklicky slave procesorů na data. Komunikace probíhá pomocí adresovaných paketů. Např. je-li potřeba přenášet 1 datový bajt, používají se pakety s délkou 1 nebo 3 bajty:

Dotaz master na slave zda má data:
11nnnnnn - n je adresa slave 0…63

Odpověď od slave s daty:
10nnnnnn - n je adresa slave 0…63
00xxaaaa - nižší 4 bity datového bajtu
00xxbbbb - vyšší 4 bity datového bajtu

Odpověď od slave že nemá data:
01nnnnnn - n je adresa slave 0…63

Každý slave čeká a odpovídá jen když se objeví jeho bajt 11nnnnnn, jinak si komunikace na sběrnici nevšímá.

Jinak by se dalo použít např. I2C.

Případně otevřený kolektor a protokol jaký používá sběrnice CAN kdy vysílat může začít kdokoliv kdykoliv a pokud dojde ke kolizi, odpadávají postupně nódy s adresami obsahující více jedniček protože současně poslouchají - 01010000 má vyšší prioritu než 01010011. Tohle se ale musí emulovat softwarově pokud teda nemáš CAN BUS na chipu…

Dakujem velmi pekne uzivatelovi Radius a Panda38 za odpovede. Ten prevodnik by som doplnil. Pozeral som sa nan, len mi nie je jasne, na co sluzia piny DE a RE. Na internete som nasiel obrazok, ze boli zapojene na CPU na dalsie dva piny. Je to potrebne? Co signalizuju, resp. naco sluzia? A este ako pripojit CPU6? rovnako ako ostatne? alebo tu prehodit piny ako boli predtym (RX a TX)?

V prilohe posielam upravenu komunikacnu schemu doplnenu o prevodniky a znazornene aj napajanie. CPU maju samozrejme ochranny kondenzator na napajani. Je potrebne ich davat aj k prevodnikom? Zas na jednom obrazku som videl pouzite 10R odpory na vystupe z prevodnika (piny A a B) - su potrebne?

To osetrenie komunikacie, aby vysielal len jeden CPU este zapracujem, aby teda CPU6 dopytoval ostatne CPU o hodnotu. Ak mu nejaky CPU posle hodnotu, tak ju posle vsetkym a vsetke CPU ju aj musia prijat. Len mi nie je jasne ako sa bude spravat CPU6, ked dopytovany CPU mu nebude mat co poslat. Ako to riesite? Alebo by som spravil, ze posle jeden kod, ktory bude urceny prazdnej kodnote a tu CPU6 odignoruje a bude dopytovat dalsi CPU.

Ak bude mat niekto z Vas zaujem o celkovy program mozem mu poslat na mail.

Zatial velmi pekne dakujem.
Lego vlaky Komunikacna schema.pdf (100 KB)

Signál DE - aktivuje vystup převodníku (je třeba aktivovat před vysíláním) Signál RE - aktivuje poslech (pokud nechceš poslouchat při vysílání tak je třeba deaktivovat)

Odpory u A,B někdy slouží jako ochrané (záleží na tobě).

Pokud bys měl mezi cpu dlouhé dráty a vyšší přenosovou rychlost, je vhodné zběrnici zaterminovat na konci a začátku odporem podle impedance kabelu.

Ano, všehny cpu budou zapojeny stejně.

Zablokovat napájení každému aktivnímu prvku je vhodné.

Pokud má cpu co poslat tak to musí poslat do určite doby jinak se to bere jako nic nemá (metoda timeout) a nebo pošle zprávu NIC_NEMAM.

Ještě poznámka - pokud by ti stačilo přepínat jen mezi režimem PŘÍJEM/VYSÍLÁNÍ tak spojíš signály DE a /RE a ovládáš pak celý převodník jedním drátem.

Jestli je to pro kolejiště tak tam už bude nutná 485, bude to hodně rušené.

Vzhledem k tomu že všechno bude zapojené na jednom vedení, tak není důvod aby CPU6 po příjmu ten bajt rozesílal ostatním CPU, protože ty tu hodnotu mohou vidět hned. CPU6 slouží jen na to, aby časoval povely, kdy má který CPU vysílat. Možná bys mohl upřesnit co je obsahem datového bajtu (alespoň jaký rozsah se využívá). Je-li to 0 až 255, tak si nevystačíš jen s vysíláním jednoduchého bajtu, protože bys nerozlišil adresu od dat, je to potřeba rozložit na méně bitů a odlišit tak řídicí kódy od dat.

Pokud CPU nemá co vysílat, měl by to oznámit prázdným paketem. Jiná možnost je že každý CPU má vyhrazené krátké časové okno, když nemá data tak neodpoví. Musí si ale hlídat kdy mu přišel dotaz a pokud uplynula určitá doba, tak už nesmí odpovědět, jinak by mohl narušit nový dotaz od mastera.

S přepínáním směru vysílače 485 pozor, po odeslání posledního bajtu se musí čekat až bude vysílací buffer prázdný, jinak by se přepnutím na příjem poslední bajt narušil (odeslání bajtu chvíli trvá).

Dakujem velmi pekne za odpovede.

Do komunikacnej schemy som doplnil priblizne dlzky komunikacie medzi jednotlivymi CPU. Ako Panda38 spomenul, ide o vlakovu zeleznicu, ale je to vsetko z lega a kazdy vlak ma vlastne baterie - kolajnice su plastove, takze rusenie by tam nemalo byt velke. Popri komunikacii mi ide 2x napajanie, zatial docastne 1x10V pre L7805CV z ktorych robim 5V - kvoli ubytku napatia som ho zdvykol na 10V aby aj v poslednom CPU dokazal stabilizator spravit 5V a 1x11V pre napajanie motorcekov pre prepinanie vyhybiek. Do buducna, ked budem robit uz plosaky chcem spojit tie dve napajania do jedneho, kde sa mi zvysi prierez kabla a pustim tam vacsie napatie, ktore najprv zrazim stabilizatorom 7809TO220 na 9V pre napajanie morocnekov a potom z tych 9V stabilizatorom L7805CV spravim 5V pre CPU, LED a pod.
CPU su cez externy krystal taktovane na 14,7456MHz a prenosovu rychlost som zvolil 9600 baud, chybovost je 0,0%. Prosim len o potvrdenie, ci je to spravne, popripade, ci je vhodne zvysit rychlost? Bude potrebne pouzit “zaterminovanie” komunikacie?

Radius - tie ochrane odpory ty pouzivas a ak ano tak akej hodnoty? Nerobi mi problem ich tam doplnit, aj pri programovani cez LPT port a piny MISO, MOSI a SCK pouzivam ochranne odpory, tam mam 330 Ohm. Neviem ako velmi je citlivy tento prevodnik.

Napajanie prevodnikov zablokujem ako pri CPU 100nF keramickym kondenzatorom.

Ten prevodnik teda pouzijem presne SN75176BP, ako ste mi poradili, dufam, ze bude dobre fungovat pri danej frekvencii a rychlosti. Do komunikacnej schemy som doplnil zapojenie pinov DE a RE na jeden vystup CPU. Ak som spravne pochopil, nastavim na pine CPU log 0 pre citanie z komunikacii (prijat znak) a log 1 pre pre posielanie do komunikacie (odoslat znak). Pri CPU6 v komunikacnej scheme som principialne zakreslil signalizaciu s dvoma LED diodami, ktora by mala znazornit, ci dany CPU cita alebo vysiela - aj ked neviem, ci to bude volnym okom pozorovatelne.

Rozmyslal som nad prepinanim medzi citanim a odosielanim pri CPU1-5. Ako riesenie mi vychadza urobit to cez prerusenia:

  1. Zapnutie napajania, CPU1-5 bude prepnute do rezimu citania a CPU6 do rezimu vysielania.
  2. CPU6 posle znak 11000001 (vysielaj CPU1) - neviem, ci nie je potrebne osetrit, aby zacal vysielat az po urcitom case, aby boli vsetky CPU pripravene po privedeni napajania na citanie? Mozno by som pre CPU6 pouzil delay_ms hned na zaciatku na cca 5 sekund.
    3.1. CPU1-5 prijme znak a po dokonceni prijmu znaku skoci do prerusenia USART0 Tx Complete (USART0_TX alebo USART_TX) a vyhodnoti, ci dany CPU moze alebo nemoze vysielat.
    3.2. CPU6 skoci do prerusenia USART Rx Complete (USART_RX) a prepne sa do rezimu citania.
    (poznamka)
  3. Po precitani znaku CPU1 zisti, ze ma vysielat.
    (poznamka)
  4. Nasledne sa CPU1 prepne do rezimu vysielania a ak ma co poslat, tak posle udajovy znak a ak nie, posle 11000000 (prazny znak). Ostatne CPU ostavaju v rezime citania.
  5. Poslanu hodnotu prijme CPU2 az CPU6 a skocia do prerusenia TX Complete. CPU1 skoci do prerusenia RX Complete.
    6.1. Ak ide o udajovy znak, kazde CPU okrem CPU1 ho prijme a zapracuje (aj CPU6 - kde LED diodami signalizujem ktora trat je volna a ktora obsadena - pre info)
    6.2. Ak ide o prazdny znak, CPU1-5 ho odignoruje a spracuje ho len CPU6. V podstate ho aj CPU6 odignoruje.
    (poznamka)
    7.1. CPU1 sa prepne do rezimu citania.
    7.2. CPU6 sa prepne do rezimu vysielania a posle znak 11000010 (vysielaj CPU2) a vsetko sa zopakuje. Takto by to stale dookola.

(poznamka) → Tieto poznamky som tam vkladal preto, ci tam netreba cakat na vyprazdnenie buferu, ako pisal Panda38, alebo staci pouzit prepinanie v preruseniach RX/TX Complete? Ak nie, slo by to osetrit cez prerusenie USART, Data Register Empty (USART0_UDRE a USART_UDRE)? Zatial som to chapal tak, ze ked skoci do prerusenia RX Complete, tak je komunikacia skoncena a moze sa zas pouzit na prenos.

V prilohe posielam upravenu komunikacnu schemu a tabulku vyznamu kodov, ktore pouzivam pri prenose.

Zatial velmi pekne dakujem.
Lego vlaky Vyznam znakov.pdf (23 KB)
Lego vlaky Komunikacna schema.pdf (126 KB)

Nevím, jestli nejde jenom o překlep, ale v bodech 3 a 6 píšeš opačně o přerušeních TX Complete a RX Complete. TX Complete (Transmit Complete - vysílání dokončeno) je vyvoláno po odvysílání znaku a nikoliv po jeho příjmu. O to se stará RX Complete (Receive Complete - příjem dokončen).

Pokud posíláš pouze 1 byte, pak můžeš zpracování přijatého bytu vložit do rutiny přerušení RXC. Pokud je byte určený pro daný procesor a je-li třeba poslat odpověď, vypneš poslech (abys neposlouchal sám sebe), zapneš vysílání a uložíš odpověď do registru pro odvysílání. Rutina TXC pak zajistí opětovné přepnutí na poslech linky.

Ochrané odpory ano, cca 10 ohmů , terminační odpory ano 120 ohmů na každé straně. Rychlost komunikace neřeš, převodník má bohaté rezervy.
Všechno vyřeš v přerušení (časování i komunikaci)
Komunikační protokol v podstatě OK jen jak poznamenal Balů - Rx a Tx done ti nesedí… a jen drobnost - pokud některý z cpu1-5 něco odvysílá, nesmí ta se data krýt s výzvou od mastera.

Jo a ledky doporučuju na samostatné vystupy abys mohl bliknutí programově prodloužit…

Dakujem velmi pekne za rady. Za vymenu RX a TX preruseni sa ospravedlnujem, aj ked som si daval pozor, i tak sa mi podarilo ich vymenit. Prevodniky mam objednane, tak uz len budem skusat. Ak nieco ozvem sa. Este raz dakujem za pomoc.

Já jsem si to vyrešil naprogramováním I2C zběrnice v režimu Multimaster. Když vznikne kolize na SDA, kdo prohrává, odmlčí se a počká si na STOP podmínku.
Dost jsem se s tím potrápil, protože jsem neměl dost informací jak to vlastně funguje v reálu.
Právě jsem objednal logický analyzátor, kterým má podporu I2C analýzy. Tak se na to podívám i z této stránky.