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

16. 11. 2023, 7:25

Tak, ani nebudu psát kolik jsem tomu věnoval času dneska :roll:

Předem hodně dík za rady, hlavně od miv. Zkusil jsem si z tvojí rady něco vzít a poskládat (podle sebe) kód, ale moc mi nefungoval, tak jsem to pak od Tebe viceméně zkopíroval 8) ...

Aktuální stav je takový, že to možná funguje tak jak má, připadá mi, že se mi párkrát stalo, že když jsem zmáčkl tlačítko, tak se program sekl a už se nic nevypisovalo a ledka se neměnila. Ještě musím nějak vymyslet, jak udělat, aby to nevypisovalo od prvního zmáčknutí, ale až od 2. protože absolutně prvotní stisk by neměl vypisovat čas.

#define LED PORTB.B1

unsigned char data_pripravena;
unsigned int citac;
unsigned char muzes_ukoncit;
volatile int M_citac;
volatile int M_casovac;
volatile unsigned char mereni_hotovo;
volatile unsigned char existuje_vysledek;
volatile float vysledek;
volatile unsigned char muze_se_merit;

char txt[7];

void Init(void);

void interrupt () {

if(muze_se_merit == 1)
{
citac++;
if(INTCON.B1 == 1)
{
LED = !LED;
muze_se_merit = 0;
}
}

if(muze_se_merit == 0)
{
if(data_pripravena == 0)
{
M_citac = citac; //prirazeni hodnoty citace k M_citac
M_casovac = TMR0; //prirazeni hodnoty k M_casovac
muze_se_merit = 1;
data_pripravena = 1;
citac = 0;
TMR0 = 0;
//INTCON.b1 = 0;
}
}

INTCON.b1 = 0; //vymazani flagu pro preruseni externi
INTCON.b2 = 0; //vymazani flagu pro preruseni preteceni casovace

}

void main() {

Init();
LED = 0;
citac = 0;
muze_se_merit = 1;
data_pripravena = 0;

while(1){

if(data_pripravena) {
vysledek = (0.0131*M_citac) + (M_casovac * (4/78125)) ;
FloatToStr(vysledek, txt);
UART1_Write_Text(txt);
data_pripravena = 0;
}

}

}

void Init(void){

//PUVODNI NASTAVENI

TRISB.B0 = 1; //port 0 registru B je input
TRISB.B1 = 0; //port 1 registru B je output

//nastaveni registru pro preruseni INTCON
INTCON.B7 = 1; //GIE = 1; dovoleni externiho preruseni
INTCON.B6 = 1; //PEIE = 1; dovoleni preruseni of periferii
INTCON.B5 = 1; //TMR0IE = 1; preteceni casovace vyhodi preruseni
INTCON.B4 = 1; //INTE = 1; povoleni externiho preruseni na pinu RB0

//nastaveni registru OPTION_reg
//Fosc = 20MHz, Fosc/4=5MHz,
OPTION_REG.b6 = 1; //preruseni bude aktivni pri high na RB0, 0 - kdyz je low

OPTION_REG.b5 = 0; //casovani je pres vnitrni oscilator 20MHz,
OPTION_REG.b3 = 0; //delicka je prirazena Timeru0

//DELICKA
OPTION_REG.b2 = 1; //nastaveni delicky na 256 ... perioda 5.12x(10ˇ-5)
OPTION_REG.b1 = 1; //delicka na 256
OPTION_REG.b0 = 1; //delicka na 256

TMR0 = 0; // neni potreba nastavit pocatecni hodnotu casovace

UART1_Init(9600);
}
atlan
Příspěvky: 3346
Registrován: 7. 2. 2011, 9:12

17. 11. 2023, 9:07

Myslis ze je toto dobre? INTCON.b1 = 0; //vymazani flagu pro preruseni externi
INTCON.b2 = 0; //vymazani flagu pro preruseni preteceni casovace

Mazes priznaky mimo obsluhy ich vyhodnotenia.
Ked zistis ze bol priznak nastaveny, urob co treba a na konci vyhodnotenia ho zmaz.

Hardver vyzera ako? Dufam ze pull up je, a k tlacitku je na prasaka paralelnw 100n.
Onder
Příspěvky: 123
Registrován: 6. 4. 2021, 2:14

17. 11. 2023, 9:27

