Sari la conținut
ELFORUM - Forumul electronistilor

Tahometru/RPM


catalin004

Postări Recomandate

Salutare....vreau sa citesc turatia unui cooler, 3500rpm, 122Hz iesirea la turatie maxima pe firul de citire....rog ajutor pentru citirea interuuptului...am incercat aici dar nu imi iese

void interrupt(){
 N2=(unsigned int)(256*CCPR1H+CCPR1L); // Calcul valoare curenta registru TMR1
 N=N2-N1; // Calcul interval de timp scurs între doua întreruperi
 N1=N2; // Memorare valoare curenta
 tword=N;
 PIR1.CCP1IF=0;
}

void rpm()
{
 T1CON.T1CKPS1=1; // Setare prescaler Timer 1
 T1CON.T1CKPS0=1;
 T1CON.TMR1ON=1; // Pornire Timer 1
 CCP1CON = 0x05; // Capture mode every rising edge
 //CCP1CON=0b00000111; // CCP în mod captura la al 16-lea front crescator
            WordToStr(tword, txt); // convert to string and send back to terminal
            LCD_Out(2,11,txt);

            delay_ms(500);
            PIR1.CCP1IF = 0; //clear CCP flag
            PIE1.CCP1IE = 1; // enable interrupt
}
Editat de catalin004
Link spre comentariu
  • Răspunsuri 35
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

  • catalin004

    19

  • mars01

    13

  • Bandi Szasz

    2

  • Mircea

    1

Top autori în acest subiect

N2=(unsigned int)(256*CCPR1H+CCPR1L); // Calcul valoare curenta registru TMR1

 

N=N2-N1; // Calcul interval de timp scurs între doua întreruperi

 

N1=N2; // Memorare valoare curenta

 

tword=N

 

Dupa tine, ce valoare ar avea tword in urma executarii instructiunilor insirate mai sus? Caci in realitate e aleatoare, nu?!

 

LE: pe telefon nu merge code?

Editat de thunderer
Link spre comentariu

Salut!

 

Cele doua functii, fara a fi puse in context, nu ofera prea multe informatii.

 

Dar cateva indicii:

- asigura-te ca in functia de intrerupere testezi ce anume a generat intreurperea si abia apoi executi codul din intrerupere;

- fiidnca te folosesti de variabila "tword" in afara intreruperii si e declarata globala (nu este locala in functia interrupt() ) asigura-te ca ai declarat-o volatila; oricum nu vad rostul lui 'tword' atata timp cat vad ca atat tword cat si N2 sunt variabile globale;

- Mircea s-a referit la un aspect concret; ai nevoie ca sa folosesti un alt timer, sa zicem Timer0 care sa fie setat sa dea o intrerupere sa zicem la 1ms. Cand se executa codul intreruperii TMR0, incrementezi o variabila statica (sau globala) pana la 1000, cand a ajuns sa fie 1000 (adica a trecut 1secunda) primul lucru care-l faci este sa dezactivezi CCP1IE, initializezi variabila contor, calculezi N, tii minte N2 in N1, te asiguri ca CCPR1H si CCPR1L sunt initializati (daca nu s-a facut deja prin citirea lor) si activezi CCP1IE. In felul acesta stii cate impulsuri ai avut in 1000ms si de aici calculezi viteza cu un update-rate de 1 citire pe secunda.

- initializarea timerelor si a CCP1 o faci intr-o functie separata care se executa o singura data inainte de bucla infinita while(1) iar daca ai nevoie sa modifici ceva in runtime, o faci apeland-o cand ai nevoie si numai cand ai nevoie ,nu de fiecare data cand treci prin bucla infinita.

- fereste-te pe cat posibil de delay-uri cand te folosesti de intreruperi. daca ai nevoie de delay-uri creeaza-ti un delay non-blocking asa cum s-a facut in programele anterior discutate.

Editat de mars01
Link spre comentariu

Am incercat ceva...insa nu am cum sa il testez pentru ca am la serviciu toate jucariile....pe acest PC nu am nici proteus....nu stiu daca este bine dar am incercat sa repet pasii lui mars

char txt=[4];
volatile unsigned long n, n1, n2;
 // clear the watchdog timer
void clrwdt()
{
   asm CLRWDT;
}

