jednoduchý kód na PIC

arduino, teensy, atmega, pic a jine (software, hardware)
Onder
Příspěvky: 123
Registrován: 6. 4. 2021, 2:14

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
(2.69 KiB) Staženo 68 x
PBr
Příspěvky: 941
Registrován: 16. 6. 2007, 8:21
Bydliště: Slovensky Grob
Kontaktovat uživatele:

9. 11. 2023, 10:58

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
dracekvo
Příspěvky: 72
Registrován: 17. 3. 2015, 6:04

10. 11. 2023, 5:22

A jak to potřebuješ přesně? Ty vnitřní oscilátory stojí za starou belu.
Onder
Příspěvky: 123
Registrován: 6. 4. 2021, 2:14

10. 11. 2023, 7:09

Nene oscilátor je externí, 20MHz. V tom kódu to není třeba zohlednit, protože v PICu je bootloaderu a nahrává se do něj přes usb-ttl.

Takže výsledná frekvence je 20/4 ... 5Mhz a to je děličkou nastavenou na 256 bit ještě vydeleno
miv
Příspěvky: 777
Registrován: 17. 9. 2019, 11:55

10. 11. 2023, 8:46

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
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, nastavit
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.
Uživatelský avatar
Thomeeque
Příspěvky: 8913
Registrován: 30. 1. 2012, 10:20
Bydliště: Mimo ČR

10. 11. 2023, 11:36

Buď to máš sofistikovanější, než si myslím, nebo používáš v ifech špatný oprátor pro logické AND, správně má být &&, nikoliv &.
mimooborová naplavenina • kolowratský zázrak™ • NPS • GCU • HirthCalc • ncDP.ino
Uživatelský avatar
Radhard
Příspěvky: 288
Registrován: 1. 7. 2020, 10:19
Bydliště: Praha
Kontaktovat uživatele:

10. 11. 2023, 11:41

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.
miv
Příspěvky: 777
Registrován: 17. 9. 2019, 11:55

11. 11. 2023, 4:34

Thomeeque píše: 10. 11. 2023, 11:36 Buď to máš sofistikovanější, než si myslím, nebo používáš v ifech špatný oprátor pro logické AND, správně má být &&, nikoliv &.
V tomto případě je to asi jedno, ty subvýrazy se vyhodnotí jako 0x00 nebo 0xff. Ale obecně máš samozřejmě pravdu.
Onder
Příspěvky: 123
Registrován: 6. 4. 2021, 2:14

15. 11. 2023, 5:53

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...
atlan
Příspěvky: 3346
Registrován: 7. 2. 2011, 9:12

15. 11. 2023, 7:44

MCLR pin mas ako zapojeny
gaminn
Příspěvky: 881
Registrován: 23. 6. 2007, 8:26

15. 11. 2023, 12:09

Nevím jak PIC, ale většina moderních MCU má funkci zachycení času mezi dvěma událostmi na pinu zadrátovanou přímo v HW. Jmenuje se to "input capture".
miv
Příspěvky: 777
Registrován: 17. 9. 2019, 11:55

15. 11. 2023, 5:47

Onder píše: 15. 11. 2023, 5:53 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".
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.
Uživatelský avatar
Radhard
Příspěvky: 288
Registrován: 1. 7. 2020, 10:19
Bydliště: Praha
Kontaktovat uživatele:

15. 11. 2023, 7:46

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.
miv
Příspěvky: 777
Registrován: 17. 9. 2019, 11:55

15. 11. 2023, 9:55

Radhard píše: 15. 11. 2023, 7:46 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í).
Uživatelský avatar
Radhard
Příspěvky: 288
Registrován: 1. 7. 2020, 10:19
Bydliště: Praha
Kontaktovat uživatele:

15. 11. 2023, 11:28

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.
Odpovědět

Zpět na „MCU“