Zkusil jsem nejake kombinace umisteni tech vymazani flagu, ale nefunguje to tak jak ten prvotni. Mozna to myslis tak, ze bych to musel cele upravit, neco mi taky rika ze to tam takhle nema byt ale funguje to.... Hardware je pull down a nejakych 70n.

Ale jinak nejake mouchy to ma, kdyz rychle zmacknu tlacitko za sebou, tak to vypise blbost nebo se to cele nejak sekne :|
Modros
Příspěvky: 1680
Registrován: 31. 3. 2019, 7:58

18. 11. 2023, 12:36

Programování moc nerozumím, nicméně mě poslední dobou pomáhá umělá inteligence....pro srandu sem mu hodil tvuj kod....za výsledek neručim, vím že pěkně lže :D




Váš kód vypadá jako program pro mikrokontrolér v jazyce C, který měří nějaký časový interval a přenáší výsledek přes UART. Zdá se, že je založen na přerušení od externího signálu.

Zde jsou některé připomínky a opravy:

Nulování proměnných: V main() funkci byste měli na začátku nulovat všechny proměnné, abyste se ujistili, že program začíná v definovaném stavu.
c
Copy code
void main() {
Init();
LED = 0;
citac = 0;
muze_se_merit = 1;
data_pripravena = 0;

while(1) {
if(data_pripravena) {
vysledek = (0.0131 * M_citac) + (M_casovac * (4.0 / 78125.0)); // Oprava: desetinné číslo
FloatToStr(vysledek, txt);
UART1_Write_Text(txt);
data_pripravena = 0;
}
}
}
Typy proměnných: Při provádění aritmetických operací s desetinnými čísly by měly být použity desetinné typy dat. V tomto případě jsem změnil int na float pro proměnné, které obsahují desetinné číslo.
c
Copy code
volatile float vysledek;
volatile float M_casovac;
Nastavení DELICKY: V kódu je nastavena delička na 256. Můžete zkontrolovat, zda je to správná hodnota pro váš účel, nebo přizpůsobit podle potřeby.

Typ deličky: V kódu je nastavena delička na 256, což odpovídá nastavení OPTION_REG.b2 = 1; OPTION_REG.b1 = 1; OPTION_REG.b0 = 1;. To vytvoří deličku na 256. Pokud potřebujete deličku 256, pak je to v pořádku.

Ošetření desetinných čísel: Při použití desetinných čísel ve výrazech bych doporučil být opatrný při provádění operací, abyste se vyhnuli ztrátě přesnosti. Jsem si vědom, že v mnoha případech mohou být desetinná čísla nepřesná na mikrokontrolérech, ale to závisí na konkrétním hardware a použité knihovně.

Mějte na paměti, že správná funkčnost závisí na konkrétním zařízení, pro které je tento kód určen, a na specifických požadavcích vašeho projektu.
Masso, stroje všemožný, autoservis, amatérské závody Nissan GTR
miv
Příspěvky: 777
Registrován: 17. 9. 2019, 11:55

20. 11. 2023, 6:41

Onder píše: 16. 11. 2023, 7:25
Aktuální stav je takový, že to možná funguje tak jak má, připadá mi, že se mi párkrát stalo, že když jsem zmáčkl tlačítko, tak se program sekl a už se nic nevypisovalo a ledka se neměnila. Ještě musím nějak vymyslet, jak udělat, aby to nevypisovalo od prvního zmáčknutí, ale až od 2. protože absolutně prvotní stisk by neměl vypisovat čas.
Gratuluji k prvním úspěchům. Za sebe bych doporučil začít věcmi jednoduchými a až pak zesložiťovat. Takže například IRQ rutiny používat nejdříve "cvičně" pouze samostatně a až po jejich zvládnutí je kombinovat a podobně. Dále bych doporučil nastudovat co to je stavový stroj (nebo se tomu také říká stavový automat), jak se používá a zkusit si nějaký naprogramovat. To je totiž extrémně užitečný nástroj pro situace, kdy se ti na pozadí mění stav systému (třeba v přerušeních) a ty potřebuješ volat několik nesouvisejícíh úloh, kdy každá čeká na nějaký stav systému a přitom se tam program nesmí zastavit. Je to takový multitasking bez operačního systému. I ten tvůj problém se dá snadno řešit pomocí stavového stroje.
Onder
Příspěvky: 123
Registrován: 6. 4. 2021, 2:14