//Timer0
//Prescaler 1:4; TMR0 Preload = 6; Actual Interrupt Time : 1 ms
void InitTimer0(){
  OPTION_REG	 = 0x81;
  TMR0		 = 6;
  INTCON	 = 0xA0;
}

void Interrupt(){
unsigned long timer_cnt = 0;     // variable to store time in multiples of 0.001sec
  if (TMR0IF_bit){
    TMR0IF_bit	 = 0;
    TMR0         = 6;
    timer_cnt++;

    if (timer_cnt >= 1000)      // numara 1 sec
         {
         PIE1.CCP1IE = 0;        // disable interrupt while processing
         timer_cnt =0;
         n2=(unsigned int)(256*CCPR1H+CCPR1L); // Calcul valoare curenta registru TMR0
         n2=n1;
         PIE1.CCP1IE = 1;        // enable interrupt while processing
         }
    else
        {
        timer_cnt++;
        }
  }
}

void main()
{
 LCD_Init();
 LCD_Cmd(_LCD_CURSOR_OFF);
 LCD_Cmd(_LCD_CLEAR);

 TRISC.F2=1;              //intrare tahogenerator
 CCP1CON = 0x05; // Capture mode every rising edge
 while(1)
         {
          WordToStr(n1, txt); // convert to string and send back to terminal
          LCD_Out(2,6,txt);
          }
}
Editat de catalin004
Link spre comentariu

Salut!

 

Sunt greseli.

 

1. In functia interrupt() linia:

unsigned long timer_cnt = 0;     // variable to store time in multiples of 0.001sec

ar trebui sa fie:

static unsigned long timer_cnt = 0;     // variable to store time in multiples of 0.001sec

In cazul tau, la fiecare intrerupere timer_cnt va fi mereu zero.

 

2. In functia interrupt() faci urmatoarea atribuire:

n2=n1;

Tinand cont ca n2 si n1 sunt var globale, se presupune ca sunt initializate cu zero la pornirea programului. Tu practic dupa ce incarci anterior in n2 valorile registrilor CCPR1x, prin linia mentionata practic incarci valoarea zero in variabila n2. Variabila n1 nu are nici-o utilitate aici. Poti sa renunti la ea.

 

3. In functia interrupt() fix inainte de linia:

PIE1.CCP1IE = 1;        // enable interrupt while processing

ar trebui sa te asiguri ca initializezi registrii CCPR1x pentru ca la urmatoarea intrerupere sa ai un numar de pulsuri real, fara carryover de la determinarea precedenta.

 

4. Nu pornesti Timer1 care trebuie sa fie in mod counter pentru a putea fi folosita functia de capture a CCP1. Deci lipseste linia:

TMR1ON_bit = 1;
CCP1CON = 0x05; // Capture mode every rising edge

Si mai trebuie si configurat (cred) prin registrul T1CON

 

5. Functia void InitTimer0() este doar declarata si nu si folosita. Practic Timer0 nu porneste. Trebuie introdusa inainte de bucla while(1) dar dupa linia:

CCP1CON = 0x05; // Capture mode every rising edge

ca sa profiti de faptul ca in InitTimer() pornesti intreurperile cu linia din functie:

INTCON	 = 0xA0;

care de altfel s-ar putea (functie de uC-ul folosit) sa nu fie suficienta pentru ce ai tu nevoie.

 

As inlocui linia de mai sus cu actiuni de activare intreruperi explicite:

PEIE_bit = 1;
GIE_bit = 1;

6. Rulezi functia de afisare in bucla principala. S-ar putea sa fie prea rapid, ar trebui sa folosesti un non-blocking delay si sa afisezi rezultatul doar, sa zicem, de 2 ... 3 ori pe secunda. Daca vrei sa afisezi valoarea in RPM (rotatii pe minut) atunci va trebui sa inmultesti valoarea cu 60.

Link spre comentariu

In functia interrupt() linia:

unsigned long timer_cnt = 0; // variable to store time in multiples of 0.001sec

ar trebui sa fie:

static unsigned long timer_cnt = 0; // variable to store time in multiples of 0.001sec

In cazul tau, la fiecare intrerupere timer_cnt va fi mereu zero.

 

 

