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
/*
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
/*
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
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
#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
BrainBooster:
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.
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é