20. 11. 2023, 8:39

miv píše: 20. 11. 2023, 6:41
Onder píše: 16. 11. 2023, 7:25
Aktuální stav je takový, že to možná funguje tak jak má, připadá mi, že se mi párkrát stalo, že když jsem zmáčkl tlačítko, tak se program sekl a už se nic nevypisovalo a ledka se neměnila. Ještě musím nějak vymyslet, jak udělat, aby to nevypisovalo od prvního zmáčknutí, ale až od 2. protože absolutně prvotní stisk by neměl vypisovat čas.
Gratuluji k prvním úspěchům. Za sebe bych doporučil začít věcmi jednoduchými a až pak zesložiťovat. Takže například IRQ rutiny používat nejdříve "cvičně" pouze samostatně a až po jejich zvládnutí je kombinovat a podobně. Dále bych doporučil nastudovat co to je stavový stroj (nebo se tomu také říká stavový automat), jak se používá a zkusit si nějaký naprogramovat. To je totiž extrémně užitečný nástroj pro situace, kdy se ti na pozadí mění stav systému (třeba v přerušeních) a ty potřebuješ volat několik nesouvisejícíh úloh, kdy každá čeká na nějaký stav systému a přitom se tam program nesmí zastavit. Je to takový multitasking bez operačního systému. I ten tvůj problém se dá snadno řešit pomocí stavového stroje.
Už jsem Tě předběhl :) Přesně ty rady typu to si najdi, nebo aspoň napsat název něčeho co nevím že existuje mi stačí. Stavový automat jsem asi viděl poprvé, na internetu je k tomu docela dost a ta logika jde implementovat do programování.

Možná to ještě není úplně tutovka, ale tento kód funguje lépe. Hlavně jsem s tím dokázal vyřešit zapínání a vypínaní měření.... : časovač neustále počítá, takže si v přerušení může jet jak mu je libo ale při každém flagu přihodí k proměnné preteceni. Když se zmáčkne poprvé tlačítko, tak se preteceni vynuluje. A časovač si opět může počítat, ale od nuly. Když se zmáčkne podruhé tlačítko, vypíše se aktuální hodnota preteceni do (mainovské) proměnné a povolí se výpočet z existuje_vysledek.

#define LED PORTB.B1
unsigned short preteceni_start;
unsigned short existuje_vysledek;
float cas;
volatile unsigned int preteceni;
volatile unsigned int hodnota_preteceni;
volatile unsigned char hodnota_TMR;
static enum stavy{
start,
stop} stav;
float rychlost;


void Init(void);

// co se stane, kdyz nastane preruseni na pinu RB0

void interrupt(){

if(INTCON.B1 == 1)
{

switch(stav){
case start:
{
preteceni = 0;
TMR0 = 0;
stav = stop;
LED = 1;
break;
}
case stop:
{
hodnota_preteceni = preteceni;
hodnota_TMR = TMR0;
stav = start;
LED = 0;
existuje_vysledek = 1;
break;
}
default:
{
break;
}
}

INTCON.b1 = 0;
}

if(INTCON.B2 == 1)
{
preteceni++;
INTCON.b2 = 0;
}

}


void Init(void);
char txt[15];

void main() {

Init(); // vlozeni inicializacniho nastaveni (nahrani nastaveni registru)

//Delay_ms(100); //mozna vyzkouset

LED = 0;
preteceni = 0;
stav = start;
existuje_vysledek = 0;

while(1)
{


if(existuje_vysledek){

//Delay_ms(100); //MOZNA NASTAVIT
cas = (0.013*hodnota_preteceni) + (hodnota_TMR * (4/78125)) ;
rychlost = 0.5/cas;
FloatToStr(rychlost, txt);
UART1_Write_Text(txt);
existuje_vysledek = 0;

}



}
}


void Init(void){

TRISB.b0 = 1; //port 0 registru B je input
TRISB.b1 = 0;

//nastaveni registru pro preruseni INTCON
INTCON.B7 = 1; //GIE = 1; dovoleni externiho preruseni
INTCON.B6 = 1; //PEIE = 1; dovoleni preruseni of periferii
INTCON.B5 = 1; //TMR0IE = 1; preteceni casovace vyhodi preruseni
INTCON.B4 = 1; //INTE = 1; povoleni externiho preruseni na pinu RB0
//INTCON.B1 = 0; //****** prvotni nastaveni preruseni RB0 = 0 OPRAVA!

//nastaveni registru PIE1
//PIE1.B0 = 1; //Enabluje/povoluje TMR1IE - preruseni od casovace

//nastaveni registru PIR1
//PIR1.B0 = 0; //Vynulovani priznaku preruseni casovace TMR1


//nastaveni registru OPTION_reg
//Fosc = 20MHz, Fosc/4=5MHz,
OPTION_REG.b6 = 1; //preruseni bude aktivni pri high na RB0, 0 - kdyz je low
OPTION_REG.b5 = 0; //casovani je pres vnitrni oscilator 20MHz
OPTION_REG.b3 = 0; //delicka je prirazena Timeru0

OPTION_REG.b2 = 1; //nastaveni delicky na 256 ... perioda 5.12x(10ˇ-5)
OPTION_REG.b1 = 1; //delicka
OPTION_REG.b0 = 1; //delicka na 256

//TMR0 = 0; // neni potreba nastavit pocatecni hodnotu casovace

// nastaveni prvotniho stavu snimace

UART1_Init(9600);

return;
}
Onder
Příspěvky: 123
Registrován: 6. 4. 2021, 2:14

20. 11. 2023, 8:42

je to tam trochu nepřehledné, tak tu dám obrázek jak ten interrupt vypadá přehledněji
Snímek obrazovky 2023-11-20 214204.png
btw. na internetu jsem se díval že v ISR by se switch neměl používat, že to zpomaluje,.. toto jsem udělal jak mě to napadlo a funguje to.

Ale opět mi připadá, že pokud to tlačítko zmáčknu za sebou moc rychle, tak se to nějak celé zasekne.
miv
Příspěvky: 777
Registrován: 17. 9. 2019, 11:55

20. 11. 2023, 9:01

Onder píše: 20. 11. 2023, 8:42
btw. na internetu jsem se díval že v ISR by se switch neměl používat, že to zpomaluje,.. toto jsem udělal jak mě to napadlo a funguje to.

Ale opět mi připadá, že pokud to tlačítko zmáčknu za sebou moc rychle, tak se to nějak celé zasekne.
Výborně, začíná to vypadat jako program. :D O těch switch to sice platí, ale až při mnohem vyšších nárocích na rychlost. Však také některé překladače pro některé procesory mají switch s flagem pro přímý skok, kdy case hodnoty jsou v násobcích adres, takže se to pak překládá přímo skokovou tabulkou (viz např. MSP430 od texasů). Nezkoumal jsem tvůj kód z pohledu obsluhy tlačítka - ten tvůj procesor neznám. Pokud máš tlačítko obsluhované v IRQ, pak takové chyby často vznikají neobsloužením flagu příslušného přerušení. Tady pomůže jen důkladné studium daného procesoru z hlediska jeho IRQ systému.
Uživatelský avatar
Radhard
Příspěvky: 288
Registrován: 1. 7. 2020, 10:19
Bydliště: Praha
Kontaktovat uživatele:

20. 11. 2023, 10:39

Jak jsou které konstrukce v C náročné na procesorový čas určuje instrukční soubor MCU/CPU.

Tyhle malé 8bity toho moc neumí - stačí použít násobení ve float32 , předání parametru do funkce pomocí pointeru nebo rozsáhlý switch/case a končíš.

Takže pokud neznáš instrukce toho procesoru a jeho možnosti, je třeba programovat dost konzervativně. Někdy je taky jediná cesta časově kritické sekce napsat v ASM a zbytek v C.

Taky je potřeba dávat pozor na zásobník - speciálně PIC procesory - nenapsal jsi kterej konkrétní typ programuješ, takže nemohu být víc konkrétní.
atlan
Příspěvky: 3346
Registrován: 7. 2. 2011, 9:12

21. 11. 2023, 9:14

Paralelne k tlacitku mas kondik 47 alebo 100n
Onder
Příspěvky: 123
Registrován: 6. 4. 2021, 2:14

21. 11. 2023, 11:24