Care este diferenta intre ele? ce face static in plus?

Multumesc si va salut

Link spre comentariu
Variabila timer_cnt este declarata in interiorul functiei Interrupt, din acest motiv este considerata o variabila locala (i se aloca memorie doar pe durata executarii functiei Interrupt).

Dupa executia functiei Interrupt, aceasta variabila devine invizibila si continutul nu mai este disponibil.

Asta inseamna ca timer_cnt nu pot fi utilizat in restul programului, ca la fiecare intrerupere o sa fie zero.

Daca se doreste pastrarea continutului unei variabile locale dupa ce se incheie executarea functiei, se declara acea variabila incluzand cuvantul cheie static sau se foloseste o variabila globala.

Link spre comentariu

Multumesc...si la mine care sunt variabile globale? n, n1 si n2?

 

Am modificat programul, insa mai am de lucru doar la afisarea pe display....adica sa ii fac un non blocking...

char txt=[4];
volatile unsigned long n, n1, n2;
 // clear the watchdog timer
void clrwdt()
{
   asm CLRWDT;
}

//Timer0
//Prescaler 1:4; TMR0 Preload = 6; Actual Interrupt Time : 1 ms
void InitTimer0(){
  OPTION_REG	 = 0x81;
  TMR0		 = 6;
  INTCON	 = 0xA0;
}

void Interrupt(){
static unsigned long timer_cnt = 0;     // variable to store time in multiples of 0.001sec
  if (TMR0IF_bit  && PIR1bits.CCP1IF){
    TMR0IF_bit	 = 0;
    TMR0         = 6;
    timer_cnt++;

    if (timer_cnt++ >= 1000)      // numara 1 sec
         {
         PIE1.CCP1IE = 0;        // disable interrupt while processing
         timer_cnt =0;
         n2=(unsigned int)(256*CCPR1H+CCPR1L); // Calcul valoare curenta registru TMR0  frecventa
         n1=n2*60;                              //calcul in rpm
         PIE1.CCP1IE = 1;        // enable interrupt while processing
         }
    else
        {
        timer_cnt++;
        }
  }
}

void main()
{
 LCD_Init();
 LCD_Cmd(_LCD_CURSOR_OFF);
 LCD_Cmd(_LCD_CLEAR);

 TRISC.F2=1;              //intrare tahogenerator
 TMR0ON_bit = 1;          //TMR0 pornit
 CCP1CON = 0x05;          // Capture mode every rising edge
 PEIE_bit = 1;
 GIE_bit = 1;             //Enable Global Interrupt
 while(1)
         {
          WordToStr(n1, txt); // convert to string and send back to terminal
          LCD_Out(2,6,txt);
          }
}

Nu am inteles de ce trebuie folosit timer 1....atata timp cat eu am initializat timer0...probabil ca ati gresit in exprimare...ma refer la punctul 4

Link spre comentariu

Multumesc...si la mine care sunt variabile globale? n, n1 si n2?

 

Am modificat programul, insa mai am de lucru doar la afisarea pe display....adica sa ii fac un non blocking...

Nu am inteles de ce trebuie folosit timer 1....atata timp cat eu am initializat timer0...probabil ca ati gresit in exprimare...ma refer la punctul 4

 

Variabilele pot fi globale, adica accesibile de oriunde din program. Se declara la inceputul programului (simplificat vorbind si incomplet dar e suficient pentru explicatia curenta).

Variabilele pot fi locale, adica declarate in interiorul unei functii. Variabila locala exista (este stocata in memorie) doar cat se executa functia, apoi memoria este eliberata. Altfel spus, cand programul ajunge intr-un punct cand o functie este apelata, el sare la adresa din memorie unde incepe functia, daca are parametri functia atunci ii copiaza pentru utilizare in corpul functiei si apoi isi aloca memorie pentru variabilele locale si face ce are de facut functia mai departe. La finalul executiei functiei, variabilele locale "create" in functie, sunt distruse.

 

Diferenta este ca atunci cand se declara o variabila locala ca si STATIC, acea variabila se va comporta ca si cum ar fi un fel de variabila globala in sensul ca isi pastreaza valoarea chiar si dupa ce functia este executata dar in acelasi timp ramane variabila locala adica nu se poate apela altundeva in program ci doar in cadrul functiei unde a fost declarata.

 

Priveste-o ca pe o compartimentalizare. Cineva ar putea spune: de ce mai este nevoie de variabile locale cand avem variabile globale? E mai usor sa declari variabila globala si sa nu iti mai faci probleme cu STATIC si asa mai departe.

 

Diferenta este ca variabilele globale odata declarate ele "mananca" memoria aia de care au nevoie in mod constant. Cand o variabila este locala (simplu, fara atributul static), memoria se aloca doar pe timpul executiei functiei si cand se termina executia se elibereaza memoria devenind disponibila pentru alte lucruri. Aceasa poate genera alte probleme dar nu intru detalii.

 

Mai mult, o variabila locala este "protejata". Nu o poti modifica din greseala de altundeva din program. Poate avea si acelasi nume cu o alta variabila locala (fiecare sta in "cutiuta" ei (adica functia ei :) ) ceea ce nu se poate cand lucrezi cu variabile globale care trebuie sa aiba un nume unic.

 

 

*********************************************************************************************************************************

 

 

Legat de programul tau. In continuare sunt multe greseli.

 

Tu nu intelegi un lucru elementar. O functie o declari mai intai, apoi o definesti si la final o folosesti.

De declaratie cateodata scapi sa o faci separat (o faci simultan cu definitia) dar daca nu pui functiile in ordine ai incurcat borcanele (in caz ca acea functie este folosita in alta functie).

Cand o definesti ii scrii corpul, adica scrii ce urmeaza sa faca functia.

Cand o folosesti, ii incluzi numele in functia main() in pozitia necesara in programul tau.

 

Trebuie sa intelegi un lucru. Programul executat de uC este fix ce vezi tu in functia main(). Nimic mai mult, nimic mai putin. Aparent o exceptie face functia interrupt() dar in realitate compilatorul o "infige" si pe ea in functia main() doar ca nu o vezi tu.

 

Restul, ceea ce aparent nu este in functia main(), este "cules" de compilator in momentul compilarii si plasat cum trebuie, in ordine, in functia main().

 

Un mod simplicat de a vorbi dar e clar acum?

 

 

La obiect acum.

 

1. Nu ai declarat functia InitTimer0() decat in momentul definitiei dar sa zicem ca scapi si fara sa o faci in prealabil (o mai fac si eu :) ). In cazul acesta.

Corect era ca la inceputul programului sa scrii:

void InitTimer0();

2. Ai definit (si simultan declarat) functia InitTimer0() aici:

//Timer0
//Prescaler 1:4; TMR0 Preload = 6; Actual Interrupt Time : 1 ms
void InitTimer0(){
  OPTION_REG	 = 0x81;
  TMR0		 = 6;
  INTCON	 = 0xA0;
}

3. Dar unde folosesti tu functia InitTimer0() in programul tau principal, main()?

Oops ca nu o folosesti ...

 

Trebuia ceva de genul:

void main(){
   LCD_Init();
   LCD_Cmd(_LCD_CURSOR_OFF);
   LCD_Cmd(_LCD_CLEAR);
 
   InitTimer();

   TRISC.F2=1;              //intrare tahogenerator
   TMR0ON_bit = 1;          //TMR0 pornit
   CCP1CON = 0x05;          // Capture mode every rising edge
   PEIE_bit = 1;
   GIE_bit = 1;             //Enable Global Interrupt
 
   while(1){
     WordToStr(n1, txt); // convert to string and send back to terminal
     LCD_Out(2,6,txt);
   }
}

************************************************************************************

 

 

Ce este aceasta?

char txt=[4];

Nu exista in sintaxa C. Poate ai vrut ceva de genul:

char txt[4];

In care declari un vector (matrice unidimensionala) cu 4 elemente.

 

************************************************************************************

 

In intrerupere sectiunea aceasta este gresita scrisa si arata ca nu stii ce faci. Ar trebui sa mai studiezi putin manualele ...

