Pages: 1 [2] 3 4 ... 7   Go Down
Author Topic: Frequenzimetro  (Read 4980 times)
0 Members and 1 Guest are viewing this topic.
Deep south of Italy
Offline Offline
Faraday Member
**
Karma: 8
Posts: 2955
The quieter you become, the more you can hear
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Se volete un esempio "porchereccio" di questo tipo di approccio, io sto provando a fare qualcosa di simie...
Ecco il codice iniziale per le prove:
Code:

volatile unsigned long stateh = 0; //tick alti
volatile unsigned long statel = 0;  //tick bassi
long previousMillis = 0;  //variabile per controllo tempo di scan
unsigned long htime=0;  //tempo High
unsigned long ltime=0;  //tempo Low
unsigned long phtime=0; // tempo precedente High
unsigned long pltime=0; // tempo precedente Low
unsigned long freq=0;  // frequenza
long interval = 1000;  //intervallo invio letture
float offset=3.00;  //offset empirico
void setup()
{
  Serial.begin(9600);  //inizializzo la seriale
  attachInterrupt(0, hitime, HIGH);  //iniziamo da un livello alto
 
}

void loop()
{
 
  unsigned long currentMillis = millis(); //prendo il tempo
  if(currentMillis - previousMillis > interval) {  //se è trascorso l'intervallo impostato
   
    previousMillis = currentMillis;  //reetto il tempo
    //stampo i valori calcolati
  Serial.print("Hi= ");
   Serial.println(stateh);
    Serial.print("lo= ");
   Serial.println(statel);
     Serial.print("frequenza(Hz)= ");
     freq=((stateh + statel)/2)-offset;  //presunto dutycycle a 50%
       Serial.println(freq,9);
   Serial.print("periodo(ms)= ");
   Serial.println(((1.00/freq)*1000000.00),4);
   Serial.print("Htime(uS)= "); 
   Serial.println(htime);
   Serial.print("Ltime(uS)= ");
   Serial.println(ltime);
  // azzeriamo tutto... si riparte
stateh=0;
statel=0;
freq=0;
phtime=0;
htime=0;
pltime=0;
ltime=0;
}

}

void hitime()  //interrupt per livello alto
{
  ltime=pltime-micros();
  stateh  = stateh + 1;  //incremento numero tick alti
  detachInterrupt(0);
  attachInterrupt(0, lotime, LOW);  //aspettiamo l'evento low
  phtime=micros();
}

void lotime()  //interrupt per livello basso
{
  htime=phtime-micros();
  statel  =statel + 1; //incremento numero tick bassi
  detachInterrupt(0);
  attachInterrupt(0, hitime, HIGH);  //aspettiamo l'evento high
  pltime=micros();
}
non badate allo stile ma segnalatemi eventuali errorazzi  smiley-mr-green
lo sto provando con un generatore di onda quadra (autocostruito) che mi spara fuori 57Hz collegato sul pin 2 e che il programmillo legge correttamente, ripeto è un inizio... anche se i DSO mi dice che funziona.
« Last Edit: October 24, 2012, 03:16:43 am by BrainBooster » Logged

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10448
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

1. tutte le variabili usate (anche in sola lettura) da due intterrupt differenti, o tra "main" e interrupt, sono da dichiarare volatili. Un paio le hai azzeccate, ma ti sei dimenticato di quasi tutti i long.

2.
Quote
detachInterrupt(0);
  attachInterrupt(0, hitime, HIGH);  //aspettiamo l'evento high
inutile il detach, poichè l'attach va a sostituire la funzione precedente.

3. non vedo perchè usaere phtime e pltime; in realtà o usi una o usi l'altra, quindi tanto vale usarne una sola generica "ptime"

4.
Code:
phtime=0;
htime=0;
pltime=0;
ltime=0;
perchè azzeri i tempi? questo farà impazzire la prima lettura dopo la print. Tanto l'overflow di queste variabili è legata alla micros(), quindi azzerarle è perfettamente inutile, anzi, come detto prima antiproduttivo. Anche azzerare freq è inutile, poichè non è un contatore ma viene riassegnata quando serve, ma almeno non crea casini.

5. perchè elimini 3.00 da freq?
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Deep south of Italy
Offline Offline
Faraday Member
**
Karma: 8
Posts: 2955
The quieter you become, the more you can hear
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