zapojení je takto, teď jsem to udělal narychlo, protože musím dělat jiné věci. Každopádně, je to školní projekt, a dělám to už na pospájené desce. V tom picu je bootloader a nahrává se tam teda přes převodník USB-ttl.
schema.png
btw ještě tam je ledka zapojená na pin RB1, hned vedle RB0.
A teď si ani nejsem jistý jestli ten kondenzátor mám zapojený takto nebo na +5V :?
Uživatelský avatar
Pipik
Příspěvky: 868
Registrován: 9. 11. 2016, 3:32
Bydliště: České Budějovice

21. 11. 2023, 1:05

gaminn píše: 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".
To tam má taky, jen si toho nevšiml a dělá to postaru :D
Každopádně úplně s ním nesouhlasím ohledně té složitosti co psal v úvodu - dneska už je ten software tak vychytanej, že napsat něco takovýhleho je záležitost asi tak na deset minut spíš víc klikání než psaní. Prostě si nastavit čítač na požadovanou časovou jednotku (frekvenci), programově ho jen jedním příkazem zapnout, druhý čítač nastavit aby čítal přetečení prvního čítače (pokud je frekvence nebo interval signálu větší), a pokud dojde k interuptu od tlačítka (rovněž víc klikání než psaní), tak si prostě přečíst hodnotu druhého čítače a oba vynulovat.
Toť asi teorie cesty, kterou bych šel já :)

...ale nestudoval jsem jeho program, třeba to tak má :)

ps.: Ne, po přerušení se program opravdu vrací do bodu odkud přišel. ...pokud jsi mu nepřepsal návratovou adresu, samozřejmě :)
Ten blbec, kterej to vyrobil, pač mu zapoměli říct že to nejde vyrobit :wink:
Onder
Příspěvky: 123
Registrován: 6. 4. 2021, 2:14

21. 11. 2023, 9:25

Pipik píše: 21. 11. 2023, 1:05
gaminn píše: 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".
To tam má taky, jen si toho nevšiml a dělá to postaru :D
Každopádně úplně s ním nesouhlasím ohledně té složitosti co psal v úvodu - dneska už je ten software tak vychytanej, že napsat něco takovýhleho je záležitost asi tak na deset minut spíš víc klikání než psaní. Prostě si nastavit čítač na požadovanou časovou jednotku (frekvenci), programově ho jen jedním příkazem zapnout, druhý čítač nastavit aby čítal přetečení prvního čítače (pokud je frekvence nebo interval signálu větší), a pokud dojde k interuptu od tlačítka (rovněž víc klikání než psaní), tak si prostě přečíst hodnotu druhého čítače a oba vynulovat.
Toť asi teorie cesty, kterou bych šel já :)

...ale nestudoval jsem jeho program, třeba to tak má :)

ps.: Ne, po přerušení se program opravdu vrací do bodu odkud přišel. ...pokud jsi mu nepřepsal návratovou adresu, samozřejmě :)
Já myslel že ty jsi nějaký herec v divadle co má jako koníček cncčka a výrobu hezkých věcí a ty toho umíš mnohem víc jak vidím :lol:
Onder
Příspěvky: 123
Registrován: 6. 4. 2021, 2:14

21. 11. 2023, 9:27

atlan píše: 21. 11. 2023, 9:14 Paralelne k tlacitku mas kondik 47 alebo 100n
Jo tak chyba byla i v mojem zapojení tlačítka, dal jsem to na pull up, kondenzátor jsem přípojil paralelně k zemi a jede to perfektně teď...
Myslel jsem že to tak může být i v pull down, ale ten kondík byl zapojen do země přesně podle toho schématu co jsem posílal víše, takže to byla hloupost
Uživatelský avatar
Pipik
Příspěvky: 868
Registrován: 9. 11. 2016, 3:32
Bydliště: České Budějovice

22. 11. 2023, 10:48

Onder píše: 21. 11. 2023, 9:27 Jo tak chyba byla i v mojem zapojení tlačítka, dal jsem to na pull up, kondenzátor jsem přípojil paralelně k zemi a jede to perfektně teď...
Funny - nikdo si toho nevšiml, ani já ne :lol:
Každopádně jsi to pak zapojil už dobře :)
Ten blbec, kterej to vyrobil, pač mu zapoměli říct že to nejde vyrobit :wink:
Odpovědět

Zpět na „MCU“