if (TMR0IF_bit  && PIR1bits.CCP1IF){
    TMR0IF_bit	 = 0;
    TMR0         = 6;
    timer_cnt++;

    if (timer_cnt++ >= 1000)      // numara 1 sec
         {
         PIE1.CCP1IE = 0;        // disable interrupt while processing
         timer_cnt =0;
         n2=(unsigned int)(256*CCPR1H+CCPR1L); // Calcul valoare curenta registru TMR0  frecventa
         n1=n2*60;                              //calcul in rpm
         PIE1.CCP1IE = 1;        // enable interrupt while processing
         }
    else
        {
        timer_cnt++;
        }
  }

Ar trebui scrisa asa:

if (TMR0IF_bit  && TMR0IE_bit){	//daca flagul de intrerupere emis de TMR0 este HIGH si intreruperea lui TMR0 este activata
    // incarca valorile in TMR0 si anuleaza flagul de intrerupere in pregatire pentru urmatoarea intrerupere
    TMR0IF_bit	 = 0;
    TMR0         = 6;
    // timer_cnt++;             // linia aceasta nu are nici-un sens, se bate cap in cap cu acelasi lucru din else-ul de mai jos

    // if (timer_cnt++ >= 1000) // ++ ul din paranteza se "contreaza" cu continutul else-ului - trebuie sa dispara
    if (timer_cnt >= 1000)
    {
        PIE1.CCP1IE = 0;        // disable CCP1 interrupt while processing
        timer_cnt =0;
        n2=(unsigned int)(256*CCPR1H+CCPR1L); // Calcul valoare curenta registru TMR0  frecventa
        
        // Nu iti recomand sa faci inmultirea aceasta in intrerupere; mai bine o faci cand faci afisarea
        n1=n2*60;               //calcul in rpm 
        PIE1.CCP1IE = 1;        // enable CCP1 interrupt after processing
    }
    else
    {
        timer_cnt++;
    }
}

******************************************************************************************************************************************************************

 

 

Nu am inteles de ce trebuie folosit timer 1....atata timp cat eu am initializat timer0...probabil ca ati gresit in exprimare...ma refer la punctul 4

 

Pentru ca nu ai citit datasheet-ul uC-ului folosit, subsectiunea Capture in sectiunea Modulului CCP.

Nu stiu ce uC folosesti dar Microchip foloseste Timer1 atunci cand se configureaza modulul CCP pentru functia de Capture.

Editat de mars01
Link spre comentariu

PIC16F876A-I/SP

 

 

Pff....ce greu este....degeaba citesc daca nu mi se explica....acum cam incep sa inteleg.... :tryre

Salut!

 

Cele doua functii, fara a fi puse in context, nu ofera prea multe informatii.

 

Dar cateva indicii:

- asigura-te ca in functia de intrerupere testezi ce anume a generat intreurperea si abia apoi executi codul din intrerupere;

- fiidnca te folosesti de variabila "tword" in afara intreruperii si e declarata globala (nu este locala in functia interrupt() ) asigura-te ca ai declarat-o volatila; oricum nu vad rostul lui 'tword' atata timp cat vad ca atat tword cat si N2 sunt variabile globale;

- Mircea s-a referit la un aspect concret; ai nevoie ca sa folosesti un alt timer, sa zicem Timer0 care sa fie setat sa dea o intrerupere sa zicem la 1ms. Cand se executa codul intreruperii TMR0, incrementezi o variabila statica (sau globala) pana la 1000, cand a ajuns sa fie 1000 (adica a trecut 1secunda) primul lucru care-l faci este sa dezactivezi CCP1IE, initializezi variabila contor, calculezi N, tii minte N2 in N1, te asiguri ca CCPR1H si CCPR1L sunt initializati (daca nu s-a facut deja prin citirea lor) si activezi CCP1IE. In felul acesta stii cate impulsuri ai avut in 1000ms si de aici calculezi viteza cu un update-rate de 1 citire pe secunda.

- initializarea timerelor si a CCP1 o faci intr-o functie separata care se executa o singura data inainte de bucla infinita while(1) iar daca ai nevoie sa modifici ceva in runtime, o faci apeland-o cand ai nevoie si numai cand ai nevoie ,nu de fiecare data cand treci prin bucla infinita.

- fereste-te pe cat posibil de delay-uri cand te folosesti de intreruperi. daca ai nevoie de delay-uri creeaza-ti un delay non-blocking asa cum s-a facut in programele anterior discutate.