1. hai ragione, in verità ero partito con un altro codice che poi ho adattato sempre più, adesso ho corretto con i tipi giusti.
2. non lo sapevo smiley li ho levati ed effettivamente sembra ininfluente
3. le leggo entrambi per verifica e futuro calcolo del dutycycle
4. azzerare i contatori serve per ripulire dai dati della lettura precedente dopo che l'ho stampata, non sembra far ipazzire nulla.
5. quel tre è un valore di scostamento fisso che ho con la lettura sull'oscilloscopio, dopo vedrò di capire perchè c'è questa differenza di letture
Logged

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10448
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

3. nache ai fini del dutycicle on ti serve avere le due variabili (leggeresti solo l'ultimo dutycicle), ma piuttosto un array degli ultimi X valori, oppure una media. quindi lì usa una variabile sola, che poi al massimo elabori a seconda delle necessità
4. non ti accorgi che impazzisce perchè non stampi i duticicle. quando fai ltime=pltime-micros(); nell'interrupt, e hai appena azzarato la variabile, ti esce che l'impulso è durato micros()...
5. se implementi una variabile booleana (ma devi essere certo dello stato del pin alla partenza) o una lettura (ma con twi / cbr o come si chiamano) nell'iterrupt, e hai seguito il mio consiglio al punto 3, scopirrai che i due codici sono perfettamente identici. Quindi anzichè avere 2 interrupt, RAISING e FALLING, ne avrai solo uno di CHANGE, che guarda caso è possibile attivare su qualsiasi pin lavorando a basso livello coi registri.
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Deep south of Italy
Offline Offline
Faraday Member
**
Karma: 8
Posts: 2955
The quieter you become, the more you can hear
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

per adesso non sto facendo la media dei valori ottenuti ma faccio solo una lettura al secondo, quindi quello sarebbe solo l'ultimo dutycycle, poi si vedrà...
quindi alla fine tu dici che è meglio usare un pcint piuttosto che gli interrupt normali?
Logged

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10448
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

no, dico che è la stessa cosa per i tuoi fini, però dico che è meglio accorpare la logica in una sola funzione generica sia per RISING che per FALLING.

così se devi modificare qualcosa in un colpo solo lo fai per entrambi i picchi, evitando stupidi errori di copia-incolla che fanno solo perdere tempo.

poi trovo che la stesura del codice va sempre fatta con un occhio di rigurado al fine che si vuole ottenre, si chiama architettura.
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Deep south of Italy
Offline Offline
Faraday Member
**
Karma: 8
Posts: 2955
The quieter you become, the more you can hear
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

chiaramente hai ragione quando parli di architettura, ma l'avevo detto all'inizo, è solo un primo abbozzo della logica, poi tutto si può migliorare smiley
quindi in pseudocodice (anche non pseudo smiley  ) tu che faresti?
edit:
... pensavo che se uso l'evento change, poi non devo andare a leggere "a mano" lo stato del pin introducendo ulteriore ritardo?
« Last Edit: October 24, 2012, 09:12:48 am by BrainBooster » Logged

Deep south of Italy
Offline Offline
Faraday Member
**
Karma: 8
Posts: 2955
The quieter you become, the more you can hear
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Rifatto e semplificato con pinchange interrupt

Code:
#include <PinChangeInt.h>
volatile unsigned long previousMillis = 0;  //variabile per controllo tempo di scan
long interval = 1000;  //intervallo invio letture
volatile unsigned long hticks=0;
volatile unsigned long  lticks=0;

void setup()
{
  PCintPort::attachInterrupt(2, &quicfunc, CHANGE);
   Serial.begin(9600);
}

void loop()
{
   unsigned long currentMillis = millis(); //prendo il tempo
  if(currentMillis - previousMillis > interval) {  //se è trascorso l'intervallo impostato
   
    previousMillis = currentMillis;  //resetto il tempo
    unsigned long totale=hticks+lticks;
    Serial.print("numero ticks Hi= ");
    Serial.println(hticks);
   
    Serial.print("numero ticks lo= ");
    Serial.println(lticks);
   
     Serial.print("frequenza (Hz)= ");
    Serial.println((totale/2));
     Serial.print("periodo (uS)= ");
    Serial.println(((1.0/hticks)*1000000.0),4);
    hticks=0;
    lticks=0;
  }}
 
 
  void quicfunc() {
  if (digitalRead(2)==HIGH){
  hticks++;}
  else{
  lticks++;
  }
}
legge bene fino a da 1 a 15000hz (limite dell'oscillatore che uso per le prove)
che ne dite?
Logged

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10448
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

il llimite della digitalRead è di 145KHz. Se usi direttamente i registri, sali a 4MHz

more info:
http://www.billporter.info/ready-set-oscillate-the-fastest-way-to-change-arduino-pins/

piccola chicca per il tempo:
Code:
#define byte MAX 10 //una define non ha bisogno di essere volatile!
volatile byte contatore = 0;
volatile unsigned long lastDuration[MAX];

void quicfunc() {
  lastDuration[contatore<MAX-1?contatore+1:0;] = millis(); //inizializza il tempo di inizio impulso del PROSSIMO segnale
  lastDuration[contatore] = millis()-lastDuration[contatore]; //calcola la durata del segnale attuale
  contatore=contatore<MAX-1?contatore+1:0;

  if (digitalRead(2)==HIGH){
    hticks++;
  }else{
    lticks++;
  }
}

NON È TESTATO! ma in pratica riempo un array delle ultime 10 durate di impulso (però non c'è modo per sapere se il primo impulso è alto o basso, potresti usare un boolenao di quelli che avanzano per indicare se la lettura in posizione 0 è high o low e da li ricavare il resto)
al posto di un int e dei vari if, potresti usare una union, quindi crei una variabile di X bit (e quindi che con l'overflow va a 0 da sola) e sfruttare uno dei bit che ti avanza al posto della booleana.
ottimizzazione spinta, senza andare troppo nel basso livello smiley
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Lamezia Terme
Offline Offline
Shannon Member
****
Karma: 513
Posts: 12317
Le domande di chi vuol imparare rappresentano la sua sete di sapere
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Lesto, può essere che ciò che dico sia a sproposito in questa discussione, e mi pare peraltro di averlo già scritto. Io e te abbiamo parlato tempo fa di una lib, che a te non piace molto (ma le motivazioni erano troppo ostiche per le mie misere conoscenze), ma con la quale io leggo senza problemi fino a poco più di 7MHz, riferendomi ad un segnale prodotto da un Generatore.
Questa mi affermazione contrasta con la tua (4MHz con digitalRead) o sono due cose differenti?
Logged

Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10448
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

sì ricodo ma non ricordo la libreria. forse era la digitalWriteFast?

un alibreria non può essere più veloce del semplice codice, per il semplice fatto che si perdono clock nel salto a funzione (e non credo proprio che la cosa sia ottimizzata nel compilatore)

ho controllato, e il link da cui ho preso i dati si parla di SCRITTURA, mentre noi parliamo di lettura.

quindi ho cercato nei menadri del forum: http://arduino.cc/forum/index.php/topic,47106.0.html

Code:
PIND & B00000010

impiega 2 cicli macchina, quindi frequenza massima di 8MHz con quazo a 16MHz

edit: e comunque non stiamo tenedo conto del coide di contorno, mooolto più pesante.
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Lamezia Terme
Offline Offline
Shannon Member
****
Karma: 513
Posts: 12317
Le domande di chi vuol imparare rappresentano la sua sete di sapere
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

E' una lib specifica per far funzionare Arduino come frequenzimetro, ho dovuto metttere mano ad alcuni parametri, forte del fatto che avevo strumentazione seria per i confronti, ma alla fine ho letto oltre 7MHz senza problemi, visualizzandoli su un LCD; l'avevo vista sul tuo sito e ti ho chiesto se l'usavi anche tu e mi hai risposto che non ti piaceva, comunque parliamo sempre e comunque di lettura e misurazione, NON di scrittura
Logged

Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10448
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ah, ho capito, parli della freqcounter di Martin Nawrath.. in pratica usa il timer0 come contatore, per un intervallo di tempo deciso da timer2.

per questo raggiunge la precisione di una pura lettura digitale (2 clock circa). In effetti quel codice è più ottimizzato dell'uso dell'interrupt, ma ci perdi 2 timer e la possibilità di studiare l'andamento PWM.
certo è un bel esercizio di stile, ma non la userei mai in un codice che debba fare pure altro.
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Lamezia Terme
Offline Offline
Shannon Member
****
Karma: 513
Posts: 12317
Le domande di chi vuol imparare rappresentano la sua sete di sapere
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Nel mio caso non deve fare altro, dovrò solo implementare la lettura di un pulsante ed il controllo di due pin, il resto è tutto sano hardware smiley
Logged

Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10448
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

se implementi l'anti-bounce in hardware hai fatto cinquina smiley
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Pages: 1 [2] 3 4 ... 7   Go Up
Jump to: