Forum » Elektrotehnika in elektronika » interupti in merjenje frekvence v picu
interupti in merjenje frekvence v picu
ql000 ::
Imam senzor (foto tranzistor iz miške), ki mi daje 5V impulze npr. s frekvenco 1kHz. Sedaj me pa zanima kako naj preberem to frevenco v picu, ampak to na tak način, da bo npr. neka rutina pregledela frekvenco in jo zapisala v neko spremenljivko. Eno rešitev sem našel v examplih od PIC C CCS compilerju, samo tist požre vse resurse pa samo na eno sekundo gleda. Sploh nimam ideje kako bi to oštimal.
Brane2 ::
Spelji ta signal na kak primerne pin PIC-a, denimo na vhod internega števca ali ( če tega ni) INT pin ali kaj takega inn uporabi hardver namesto softverja.
On the journey of life, I chose the psycho path.
ql000 ::
mnja sej jaz bi naredu zadevo hardwaresko (CCP in PWM) ampak oba pina, ki sta temu namenjena že nucam za pogon DC motorja. Zdej moram narest čist softwaresko zadevo, samo problem je v tem, k v interuptih pa v timerjih sem pa čist mrzel k nisem rabu še nikol tega delat.
Uporabljam PIC16F876, vem da ima tri externe interupte. Če prav razumem lahko na te pine pripeljem signal. Samo kako zdej timerju povedat (v C-ju seveda ) Da začne npr. gledat signal ko pride flanka gor in pol pogleda naslednjo flanko in mi vrne čas med tema dvema flankama.
Uporabljam PIC16F876, vem da ima tri externe interupte. Če prav razumem lahko na te pine pripeljem signal. Samo kako zdej timerju povedat (v C-ju seveda ) Da začne npr. gledat signal ko pride flanka gor in pol pogleda naslednjo flanko in mi vrne čas med tema dvema flankama.
16F84 ::
Vprašanja nisem najbolj razumel :(. Za merjenje frekvence niti ne rabiš interupta. Uporabi TMR0. Kot vir clock-a navedi zunajnji vir na RA4/T0CKI (OPTION_REG,T0CS)Paralelno k pinu daj en drug pin. Glede na frekvenco določi še ustrezen preddelilnik OPTION_REG PS2:PS0
Meritev izvedeš na sledeč način.
-Pin, ki je zvezan na RA4 definiraš kot izhod S tem zablokiraš prihajajoče impulze.
-Obrišeš TMR0
-Pin ki je vezan na RA4 definiraš kot vhod - s tem sprostiš števec
- Točno določen čas ta pin pustiš kot vhod nato ga daš nazaj na izhod.
- S tem si ustavil prihajajoče impulze na TMR0
V koliko (po vsej vrjetnosti) boš uporabil preddelilnik. Le tega ne moreš direktno brati. Torej sedaj dovajaš na TMRO impulze z pinom, ki je izhod dokler se števec "ne premakne" ter le te šteješ. Na tak način boš dobil vrednost v preddelilniku.
lp
Silvo
Meritev izvedeš na sledeč način.
-Pin, ki je zvezan na RA4 definiraš kot izhod S tem zablokiraš prihajajoče impulze.
-Obrišeš TMR0
-Pin ki je vezan na RA4 definiraš kot vhod - s tem sprostiš števec
- Točno določen čas ta pin pustiš kot vhod nato ga daš nazaj na izhod.
- S tem si ustavil prihajajoče impulze na TMR0
V koliko (po vsej vrjetnosti) boš uporabil preddelilnik. Le tega ne moreš direktno brati. Torej sedaj dovajaš na TMRO impulze z pinom, ki je izhod dokler se števec "ne premakne" ter le te šteješ. Na tak način boš dobil vrednost v preddelilniku.
lp
Silvo
Highlag ::
Drug način je "brute force" metoda. Ko na izbrani vhod pride impulz, povečaš števec za 1, števec povečuješ z zanko v kateri v vsakem krogu preverjaš stanje na izbranem vhodu. V števcu bo potem številka, ki je odvisna od frekvence na kateri teče PIC. Veš koliko ciklov ure preteče, da števec poveča za 1. In če res rabiš čas oziroma frekvenco impulzov to lahko izračunaš iz vrednosti števca ter frekvence procesirja.
Never trust a computer you can't throw out a window
ql000 ::
OK, sej sem res postavu vprašanja malo zmedeno, predvsem zaradi tega, ker sploh nisem vedel, kako se lotit zadeve. Zdej sta mi dala par idej. Sedaj me pa samo še zanima kako "povezati" neko spremenljivko s timerjem, da bo ob overflowu povečal npr. vrednost te spremenljivke za 1. Ta zadeva meni ni jasna . Mnja, pa koda mora bit v C-ju. En kolega, ki vse te scene dela v assemblerju mi skozi teži nauč "se assembler, nauč se assembler" sam meni zadeva tako smrdi.
Highlag ::
Nauči se Assembler
Join the assembler side! You know it's in you!
Sploh ni tako zakomplicirano. Imaš samo cca 32 ukazov.
Join the assembler side! You know it's in you!
Sploh ni tako zakomplicirano. Imaš samo cca 32 ukazov.
Never trust a computer you can't throw out a window
Tutankhamun ::
Še nism programiru v C-ju za PICe, ampak če znaš delat z interrupti(prekinitvenimi rutinami), najprej omogočš interrupt za TIMER. Potem pa sam čakaš. Ko se pa sprož interrupt pa samo povečaš spremenljivko.
if(TIMER_INT) //ko timer sproži interrupt
i++; //povečaš spremenljivko
if(TIMER_INT) //ko timer sproži interrupt
i++; //povečaš spremenljivko
neoto ::
Če delaš v C-ju povej kateri prevajalnik uporabljaš!
Namreč CCS C compiler ima eno lepo lastnost: Čarovnika, v katerem nastaviš vse flage, interrupte in delilnike (prikazuje ti celo čas v qs, če vpišeš frekvenco kristala), AD pretvornik, .... Ponavadi prav pride, če se ti ne da računat
Namreč CCS C compiler ima eno lepo lastnost: Čarovnika, v katerem nastaviš vse flage, interrupte in delilnike (prikazuje ti celo čas v qs, če vpišeš frekvenco kristala), AD pretvornik, .... Ponavadi prav pride, če se ti ne da računat
ql000 ::
ja ravno CCS C compiler je. Ma grem probat, pa bom vidu kaj lahko sestavim. Do srede moram nerest PID kontrolo DC-motorja. Rampo mi dela, PID algoritem tudi imam, samo s tem branjem frekvence je veselica! Poročam zvečer!
ql000 ::
To je koda, ki mi prebere po deset pulzov naenkrat. Pulze bere na pinu B7 (PIC16F876). Zadevščina laufa, zdej je samo še iz tega potrebno dobit frekvenco. Probal sem tudi zadevo z interupti, uspelo mi je do te mere, da dobim čase med dvema pritiskoma tipke na tipkovnici, torej pošljem inerupt po rs232, vendar pa koda ne deluje, ko sem probal trigat na pulze. Te interupte moram še malo naštudirat. Zraven prilagam tudi kodo z interupti (je modficirana izvedba iz examplov v CCS C Compilerju). Če ima kater še kake ideje na podlagi teh dveh kod, kar z idejo na plan.
Koda šteje pulze:
koda z interuptom:
Koda šteje pulze:
void main() { int8 counter, pulses; int1 flag1; counter = 0; pulses = 10; flag1 = 0; do { for ( ; ; ) { if (input(B7) == 1 && flag1 == 0) { counter++; flag1 = 1; if (counter == pulses) { break; } } else { if (input(B7) == 0) { flag1 = 0; } } } printf(" Counter: %d\r\n", counter); }while(TRUE); }
koda z interuptom:
#int_rtcc // rtcc == timer0 --> on timer0 overflow void count() { counter++; } void main() { int8 start; int8 time; int1 rtcc_flag; set_timer0(0); setup_timer_0( RTCC_INTERNAL | RTCC_DIV_256 ); enable_interrupts(INT_RTCC); enable_interrupts(GLOBAL); rtcc_flag = 0; for ( ; ; ) { if (input(B7) == 1 && rtcc_flag == 0) { start = counter; rtcc_flag = 1; } else if (input(B7) == 1 && rtcc_flag == 1) { time = counter - start; rtcc_flag = 0; printf(" Time: %u\r\n", time); } } }
Zgodovina sprememb…
- spremenil: ql000 ()
neoto ::
Kaj pa kaj takega? Napisano za 16F876A na 20MHz. Za nižje frekvence je treba pač malo povečati čas za interrupt pri Timerju 2
int32 stevecImpulzev;
int32 stevec100qs;
#int_RTCC
RTCC_isr()
{
stevecImpulzev++;
}
#int_TIMER2
TIMER2_isr()
{
stevec100qs++;
}
void main()
{
int16 frekvenca;
setup_timer_0(RTCC_EXT_L_TO_H|RTCC_DIV_1);
setup_timer_2(T2_DIV_BY_1,30,16);
stevecImpulzev=stevec100qs=0;
enable_interrupts(INT_RTCC);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
while(1)
{
if (stevecImpulzev>1000)
{
frekvenca=stevecImpulzev*10/stevec100qs;
frekvenca*=1000;
stevecImpulzev=0;
stevec100qs=0;
}
// Tukaj delaš pa kaj drugega....
}
}
int32 stevecImpulzev;
int32 stevec100qs;
#int_RTCC
RTCC_isr()
{
stevecImpulzev++;
}
#int_TIMER2
TIMER2_isr()
{
stevec100qs++;
}
void main()
{
int16 frekvenca;
setup_timer_0(RTCC_EXT_L_TO_H|RTCC_DIV_1);
setup_timer_2(T2_DIV_BY_1,30,16);
stevecImpulzev=stevec100qs=0;
enable_interrupts(INT_RTCC);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
while(1)
{
if (stevecImpulzev>1000)
{
frekvenca=stevecImpulzev*10/stevec100qs;
frekvenca*=1000;
stevecImpulzev=0;
stevec100qs=0;
}
// Tukaj delaš pa kaj drugega....
}
}
Zgodovina sprememb…
- spremenil: neoto ()
ql000 ::
Evo, združil sem mojo kodo za merjenje števila pulzov in Neotovo kodo za timer in ni vrag nekaj miga ! Zankrat še ne vem v kakih enotah dobim odgovor s tem se bom sedaj ukvarjal, v glavnem, ko motor obremenim se frekvenca spreminja! Naslednji korak je združitev rampe, merjenje frekvence in PID algoritma.
Evo komplet kode:
Evo komplet kode:
#include <16F876.h> #include <ctype.h> #fuses HS,PUT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,WRT #use delay(clock=20000000) #use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7) #byte PORTB = 6 #define A0 PIN_A0 #define A1 PIN_A1 #define A2 PIN_A2 #define A3 PIN_A3 #define A4 PIN_A4 #define A5 PIN_A5 #define B0 PIN_B0 #define B1 PIN_B1 #define B2 PIN_B2 #define B3 PIN_B3 #define B4 PIN_B4 #define B5 PIN_B5 #define B6 PIN_B6 #define B7 PIN_B7 #define C0 PIN_C0 #define C1 PIN_C1 #define C2 PIN_C2 #define C3 PIN_C3 #define C4 PIN_C4 #define C5 PIN_C5 #define C6 PIN_C6 #define C7 PIN_C7 int16 stevec100qs; #int_rtcc // rtcc == timer0 --> on timer0 overflow void count() { stevec100qs++; } void main() { int16 frekvenca; int8 counter, pulses; int1 flag1; set_timer0(0); setup_timer_0( RTCC_INTERNAL | RTCC_DIV_256 ); enable_interrupts(INT_RTCC); enable_interrupts(GLOBAL); //stevec100qs = 0; counter = 0; pulses = 100; flag1 = 0; do { for ( ; ; ) { if (input(B7) == 1 && flag1 == 0) { counter++; flag1 = 1; if (counter == pulses) { frekvenca=counter*10/stevec100qs; frekvenca*=1000; printf(" Counter: %d\r\n", counter); printf(" frekvenca: %ld\n\r", frekvenca); printf(" stevec100qs: %ld\n\r", stevec100qs); stevec100qs=0; break; } } else { if (input(B7) == 0) { flag1 = 0; } } } }while(TRUE); }
neoto ::
Edini problemček pri tej kodi je to, da lahko izgubljaš impulze, če so le-ti prekratki in če nameravaš v main proceduri še kaj drugega delat.
Pri moji kodi je takšna zamisel: Timer0 imam nastavljen na zunanji vir (A4), Timer2 overflow pa pride vsakih 99.2 qs. S tem lahko ugotoviš koliko impulzev je bilo v danem času. Ta rezultat bi moral biti točen.
ps.: ehm, tisti dve zanki (do...while(true) in for(;;)) bi meni boljš izgledali kot while zanki (npr. while(1))
Pri moji kodi je takšna zamisel: Timer0 imam nastavljen na zunanji vir (A4), Timer2 overflow pa pride vsakih 99.2 qs. S tem lahko ugotoviš koliko impulzev je bilo v danem času. Ta rezultat bi moral biti točen.
ps.: ehm, tisti dve zanki (do...while(true) in for(;;)) bi meni boljš izgledali kot while zanki (npr. while(1))
ql000 ::
probal sem tvojo varianto na PIC16F876A, samo timer2 sem zamenjal z timerjem1, pa ustrezne nastavitve sem prilagodil. Timer2 potrebujem za PWM-je, ki poganjata DC-motor. Malo je nagajala tista koda, vrednosti sem testiral preko rs232-ja. Ta del kode, ki mi šteje pulze že uporabljam na nekem drugem projektu (kontrola laserja) in deluje dokaj dobro, res pa je, da je potrebno pazit na meje do katerih greš lahko pri nastavitvah. Glede na to, da mi pulze pri motorju prav prebere pri maximalni hitrosti bo po mojem zadeva zlaufala.
Ti zakaj bi bila while(1) varianta boljša ali obratno, estetika ali praktični razlogi?
P.S.
ti, dej mi še prosim razloži formulo za frekvenco.
Ti zakaj bi bila while(1) varianta boljša ali obratno, estetika ali praktični razlogi?
P.S.
ti, dej mi še prosim razloži formulo za frekvenco.
Zgodovina sprememb…
- spremenil: ql000 ()
Highlag ::
Ker sam delam v assemblerju je to zelo enostavno. V Microchipovem razvojnem okolju imaš namreč orodje s katerim lahko v simulatorju meriš cikle, ali celo čas. Samo vpisati moraš pravilno frekvenco delovanja.
Never trust a computer you can't throw out a window
ql000 ::
madona sej oblubim, da takoj, ko se rešim teh dveh mojh projektov se lotim Assemblerja. Evo prisežem !!!
neoto ::
Frekvenca je tako enostavno rečeno število sprememb na časovno enoto. 1 Hz je pač 1 sprememba na sekundo. Če se ti v 5 sekundah zgodi 10 dogodkov, je frekvenca 10/5 = 2 Hz. Meriš čas in število dogodkov ločeno, potem pa, ko eden izmed njih pride preko določene meje, izračunaš frekvenco.
Pri tvojem projektu me samo skrbi to, da v main funkcijo ne boš smel dodajati dodatnih stvari. Če jih boš dodal, boš tvegal, da določenih impulzev sploh ne boš zaznal, s čimer bo meritev frekvence napačna. Zdaj (še) dela.
Glede zank: meni se zdi while zanka preglednejša od Do zanke, še posebej pa od for(;;). To je pač moje mnenje.
Pri tvojem projektu me samo skrbi to, da v main funkcijo ne boš smel dodajati dodatnih stvari. Če jih boš dodal, boš tvegal, da določenih impulzev sploh ne boš zaznal, s čimer bo meritev frekvence napačna. Zdaj (še) dela.
Glede zank: meni se zdi while zanka preglednejša od Do zanke, še posebej pa od for(;;). To je pač moje mnenje.
Zgodovina sprememb…
- spremenil: neoto ()
Tutankhamun ::
Pa ne da je bol pregledn. Eno zanko lahk clo brišeš ker je preveč. Jest bi radiru for zanko.
Tutankhamun ::
Pa brake tut nima nobene funkcije. In če odstranš for, ti bo break odletu iz while zanke, in program se ti bo zakluču.
Tutankhamun ::
Alpa še bol, nevem kakšno kodo ti zgenerira, ampak recimo da break zamenaš s continue.
Vredno ogleda ...
Tema | Ogledi | Zadnje sporočilo | |
---|---|---|---|
Tema | Ogledi | Zadnje sporočilo | |
» | Arduino in luči (strani: 1 2 )Oddelek: Elektrotehnika in elektronika | 12063 (9689) | FX6300B |
» | PIC18F4550 in ds18s20Oddelek: Elektrotehnika in elektronika | 1992 (1671) | snow |
» | mokrikontrolerji.... the beginingOddelek: Elektrotehnika in elektronika | 3444 (2418) | snow |
» | Zelo pocasno utripanje LED diode (strani: 1 2 )Oddelek: Elektrotehnika in elektronika | 8701 (7906) | a13misko |
» | PIC 16f84A - utripanjeOddelek: Elektrotehnika in elektronika | 2213 (2013) | ql000 |