Aici sti zis sa pornesc timer 0...de aceea am folosit acest timer

Deci:

- variabila globala - la inceputul programului si nu necesita sa fie volatila;

- variabila statica - in functia care o apeleaza(pe variabila) -nu este necesar sa fie volatila...

 

 

cam asta am priceput pana aici

Link spre comentariu

Atributul "volatile" nu are nici-o legatura cu faptul ca o variabila este globala sau locala.

"Volatile" aplica o anumita proprietate asupra unei variabile indiferent de "vizibilitatea" acesteia.

 

Am pomenit de Timer0 pentru ca viteza masurata a unui ventilator inseamna numararea unui numar de impulsuri intr-o perioada bine definita de timp.

 

Timer1 are alt rol si acesta este un rol sa zicem secundar. Este folosit de modulul CCP atunci cand este setat in modul Capture.

 

Trebuie avut grija la configurarea prescaler-ului pentru ca daca intervalul intre evenimente (pulsuri ventilator) depaseste 65535 de tick-uri o sa ai eroare.

 

Catalin, imi pare rau de efortul meu daca doar aceasta ai inteles ... Eu pot sa iti explic dar nu pot sa inteleg in locul tau.

 

Iar explicatiile mele, prin natura mediului unde sunt prezentate, sunt limitate si nu sunt o solutie completa la ceea ce nu stii. Toate golurile in cunoastere se umplu folosindu-te de manuale.

Aici vii cu intrebari cand nu intelegi ceva ce ai citit in datasheet sau in manual.

Eu ma opresc aici.

Editat de mars01
Link spre comentariu

Dar ca sa nu las fara o solutie (poate asa inveti ceva):

/*   Compiler = mikroC 7.1.0   uC type  = 16F876A   uC freq  = 4MHz   Author   = mars01, on elforum.ro*/sbit LCD_RS at RB4_bit;sbit LCD_EN at RB5_bit;sbit LCD_D4 at RB0_bit;sbit LCD_D5 at RB1_bit;sbit LCD_D6 at RB2_bit;sbit LCD_D7 at RB3_bit;sbit LCD_RS_Direction at TRISB4_bit;sbit LCD_EN_Direction at TRISB5_bit;sbit LCD_D4_Direction at TRISB0_bit;sbit LCD_D5_Direction at TRISB1_bit;sbit LCD_D6_Direction at TRISB2_bit;sbit LCD_D7_Direction at TRISB3_bit;volatile unsigned int period = 0;volatile unsigned char display_flag = 0;unsigned char text[6];  // enough space for 5 characters// those are declared as volatile otherwise are optimized out by the compilervolatile unsigned int start = 0;volatile unsigned int stop = 0;// function prototype - declarationunsigned int period_func (int, int);void hw_init();// function definitionunsigned int period_func (unsigned int start_value, unsigned int stop_value){   return (stop_value - start_value);}   void Interrupt(){   static unsigned int cnt = 0;   static unsigned char flag = 0;      if (CCP1IF_bit && CCP1IE_bit){      CCP1IF_bit = 0;       // Reset CCP1 Interrupt period      if (flag){         stop = (((unsigned int)CCPR1H)<< 8) | ((unsigned int)(CCPR1L));                  // actual function usage (call)         period = period_func(start, stop);         flag = 0;                  // Reset Timer1         TMR1L = 0x00;         TMR1H = 0x00;      }      else{         flag = 1;         start = (((unsigned int)CCPR1H)<< 8) | ((unsigned int)(CCPR1L));      }   }      if (TMR0IF_bit && TMR0IE_bit){      // reset Timer0      TMR0IF_bit = 0;      TMR0 = 0x06;      // frequency will be displayed once every 500ms - twice per second      if (cnt >= 500){         display_flag = 1;         cnt = 0;      }      else{         cnt++;      }   }}// definitation of the hw_init() function which manage the HW initializationvoid hw_init(){   // Blink a LED to serve as a heart beat   CMCON = 0x07;     // comparators are OFF   TRISA0_bit = 0;   // RA0 is output;   ADCON1 = 0xFF;    // all pins are DIGITAL   RA0_bit = 0;      // RA0 start as OFF;      // Configure CCP1   CCP1CON = 0b00000101;      // capture mode every rising edge   CCP1IF_bit = 0;            // CCP1 interrupt flag - needs to be cleared in sw      // Configure Timer1   T1CKPS1_bit = 0;           // Timer1 prescaler set to 1:1; increment each 1us   T1CKPS0_bit = 0;   T1OSCEN_bit = 0;           // LP oscillator is OFF   TMR1CS_bit = 0;            // TMR1 is incremented on internal clock   TMR1ON_bit = 1;            // enable Timer1      // Configure Timer0: Prescaler 1:4 and TMR0 preload with 0x06   PS2_bit = 0;               // Prescaler configured at 1:4   PS1_bit = 0;   PS0_bit = 1;   NOT_RBPU_bit = 1;          // pull-ups on Port B are disabled   TMR0 = 0x06;   // Initialize working registers   TMR1L = 0x00;              // Set Timer1 register to zero   TMR1H = 0x00;   CCPR1L = 0x00;             // Initialize CCP register to 0   CCPR1H = 0x00;      // Enable CCP1 interrupt and disable Timer1 interrupt   CCP1IE_bit = 1;            // enable CCP1 interrupt   TMR1IE_bit = 0;            // disable TMR1 interrupt      // General eanble of the interrupts   GIE_bit = 1;               // enable all interrupts   PEIE_bit = 1;              // enable peripheral interrupts      LCD_init();                // initialize LCD}   void main(){   volatile unsigned long temp = 0; // volatile because otherwise it gets optimized out by the compiler      // actual usage of our function that manage the hardware initialization   hw_init();      Lcd_Out(1,1,"Frecventa:      "); // display some static text, it will not change, on line 1 of the LCD      while (1){      if (display_flag){            // if the time to display values has come (500ms passed)         display_flag = 0;          // make sure that you clear the flag so it is HIGH only when decided in the interrupt                  RA0_bit = !RA0_bit;        // LED heart beat                  temp = 1000000 / period;   // convert period (measured in microseconds) in frequency         temp = temp * 60;          // we get RPM value (rotation per minute) out of the frequency (rotations per second)         WordToStr(temp, text);     // convert RPM value to text string         Lcd_Out(2,1, text);        // display the text on LCD on line 2      }   }}

