» »

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 :8) ) 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

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. >:D
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:8) . 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>:D

Join the assembler side! You know it's in you!>:D

Sploh ni tako zakomplicirano. Imaš samo cca 32 ukazov. :D
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

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 :D

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:
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 ()

ql000 ::

@Highlag
ti kako veš koliko ciklov preteče, da se števec poveča za 1?

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....
}
}

Zgodovina sprememb…

  • spremenil: neoto ()

ql000 ::

@Neoto: signal prpeljem na RA4 ne?

neoto ::

Mislim da...

ql000 ::

Evo, združil sem mojo kodo za merjenje števila pulzov in Neotovo kodo za timer in ni vrag nekaj miga 8-)! Zankrat še ne vem v kakih enotah dobim odgovor >:D 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:
#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)) :D

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.

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.

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.

neoto ::

Tega pa niti opazil nisem ... :D

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.

ql000 ::

ja ampak a ni poanta breaka, da zaključi z izvajanjem for zanke (ali pa while)?

neoto ::

To je res, ampak poglej, kam pride, če gre iz for zanke... nazaj v for zanko.


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

Arduino in luči (strani: 1 2 )

Oddelek: Elektrotehnika in elektronika
9811442 (9068) FX6300B
»

PIC18F4550 in ds18s20

Oddelek: Elektrotehnika in elektronika
191878 (1557) snow
»

mokrikontrolerji.... the begining

Oddelek: Elektrotehnika in elektronika
203290 (2264) snow
»

Zelo pocasno utripanje LED diode (strani: 1 2 )

Oddelek: Elektrotehnika in elektronika
508388 (7593) a13misko
»

PIC 16f84A - utripanje

Oddelek: Elektrotehnika in elektronika
222082 (1882) ql000

Več podobnih tem