jednoduchý kód na PIC
Tak, ani nebudu psát kolik jsem tomu věnoval času dneska
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 ...
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);
}
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 ...
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);
}
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.
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.
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
Ale jinak nejake mouchy to ma, kdyz rychle zmacknu tlacitko za sebou, tak to vypise blbost nebo se to cele nejak sekne
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
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.
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
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íš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.
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í.miv píše: ↑20. 11. 2023, 6:41Gratuluji 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íš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.
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;
}
je to tam trochu nepřehledné, tak tu dám obrázek jak ten interrupt vypadá přehledněji
Ale opět mi připadá, že pokud to tlačítko zmáčknu za sebou moc rychle, tak se to nějak celé zasekne.
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. 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.
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í.
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í.
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.
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
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
To tam má taky, jen si toho nevšiml a dělá to postaru
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
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ímPipik píše: ↑21. 11. 2023, 1:05To tam má taky, jen si toho nevšiml a dělá to postaru
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ě
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
Funny - nikdo si toho nevšiml, ani já ne
Každopádně jsi to pak zapojil už dobře
Ten blbec, kterej to vyrobil, pač mu zapoměli říct že to nejde vyrobit