jednoduchý kód na PIC
Zdravím,
začínám se učit s programováním PICu. Je to něco jiného než arduino, protože je potřeba nastudovat datasheet a umět nastavovat registry.
Mám jednoduchou úlohu, chci jen změřit čas mezi dvěma impulzy, které příjdou na stejný pin.
Představa je taková, že první pulz vyvolá přerušení a zapne se časovač. Při druhém pulzu se znova vyvolá přerušení a přečte se hodnota kolikrát se přetekl časovač a jaká je aktuální hodnota v časovači. Aktuálně to programuju v mikro c pro, protože v mplabu x mi nešel nastavit uart.
Je ten zápis, který je v příloze někde vyloženě špatně?,.. protože (ne)překvapivě nefunguje
díky
začínám se učit s programováním PICu. Je to něco jiného než arduino, protože je potřeba nastudovat datasheet a umět nastavovat registry.
Mám jednoduchou úlohu, chci jen změřit čas mezi dvěma impulzy, které příjdou na stejný pin.
Představa je taková, že první pulz vyvolá přerušení a zapne se časovač. Při druhém pulzu se znova vyvolá přerušení a přečte se hodnota kolikrát se přetekl časovač a jaká je aktuální hodnota v časovači. Aktuálně to programuju v mikro c pro, protože v mplabu x mi nešel nastavit uart.
Je ten zápis, který je v příloze někde vyloženě špatně?,.. protože (ne)překvapivě nefunguje
díky
Ahoj, PIC nepoznam, ale algoritmicky na prvy pohlad je to OK, C-ckovo uz nie nutne.
1. Mne sa osobne nepaci kombinovana funkcia prerusenia, kde sa zistuje co to vyvolalo. Inak ako sa vie, ze funkcia interrupt() sa vola na dane prerusenia? Mozno to je nejaka vlastnost daneho kompilatora?
2. Nemaju premenne snimac a preteceni_start rovnaky vyznam? Mozno sa mylim, ale pride mi to tak.
3. Pozor na globalne premenne, ked sa kompilator rozhodne ich strcit do registra namiesto RAM tak bude problem a nebude to fungovat. Premenne pouzivane v preruseniach mali by byt volatile (alebo ekvivalent, ktory ich da do RAM). Zazil som to a bolo peklo zistit pricinu. Ale toto tiez zalezi na kompilatore...tot mojich 5 centov
1. Mne sa osobne nepaci kombinovana funkcia prerusenia, kde sa zistuje co to vyvolalo. Inak ako sa vie, ze funkcia interrupt() sa vola na dane prerusenia? Mozno to je nejaka vlastnost daneho kompilatora?
2. Nemaju premenne snimac a preteceni_start rovnaky vyznam? Mozno sa mylim, ale pride mi to tak.
3. Pozor na globalne premenne, ked sa kompilator rozhodne ich strcit do registra namiesto RAM tak bude problem a nebude to fungovat. Premenne pouzivane v preruseniach mali by byt volatile (alebo ekvivalent, ktory ich da do RAM). Zazil som to a bolo peklo zistit pricinu. Ale toto tiez zalezi na kompilatore...tot mojich 5 centov
Ten zápis je dost špatně. V main rutině čteš proměnné, které se ti mohou v interrupt rutině měnit. Tak to nelze dělat. Je třeba v interrupt rutině zkopírovat pracovní proměnné do čtecích, nastavitOnder píše: ↑9. 11. 2023, 9:04 Zdravím,
začínám se učit s programováním PICu. Je to něco jiného než arduino, protože je potřeba nastudovat datasheet a umět nastavovat registry.
Mám jednoduchou úlohu, chci jen změřit čas mezi dvěma impulzy, které příjdou na stejný pin.
Představa je taková, že první pulz vyvolá přerušení a zapne se časovač. Při druhém pulzu se znova vyvolá přerušení a přečte se hodnota kolikrát se přetekl časovač a jaká je aktuální hodnota v časovači. Aktuálně to programuju v mikro c pro, protože v mplabu x mi nešel nastavit uart.
Je ten zápis, který je v příloze někde vyloženě špatně?,.. protože (ne)překvapivě nefunguje
díky
citaniPulzu.txt
proměnnou existuje_vysledek na true a dokud ta proměnná není shozena, již ty čtecí proměnné v interruptu neměnit. Eventuelně před výpočtem v mainu zakázat před výpočtem přerušení a pak je zase povolit.
Také mi přišlo podezřelé toto:
if (INTCON.b2 == 1 & preteceni_start == 1) {
timer_count++;
INTCON.B2 = 0; // nema to byt INTCON.b2 = 0 ?? - dany procesor neznam, ale chapu to jako mazani flagu preruseni INTCON.b2
}
Dale je mi divne, ze se promenna preteceni_start nikde nemaze.
Onder píše: ↑9. 11. 2023, 9:04 Zdravím,
začínám se učit s programováním PICu. Je to něco jiného než arduino, protože je potřeba nastudovat datasheet a umět nastavovat registry.
Mám jednoduchou úlohu, chci jen změřit čas mezi dvěma impulzy, které příjdou na stejný pin.
Představa je taková, že první pulz vyvolá přerušení a zapne se časovač. Při druhém pulzu se znova vyvolá přerušení a přečte se hodnota kolikrát se přetekl časovač a jaká je aktuální hodnota v časovači. Aktuálně to programuju v mikro c pro, protože v mplabu x mi nešel nastavit uart.
Je ten zápis, který je v příloze někde vyloženě špatně?,.. protože (ne)překvapivě nefunguje
díky
citaniPulzu.txt
Už si do tohodle procesoru někdy napsal program kterej chodí ?
Pokud ne, začni blikáním ledkou
A pak to začni komplikovat.
Zatím díky všem za rady, pořád si s tím hraju. Nějaký postup už tam je ale pořád nefunkční.
Můžu se zeptat, jak je myšlena tato věta od miv:
"Je třeba v interrupt rutině zkopírovat pracovní proměnné do čtecích".
Snažím se teď nějak postupně zkoušet co se jak bude chovat jednotlivě. Ale když přidám třeba 2 podmínky v interruptu, 1. Pro externí, 2. Timer, tak se to začne chovat divně (podle dokumentace vy se to tak mělo delat, že tam jsou if (přerušení externí), if(timer)...)
Kód se třeba chová jinak, kdyz mcu vyresetuju a po sekundě zmáčknu tlačítko, vs když mcu vyresetuju a tlačítko zmáčknu po 10s.
Myslel jsem že když se nahraje kód, tak mcu jede postupně, podívá se na main načte ty funkce, inicializace atd a pak skočí do while. Když vznikne přerušení, tak kód skočí zpět while přesně tam kde skončil. Občas mi připadá jak by kód začal zase od mainu...
Můžu se zeptat, jak je myšlena tato věta od miv:
"Je třeba v interrupt rutině zkopírovat pracovní proměnné do čtecích".
Snažím se teď nějak postupně zkoušet co se jak bude chovat jednotlivě. Ale když přidám třeba 2 podmínky v interruptu, 1. Pro externí, 2. Timer, tak se to začne chovat divně (podle dokumentace vy se to tak mělo delat, že tam jsou if (přerušení externí), if(timer)...)
Kód se třeba chová jinak, kdyz mcu vyresetuju a po sekundě zmáčknu tlačítko, vs když mcu vyresetuju a tlačítko zmáčknu po 10s.
Myslel jsem že když se nahraje kód, tak mcu jede postupně, podívá se na main načte ty funkce, inicializace atd a pak skočí do while. Když vznikne přerušení, tak kód skočí zpět while přesně tam kde skončil. Občas mi připadá jak by kód začal zase od mainu...
Jde v podstatě o toto:
V mainu máš výpočet, který pracuje s proměnnými, které jsou nastavovány v přerušení. Ten výpočet je samozřejmě přeložen jako posloupnost instrukcí procesoru. Přerušení může nastat po každé instrukci. Pokud se tak stane uprostřed toho výpočtu a přerušení ty proměnné změní, pak je výsledek nesmyslný. Pravděpodobnost tohoto jevu je poměrně značná.
Jednoduchý příklad:
Dejme tomu, že interrupt bude počítat počet pulzů z nějakého vstupu a také měří čas. Z toho se v main rutině pak bude počítat průměrná délka pulzu.
IRQ rutina bude používat pracovní proměnné N_IRQ a T_IRQ, main bude pro výpočet používat N, T.
Jako signalizace platnosti N,T bude sloužit boolovská proměnná data_pripravena.
Jako semafor pro možnost měnit N_IRQ a T_IRQ poslouží proměnná muze_se_merit
IRQ rutina (symbolicky)
if (muze_se_merit==true) // může se měřit
{
Změna N_IRQ a T_IRQ dle algoritmu měření
if (měření hotovo) // dle algoritmu
{
muze_se_merit = false;
}
}
if (muze_se_merit == false)
{
if (!data_pripravena) // prepisujeme jen kdyz jiz byla predchozi data prectena
{
// kopie do ctecich dat pro main
N=N_IRQ;
T=T_IRQ;
// signalizace platnosti ctecich dat
data_pripravena = true;
muze_se_merit = true;
}
}
main rutina
if (data_pripravena==true)
{
prace s promennymi N,T;
data_pripravena = false; // signalizace do IRQ, ze se mohou zaznamenat dalsi zmerena data
}
Je vidno, že díky tomu flagu data_pripravena nemuze IRQ rutina zmenit N,T , dokud neni s nimi main rutina hotova. A tyto promenne jsou kozistentni.
Prostě, pokud operace nad proměnou není "atomická" (tj. provede se jednou instrukcí), je třeba proměné zamykat, dělat pracovní kopie a pod.
Nejen nad jednou proměnnou. V jeho případě nad více proměnnými. Pokud mu interrupt změní jen jednu, na kterou při vyhodnocování výrazu ještě nedošlo a přitom tu předchozí již výraz zpracoval, dojde k nekonzistenci. Je prostě potřeba, aby celé vyhodnocení výrazu bylo "atomické". Prostě musí "zamykat". Po pravdě řečeno je nejjednodušší udělat si lock nad boolovskou proměnnou a používat lock jako přístupový semafor. Obvykle ty procesory mívají přímo asemblerovskou instrukci pro tento účel, která je atomická. Ale vždy to lze vyřešit zákazem přerušení, nastavením boolovského flagu a následně povolením přerušení. Je to pro většinu účelů dostatečně rychlé a použití je pak triviální. Pak se nemusí pracovní proměnné kopírovat a vše se zařídí zámkem.
if (lock(&variable))
{
.. operace
unlock(&variable)
}
bool lock(bool* var)
{
disable_interrupts()
if (*var)
{
enable_interrupts();
return false;
}
else
{
*var = true;
enable_interrupts();
return true;
}
}
void unlock(bool *var)
{
*var = false;
}
Pochopitelně je toto řešení použitelné jen tehdy, když se důsledně páruje lock/unlock a v interruptu se testuje přímo lock proměná (tam je nesmysl zakazovat přerušení).
Psal jsem to obecně. Kolik tazatel hodlá používat volatilních proměných mě až tak nezajímá.
Jaká technologie je pro daný účel nejvhodnější musí zvolit programátor například podle toho který proces data produkuje a který konzumuje.
S tím zamykáním to není tak úplně jednoduché pokud smí zamykat tu samou proměnou/prostředek více než jeden proces. PIC (aspoň 16Fxx) nemá operaci kterou by současně otestoval proměnou a podle výsledku ji změnil. Jinak to problém není samozřejmě.
Tahle konkrétní úloha je řešitelná trapným stavovým automatem stojícím na bitových proměných a zamykat netřeba nic.
Jaká technologie je pro daný účel nejvhodnější musí zvolit programátor například podle toho který proces data produkuje a který konzumuje.
S tím zamykáním to není tak úplně jednoduché pokud smí zamykat tu samou proměnou/prostředek více než jeden proces. PIC (aspoň 16Fxx) nemá operaci kterou by současně otestoval proměnou a podle výsledku ji změnil. Jinak to problém není samozřejmě.
Tahle konkrétní úloha je řešitelná trapným stavovým automatem stojícím na bitových proměných a zamykat netřeba nic.