přerušení vyvolané usartem
Moderátor: Moderátoři
přerušení vyvolané usartem
Ahoj, potřeboval bych prosím poradit, nebo aspon nasměrovat správným směrem.
Ovládám přes seriovou linku a tiny2313 krokový motor. Řízení probíhá tak že odešlu řetězec a atmel ho vyhodnotí a otáčí motorem bud doleva/doprava určený čas. Ale ted bych potřeboval aby se motor točil do té doby něž přijde nový příkaz, a podle vyhodnocení se bud točil dál nebo stál. K tomu je potřeba vyvolat přerušení , pokud se nepletu..
Ale nedaří se mi přijít na to jak správně nastavit přerušení na příchozí data, ty přijmout a pak přes switch zpracovat.
V příloze mám aktualní kod bez přerušení
Ovládám přes seriovou linku a tiny2313 krokový motor. Řízení probíhá tak že odešlu řetězec a atmel ho vyhodnotí a otáčí motorem bud doleva/doprava určený čas. Ale ted bych potřeboval aby se motor točil do té doby něž přijde nový příkaz, a podle vyhodnocení se bud točil dál nebo stál. K tomu je potřeba vyvolat přerušení , pokud se nepletu..
Ale nedaří se mi přijít na to jak správně nastavit přerušení na příchozí data, ty přijmout a pak přes switch zpracovat.
V příloze mám aktualní kod bez přerušení
- Přílohy
-
- test-1.txt
- (2.78 KiB) Staženo 84 x
- bohumilfulin
- Příspěvky: 109
- Registrován: 12 led 2010, 01:00
Musis si vytvorit komunikacni protokol. Uroven slozitosti necham na tobe. U primitivnich veci muze postacovat STARTBYTE + Commandbyte nebo jenom jednobytovy prikaz. U slozitejsich to muzes vysperkovat o CRC atd, atd.
Vychazejme z verze STARTBYTE + COMMANDBYTE. Prvni znak co prijde testujes zda je to STARTBYTE pokud ano, spustis casove omezeni prijmu a cekas na dalsi prijem znaku (preruseni od seriove linky). Kdyz prijde otestujes zda tomuto bytu predchazel Startbyte a zda je v casovem intervalu. Pokud ano vezmes jej a vyhodnotis (az do teto doby je platny predchozi prikaz nebo stav po resetu). Po vyhodnoceni zastavis casove omezeni a vse znovu. To casove omezeni je tam dulezite aby se ti linka nezustala viset treba kvuli ruseni co se nachomitne na linku.
Staci takto?
Vychazejme z verze STARTBYTE + COMMANDBYTE. Prvni znak co prijde testujes zda je to STARTBYTE pokud ano, spustis casove omezeni prijmu a cekas na dalsi prijem znaku (preruseni od seriove linky). Kdyz prijde otestujes zda tomuto bytu predchazel Startbyte a zda je v casovem intervalu. Pokud ano vezmes jej a vyhodnotis (az do teto doby je platny predchozi prikaz nebo stav po resetu). Po vyhodnoceni zastavis casove omezeni a vse znovu. To casove omezeni je tam dulezite aby se ti linka nezustala viset treba kvuli ruseni co se nachomitne na linku.
Staci takto?
Jde to i bez přerušení, pro jednobajtové povely třeba takto (vytvoř si funkce pro krok)
Kód: Vybrat vše
uint8_t mot_pause = 60; // pausa mezi kroky motoru
char rec_byte; // bajt přijatý z UART
uint8_t j;
while(1)
{
rec_byte = 0;
if(bit_is_set(UCSRA, RXC)) // přišel bajt?
{
rec_byte = UDR;
if(rec_byte == '+')
for(j=0;j<5;j++) krok_plus(); // 5 kroků směrem +
if(rec_byte == '-')
for(j=0;j<5;j++) krok_minus();
if(rec_byte == '1') mot_pause = 30; // motor rychle
if(rec_byte == '0') mot_pause = 60; // motor pomalu
if(rec_byte == 'L' || rec_byte == 'l')
while(2) // motor se točí doleva
{
krok_minus();
if(bit_is_set(UCSRA, RXC)) break; // vystup z while(2)
}
if(rec_byte == 'R' || rec_byte == 'r')
while(3) // motor se točí doprava
{
krok_plus();
if(bit_is_set(UCSRA, RXC)) break; // vystup z while(3)
}
}//if(bit_is_set
}//while(1)
}
Je požadováno zpracovat vícebajtový řetězec a to se při běžícím jiném programu dá jen dalším procesorem nebo přerušením.
---
minimum pro Mega64
---
minimum pro Mega64
Kód: Vybrat vše
.cseg
.org $0 RJMP INIT
.org $024 RJMP USART_REC
.org $034 RETI
USART_REC:
push r21
in r21,sreg
// tady rutina pro prijem
out sreg,r21
pop r21
RETI
INIT:
; config StackPointer
ldi r16,low(RAMEND)
out SPL,r16
ldi r16,high(RAMEND)
out SPH,r16
; config USART
ldi r16,25 ; Set BR
ldi r17,0
sts UBRR0H, r17
out UBRR0L, r16
ldi r16, 0b10001110 ;URSEL UMSEL UPM1 UPM0 USBS UCSZ1 UCSZ0 UCPOL
sts UCSR0C,r16
ldi r16, 0b10011000 ;RXCIE TXCIE UDRIE RXEN TXEN UCSZ2 RXB8 TXB8
out UCSR0B,r16
; IntEn
sei
LOOP:
//tady main prog
RJMP LOOP
- ZdenekHQ
- Administrátor
- Příspěvky: 25593
- Registrován: 21 črc 2006, 02:00
- Bydliště: skoro Brno
- Kontaktovat uživatele:
Taková komunikace se dělá celá v přerušení - po příjmu znaku se uloží data do nějakého bufferu s tím, že se vyhodnocuje čas do příjmu dalšího znaku (překročení se bere jako povel pro vyhodnocení), počet znaků, crc atd. a pokud vše sedí, teprve potom si to převezme hlavní program, buffer se smaže, vynulují čítače času atd.
Pro moje oslovení klidně použijte jméno Zdeněk
Správně navržené zapojení je jako recept na dobré jídlo.
Můžete vynechat půlku ingrediencí, nebo přidat jiné,
ale jste si jistí, že vám to bude chutnat[?]
Správně navržené zapojení je jako recept na dobré jídlo.
Můžete vynechat půlku ingrediencí, nebo přidat jiné,
ale jste si jistí, že vám to bude chutnat[?]
Při jakém "jiném běžícím programu"?
Bavíme se o zadání z původního příspěvku.
Tam to jde bez přerušení i kdyby příkaz byl vícebajtový.
Ale nevidím žádnou výhodu v použití příkazů ":1" , ":2" proti "1" , "2".
Proč označovat začátek jednobajtového příkazu?
Říkám jenom, že to v tomto jednoduchém případě jde, ne že je to nejlepší řešení..
Bavíme se o zadání z původního příspěvku.
Tam to jde bez přerušení i kdyby příkaz byl vícebajtový.
Ale nevidím žádnou výhodu v použití příkazů ":1" , ":2" proti "1" , "2".
Proč označovat začátek jednobajtového příkazu?
Říkám jenom, že to v tomto jednoduchém případě jde, ne že je to nejlepší řešení..
Základní vám popsal bohumilfulin. Pokud budete muset reagovat na vícero reálných asynchronních událostí, tak zde je několik zásad asynchronního programování:
- datový rámec přenosového protokolu by měl někde na začátku v hlavičce obsahovat délku dat (případně i verzi protokolu). Vyhnete se tak na vrstvě obslužné rutiny přerušení od příjmu dat analýze jestli je už přijato všechno. Rutina jen bude skládat data do bufferu a po každém znaku nastaví událost příjmu znaku. Tuto událost pak zpracovává centrální automat a až teprve ten rozhoduje, jestli je už přijato všechno nebo ne a co dál s přijatým povelem.
- vyhněte se jakýmkoliv čekacím smyčkám v přerušovacích rutinách a nejlépe úplně všude.
- pokud chcete zpracovávat nějaký časový interval, třeba hlídat dobu příjmu rámce protokolu, nebo jen počkat nějakou dobu, tak si udělejte obsluhu přerušení od časovače, která dekrementuje nějaký čítač, nebo i více čítačů. Můžete zpracovávat i mnoho různých časových intervalů současně. Časovač se nahodí nastavením čítače na nějakou hodnotu a od tohoto okamžiku se začne odměřovat čas. Pokud se některý čítač dostane v přerušovací rutině od HW časovače na nulu, došlo k vypršení daného času a nastavte příznak vzniku příslušné události.
- hlavní smyčka programu bude testovat výskyt událostí, které mohou třeba reprezentovány nastavováním nějakých bitů. Jakmile se detekuje, že někdo nastavil událost, třeba rutina příjmu znaku nastavila událost, že přišel znak, zavolá se centrální automat, který v sobě spustí příslušnou rutinu zpracování této události, ale, pozor, pro svůj aktuální stav. Zpracování stejné události se bude obecně lišit pro různé stavy. Dokonce, mnoho kombinací stavů a událostí bude vyloučených, například událost vypršení časovače, když nebyl nastaven a takto se dají detekovat různé bugy v kódu. Nakonec se nuluje příznak události.
- v centrálním automatu vznikne matice rutin, kde například řádek je dán aktuálním stavem a sloupec událostí. Většinou jsou tyto matice hodně řídké a jen několik rutin je třeba skutečně naprogramovat. Ostatní buď nic nedělají (return), nebo jejich vyvolání je chyba.
- dobře si rozmyslete stavy a události automatu. To je dáno konkrétní úlohou, kterou děláte.
Ač se to celé zdá jako velký orloj, tak s mírnou nadsázkou je to naprogramovat jednodušší než popsat. Při dodržení těchto zásad není pak problém systém rozšiřovat o další zpracovávané události z okolního světa a to pořád stejným způsobem. Hranicí je pak jen výkonnost procesoru. Takový způsobem je možno například simultánně třeba generovat řídící impulsy pro motor, přijímat data ze sériové linky a obsluhovat klávesnici.
- datový rámec přenosového protokolu by měl někde na začátku v hlavičce obsahovat délku dat (případně i verzi protokolu). Vyhnete se tak na vrstvě obslužné rutiny přerušení od příjmu dat analýze jestli je už přijato všechno. Rutina jen bude skládat data do bufferu a po každém znaku nastaví událost příjmu znaku. Tuto událost pak zpracovává centrální automat a až teprve ten rozhoduje, jestli je už přijato všechno nebo ne a co dál s přijatým povelem.
- vyhněte se jakýmkoliv čekacím smyčkám v přerušovacích rutinách a nejlépe úplně všude.
- pokud chcete zpracovávat nějaký časový interval, třeba hlídat dobu příjmu rámce protokolu, nebo jen počkat nějakou dobu, tak si udělejte obsluhu přerušení od časovače, která dekrementuje nějaký čítač, nebo i více čítačů. Můžete zpracovávat i mnoho různých časových intervalů současně. Časovač se nahodí nastavením čítače na nějakou hodnotu a od tohoto okamžiku se začne odměřovat čas. Pokud se některý čítač dostane v přerušovací rutině od HW časovače na nulu, došlo k vypršení daného času a nastavte příznak vzniku příslušné události.
- hlavní smyčka programu bude testovat výskyt událostí, které mohou třeba reprezentovány nastavováním nějakých bitů. Jakmile se detekuje, že někdo nastavil událost, třeba rutina příjmu znaku nastavila událost, že přišel znak, zavolá se centrální automat, který v sobě spustí příslušnou rutinu zpracování této události, ale, pozor, pro svůj aktuální stav. Zpracování stejné události se bude obecně lišit pro různé stavy. Dokonce, mnoho kombinací stavů a událostí bude vyloučených, například událost vypršení časovače, když nebyl nastaven a takto se dají detekovat různé bugy v kódu. Nakonec se nuluje příznak události.
- v centrálním automatu vznikne matice rutin, kde například řádek je dán aktuálním stavem a sloupec událostí. Většinou jsou tyto matice hodně řídké a jen několik rutin je třeba skutečně naprogramovat. Ostatní buď nic nedělají (return), nebo jejich vyvolání je chyba.
- dobře si rozmyslete stavy a události automatu. To je dáno konkrétní úlohou, kterou děláte.
Ač se to celé zdá jako velký orloj, tak s mírnou nadsázkou je to naprogramovat jednodušší než popsat. Při dodržení těchto zásad není pak problém systém rozšiřovat o další zpracovávané události z okolního světa a to pořád stejným způsobem. Hranicí je pak jen výkonnost procesoru. Takový způsobem je možno například simultánně třeba generovat řídící impulsy pro motor, přijímat data ze sériové linky a obsluhovat klávesnici.
diky za pomoc ale jsem naprostý začátečník takže bych spíš potřeboval, příklad kodu v C jak nastavit správně přerušení a přijmout celý řetězec.
Protokol kterým se to bude řídit je pevně daný , je to LX200 protokol pro řízení zařízení od Meade (astronomické dalekohledy), Já z toho budu používat pouze sadu pro ostření což jsou příkazy :F+#; :F-# ; :FF#; :FS#; :FQ#.
Nejraději bych v rámci přerušení přijmul celý řetězec do pole, a s tím bych pak dál pracoval. Např ve smyčce kdy se motor točí dopředu , bych ještě znova testoval zdali se nezměnil příkaz, vlivem přerušení, pokud ano, tak ukončit a vybrat přes case odpovídající ukon.
Protokol kterým se to bude řídit je pevně daný , je to LX200 protokol pro řízení zařízení od Meade (astronomické dalekohledy), Já z toho budu používat pouze sadu pro ostření což jsou příkazy :F+#; :F-# ; :FF#; :FS#; :FQ#.
Nejraději bych v rámci přerušení přijmul celý řetězec do pole, a s tím bych pak dál pracoval. Např ve smyčce kdy se motor točí dopředu , bych ještě znova testoval zdali se nezměnil příkaz, vlivem přerušení, pokud ano, tak ukončit a vybrat přes case odpovídající ukon.
Nejsem si jist, že jsem dobře porozuměl, ale pokud chcete mít speciální smyčku pro pohyb motoru dopředu a v té něco testovat, aby se to nepropáslo, tak to bych udělal jinak. Smyčka detekce událostí má být jen jedna pro všechno a to, že se motor točí dopředu by mělo být poznamenáno stavem. Uvedu příklad pro běžný ss motor. Pokud například přijde příkaz k zastavení motoru a stav je "TOCENI_VPRED" nebo vzad, provede se sekvence:hajs píše:Např ve smyčce kdy se motor točí dopředu , bych ještě znova testoval zdali se nezměnil příkaz, ...
- vypnutí napětí do motoru
- nahození časovače na skutečné zastavení
- přepnutí do stavu "CEKANI_NA_ZASTAVENI"
Ve stavu čekání není možno zpracovávat další příkaz pro motor. Pokud by v tomto stavu byl zkompletován nový příkaz, tak příslušná rutina reakce na událost zkompletování tohoto příkazu jej jen uloží. Naopak, ve stavu "ZASTAVENO" by příkaz ihned vykonala.
Po vypršení časovače se provede:
- kontrola, že jsme ve stavu čekání, protože vypršení časovače zastavování v jiném stavu je bugem programu. (Tato kontrola obvykle vznikne automaticky voláním různých rutin na událost podle stavu.)
- přepnutí do stavu "ZASTAVENO"
- kontrola, jestli po dobu čekání nepřišel další příkaz a jeho případné spuštění s nastavením patřičného stavu a případně i čekáním na rozběh podobně, jako při zastavování.
Byl-li příkaz k reverzaci motoru tak se pokračuje spuštěním v opačném směru. Časovač se může pro malé motorky vynechat, ale jeho použití způsobí šetrnější ovládání motoru. Pro krokový motor se časovače vynechají, namísto toho bude v činnosti časovač odměřující krokování motoru. Naznačeným způsobem je třeba správně reagovat na povely v daných stavech a také pomocí přepínání stavu udržovat povědomí programu o tom, v jaké fázi ovládání motoru právě jsme.
http://cs.wikipedia.org/wiki/Mealyho_automat
- ZdenekHQ
- Administrátor
- Příspěvky: 25593
- Registrován: 21 črc 2006, 02:00
- Bydliště: skoro Brno
- Kontaktovat uživatele:
Obávám se, že teorie někdy příliš složitě popisuje praxi. Dobrá věc na doktorát, ale příliš složitá pro praxi.
Spoustu podmínek lze ošetřit jen tím, že doba mezi příkazy bude vždy delší než potřebný čas na vykonání nejdelšího příkazu, t.j v tomto případě reverzace.
K té komunikaci - obecně v rámci alespoň nejjednoduššího zabezpečení proti rušení bych doporučil posílat přímou a následně negovanou hodnotu příkazu, v lepší případě i nějaký kontrolní součet. Nutný je naopak nějaký time-out časovač komunikace, jinak je to nepoužitelný.
Spoustu podmínek lze ošetřit jen tím, že doba mezi příkazy bude vždy delší než potřebný čas na vykonání nejdelšího příkazu, t.j v tomto případě reverzace.
K té komunikaci - obecně v rámci alespoň nejjednoduššího zabezpečení proti rušení bych doporučil posílat přímou a následně negovanou hodnotu příkazu, v lepší případě i nějaký kontrolní součet. Nutný je naopak nějaký time-out časovač komunikace, jinak je to nepoužitelný.
Pro moje oslovení klidně použijte jméno Zdeněk
Správně navržené zapojení je jako recept na dobré jídlo.
Můžete vynechat půlku ingrediencí, nebo přidat jiné,
ale jste si jistí, že vám to bude chutnat[?]
Správně navržené zapojení je jako recept na dobré jídlo.
Můžete vynechat půlku ingrediencí, nebo přidat jiné,
ale jste si jistí, že vám to bude chutnat[?]
4 řídící příkazy mám pevně dané (:F+#; :F-# ; :FF#; :FS#; :FQ#) s tím nemohu nic měnit, takže pokud znam predem 3znaky ze 4 tak je ošetřena částečně i chybovost. Potřebuju jen v rámci přerušení přijmout celý řetězec, ukončit přerušení, a vrátit se. A pak přijatý řetězec porovnat s aktualnim stavem. Nic víc
Je to vůbec možné?
![Smile :)](./images/smilies/icon_smile.gif)
- ZdenekHQ
- Administrátor
- Příspěvky: 25593
- Registrován: 21 črc 2006, 02:00
- Bydliště: skoro Brno
- Kontaktovat uživatele:
V rámci přerušení se jen pasivně přijímají znaky do bufferu, hlavní program dělá zbytek. Dokud není v rámci určitého časového rámce přijat celý smysluplný příkaz, hlavní program provádí poslední příkaz a buffer se maže.
Pokud jde o reverzaci, pokud přichází protichůdně požadavky v rámci brždění, hlavní program prostě jen brzdí a čeká, to je věc jednoho stavového bitu.
Vážně se to hůř popisuje než programuje.
Pokud jde o reverzaci, pokud přichází protichůdně požadavky v rámci brždění, hlavní program prostě jen brzdí a čeká, to je věc jednoho stavového bitu.
Vážně se to hůř popisuje než programuje.
Pro moje oslovení klidně použijte jméno Zdeněk
Správně navržené zapojení je jako recept na dobré jídlo.
Můžete vynechat půlku ingrediencí, nebo přidat jiné,
ale jste si jistí, že vám to bude chutnat[?]
Správně navržené zapojení je jako recept na dobré jídlo.
Můžete vynechat půlku ingrediencí, nebo přidat jiné,
ale jste si jistí, že vám to bude chutnat[?]
- Panda38
- Příspěvky: 713
- Registrován: 21 lis 2012, 01:00
- Bydliště: Most, Praha, Lanžhot
- Kontaktovat uživatele:
Pokud je takhle přesně daný rámec paketů a liší se jen commandem, tak pak je lepší jen počítat bajty a vyhodnocovat strukturu paketu už v přerušení (v hlavní smyčce rozlišovat jen command):
Kód: Vybrat vše
char Cmd;
bool CmdOK = False;
char PktLen = 0;
...v přerušení (mimo jiné):
char znak = UDR;
switch (PktLen)
{
case 0:
if (znak == ':') PktLen = 1;
break;
case 1:
PktLen = (znak == 'F') ? 2 : 0;
break;
case 2:
Cmd = znak;
PktLen = 3;
break;
default:
PktLen = 0;
CmdOK = (znak == '#');
}
...v hlavní smyčce:
if (CmdOK)
{
CmdOK = False;
switch (Cmd)
{
case ....