Go Down

Topic: [RISOLTO]una semplice divisione che non funziona (Read 568 times) previous topic - next topic

BrainBooster

Oct 18, 2012, 08:09 pm Last Edit: Oct 18, 2012, 09:40 pm by BrainBooster Reason: 1
Ciao a tutti
Sto impazzendo (sarà la stanchezza) ma proprio non capisco come mai questo semplice programmino non funzioni o meglio funzioni parzialmente.
è un semplice frequenzimetro che visualizza frequenza e periodo
Code: [Select]


#include <FreqCounter.h>


unsigned long frq;
int cnt;
int pinLed=13;
float per;
void setup() {
 pinMode(pinLed, OUTPUT);

 Serial.begin(9600);        

 Serial.println("Frequenzimtro");
 delay(2000);

}



void loop() {

 
 FreqCounter::f_comp=10;  
 FreqCounter::start(100);  

 while (FreqCounter::f_ready == 0)

 frq=FreqCounter::f_freq;
 per=(1/frq);

 Serial.print("  Freq: ");
 Serial.print(frq);
 Serial.println("Hz");
 Serial.print("  Periodo: ");
 Serial.print(per);
 Serial.println("s");
 delay(20);
 digitalWrite(pinLed,!digitalRead(pinLed));  

}  


il problema è che mi stampa correttamente la frequenza ma il periodo è sempre zero.

PaoloP

Ciao Brain... è con piacere che ti invito a leggere qui --> http://arduino.cc/forum/index.php/topic,91560.0.html  ]:D ]:D

Almeno un link alla libreria che includi non sarebbe male.  :smiley-roll-blue:

BrainBooster

preso  :smiley-sweat:
http://interface.khm.de/index.php/lab/experiments/arduino-frequency-counter-library/

PaoloP


preso  :smiley-sweat:
http://interface.khm.de/index.php/lab/experiments/arduino-frequency-counter-library/


FreqCounter.h
Code: [Select]
/*
  FreqCounter.h - Library for a Frequency Counter c.
  Created by Martin Nawrath, KHM Lab3, Dec. 2008
  Released into the public domain.
*/



#ifndef FreqCounter_h
#define FreqCounter_h


#include <avr/interrupt.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

namespace FreqCounter {

extern unsigned long f_freq;
extern volatile unsigned char f_ready;
extern volatile unsigned char f_mlt;
extern volatile unsigned int f_tics;
extern volatile unsigned int f_period;
extern volatile unsigned int f_comp;

void start(int ms);


}

#endif


FreqCounter.cpp
Code: [Select]
/*
  FreqCounter.cpp -
  Using Counter1 for counting Frequency on T1 / PD5 / digitalPin 5
  Using Timer2 for Gatetime generation

  Martin Nawrath KHM LAB3
  Kunsthochschule für Medien Köln
  Academy of Media Arts
  http://www.khm.de
  http://interface.khm.de/index.php/labor/experimente/
 
  History:
  Dec/08 - V1.0
  Oct/10 - V1.1    removed occasional glitches through interference with
  Jan/12 - V1.2    Arduino 1.0
  timer0
                   set intterrupt timebase to 1ms
                   works with atmega328

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <FreqCounter.h>

unsigned long FreqCounter::f_freq;

volatile unsigned char FreqCounter::f_ready;
volatile unsigned char FreqCounter::f_mlt;
volatile unsigned int FreqCounter::f_tics;
volatile unsigned int FreqCounter::f_period;
volatile unsigned int FreqCounter::f_comp;

void FreqCounter::start(int ms) {

#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || (__AVR_ATmega1280__)


    TIMSK0 &=~(1<<TOIE0);       // disable Timer0  //disable  millis and delay
    delayMicroseconds(50);      // wait if any ints are pending
   
    f_period=ms;
 
 
    if (f_comp ==0) f_comp=1;  // 0 is not allowed in del us

    // hardware counter setup ( refer atmega168.pdf chapter 16-bit counter1)
    TCCR1A=0;                  // reset timer/counter1 control register A
    TCCR1B=0;                 // reset timer/counter1 control register A
    TCNT1=0;               // counter value = 0
    // set timer/counter1 hardware as counter , counts events on pin T1 ( arduino pin 5)
    // normal mode, wgm10 .. wgm13 = 0
   
    TCCR1B |=  (1<<CS10) ;// External clock source on T1 pin. Clock on rising edge.
    TCCR1B |=  (1<<CS11) ;
    TCCR1B |=  (1<<CS12) ;
   
    // timer2 setup / is used for frequency measurement gatetime generation
    TCCR2A=0;
    TCCR2B=0;
   
    // timer 2 presaler set to 128 / timer 2 clock = 16Mhz / 256 = 62500 Hz
    TCCR2B |=  (1<<CS20) ;
    TCCR2B &= ~(1<<CS21) ;
    TCCR2B |=  (1<<CS22) ;

    //set timer2 to CTC Mode with OCR2A is top counter value
    TCCR2A &= ~(1<<WGM20) ;
    TCCR2A |=  (1<<WGM21) ;
    TCCR2A &= ~(1<<WGM22) ;
    OCR2A = 124;                // CTC divider by 125
   
    f_ready=0;                  // reset period measure flag
    f_tics=0;                   // reset interrupt counter
    GTCCR = (1<<PSRASY);        // reset presacler counting
    TCNT2=0;                    // timer2=0
    TCNT1=0;                    // Counter1 = 0
   
    TIMSK2 |=(1<<OCIE2A);       // enable Timer2 Interrupt
   
                                // External clock source on T1 pin. Clock on rising edge.
    TCCR1B |= (1<<CS12) | (1<<CS11) | (1<<CS10);        //   start counting now     
    #endif
}
//******************************************************************
//  Timer2 Interrupt Service is invoked by hardware Timer2 every 1ms = 1000 Hz
//  16Mhz / 128 / 125 = 1000 Hz
//  here the gatetime generation for freq. measurement takes place:

ISR(TIMER2_COMPA_vect) {
// multiple 2ms = gate time = 100 ms
if (FreqCounter::f_tics >= FreqCounter::f_period) {         
                            // end of gate time, measurement ready

    // GateCalibration Value, set to zero error with reference frequency counter
    //  delayMicroseconds(FreqCounter::f_comp); // 0.01=1/ 0.1=12 / 1=120 sec
    delayMicroseconds(FreqCounter::f_comp);
    TCCR1B = TCCR1B & ~7;    // Gate Off  / Counter T1 stopped
    TIMSK2 &= ~(1<<OCIE2A);    // disable Timer2 Interrupt
    TIMSK0 |=(1<<TOIE0);      // enable Timer0 again // millis and delay
    FreqCounter::f_ready=1;             // set global flag for end count period
   
                                        // calculate now frequeny value
    FreqCounter::f_freq=0x10000 * FreqCounter::f_mlt;  // mult #overflows by 65636
    FreqCounter::f_freq += TCNT1;      // add counter1 value
    FreqCounter::f_mlt=0;
   
    }
    FreqCounter::f_tics++;            // count number of interrupt events
    if (TIFR1 & 1) {          // if Timer/Counter 1 overflow flag
    FreqCounter::f_mlt++;               // count number of Counter1 overflows
    TIFR1 =(1<<TOV1);        // clear Timer/Counter 1 overflow flag
    }
    // PORTB = PORTB ^ 32;  // int activity test
}


Secondo me dovresti spostare l'inizializzazione nel setup e non ripeterla ogni loop
Code: [Select]
FreqCounter::f_comp=10;   
  FreqCounter::start(100); 


e poi fare
Code: [Select]
per=(float)(1.0/frq);

BrainBooster

facendo come hai detto non mi stampa più neanche la frequenza :P

BrainBooster

#5
Oct 18, 2012, 09:02 pm Last Edit: Oct 18, 2012, 09:05 pm by BrainBooster Reason: 1
continuo a non capire perchè a divisione non funziona ma comunque grazie a PaoloP ho notato che il periodo viene esportato (se non ho capito male)e quindi ho provato a cambiare il codice come segue
Code: [Select]


#include <FreqCounter.h>


unsigned long frq;
int cnt;
int pinLed=13;
unsigned int per;
void setup() {
  pinMode(pinLed, OUTPUT);

  Serial.begin(9600);       

  Serial.println("Frequenzimtro");
  delay(2000);

}



void loop() {

 
  FreqCounter::f_comp=10;   
  FreqCounter::start(100);

  while (FreqCounter::f_ready == 0)

  frq=FreqCounter::f_freq;
  per=FreqCounter::f_period;

  Serial.print("  Freq: ");
  Serial.print(frq);
  Serial.println("Hz");
  Serial.print("  Periodo: ");
  Serial.print(per);
  Serial.println("ms");
  delay(20);
  digitalWrite(pinLed,!digitalRead(pinLed)); 





il risultato è che adesso mi stampa il periodo ma non è il valore atteso, stampa sempre 100
edit: che fesso.. è il periodo di campionamento, quindi torniamo al codice iniziale

astrobeed


l problema è che mi stampa correttamente la frequenza ma il periodo è sempre zero.


Perché la serial.print di default stampa solo due decimali e sicuramente il periodo è sotto questo limite.
Devi usare la serial.print(valore, n) ove n è il numero di decimali da stampare.

BrainBooster

no, astro grazie della risposta
ma quel periodo non è il valore che cerco.
Voglio solo fare il calcolo del periodo dalla frequenza, tutto qui.
ma sembra che la divisione (1/frequenza) non gli piaccia e non capisco perché

BrainBooster

ho fatto una prova stupida che però ha funzionato...
Per prova ho scambiato la divisione con una moltiplicazione e mi stampa il numero aspettato
Code: [Select]


#include <FreqCounter.h>


unsigned long frq;
int cnt;
int pinLed=13;
float per;
void setup() {
  pinMode(pinLed, OUTPUT);

  Serial.begin(9600);       

  Serial.println("Frequenzimtro");
  delay(2000);

}



void loop() {

 
  FreqCounter::f_comp=10;   
  FreqCounter::start(100); 

  while (FreqCounter::f_ready == 0)

  frq=FreqCounter::f_freq;
  per=(1.00*frq);                        //<-errore voluto, scambiato il "/" con il "*"

  Serial.print("  Freq: ");
  Serial.print(frq);
  Serial.println("Hz");
  Serial.print("  Periodo: ");
  Serial.print(per);
  Serial.println("s");
  delay(20);
  digitalWrite(pinLed,!digitalRead(pinLed)); 




quindi l'ide 1.0.1 cel'ha con le divisioni ?!  :smiley-yell:

astrobeed


ma sembra che la divisione (1/frequenza) non gli piaccia e non capisco perché


Non hai capito, se f = 1000 il periodo è 1/1000 = 0.001 e la serial.print ti stampa 0 perché sei fuori dal numero di decimali di default.

BrainBooster

come al solito hai ragione
bastava fare
Serial.print(per,6);
Grazie ;)

Go Up