LE: sa fii atent ca nu cumva pinul de tach sa fie tras in VCC al ventilatorului cu un rezistor de pull-up. In cazul acesta pulsurile iti vin inversate si trebuie configurat diferit CCP1 si in plus daca tensiunea de alimentare a ventilatorului este mai mare de 5V risti sa arzi uC-ul (trebuie redusa tensiunea la nivele acceptabile adica < 5V).

Editat de mars01
Link spre comentariu

Firul de tach este legat printr-o rezistenta de 1kohm la +5Vcc, nu la 12 unde este alimentat ventilatorul.....ventilatorul este comandata de alecasi uC, prin iesirea CCP2 (PWM2), adica am un potensiometru, il citesc prin ADC si controlez in 1khz ventilatorul cu un mosfet...si ii citesc turatia prin CCP1..

Eu nu vreau sa te oprest aici...vreau sa intelegi ca prin exemple ma ajuti mult...ma repet , citesc, am inceput si masterul in electronica si ssiteme incorporate, unde ar trebui sa ne invete programare...insa ei ce ne invata????;Sa facem un LED blink si o intefatare cu un LCD...sau iesirea PWM(si asta tot fara timer - dar sa mai vorbesc de un pwm trifazat)....

 

De stiu ca ma dau afara dupa forum (cu toate ca am o vechime in depanari), insa voi pune presiune pe raspunsurile tale...ciudat este ca nu mai e nici unul pe aici ...adica doar 1 membru stie C?

 

Revenind la program...este superba gandirea....adica modul in care se face achizitia....nu vreau sa copiez, insa vreau sa studiez si apoi sa pun in practica...Hardware nu am probleme...insa Soft 99%


PS:Din ce vad...un timer, adica 1 este folosit pentru citire si 0 pentru display...nu?

Link spre comentariu

Creează un cont sau autentifică-te pentru a adăuga comentariu

Trebuie să fi un membru pentru a putea lăsa un comentariu.

Creează un cont

Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!

Înregistrează un nou cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum



×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări