Go Down

Topic: Mi servono 6-7 decimali ma float non va.... (Read 9850 times) previous topic - next topic

leo72

La 1.0.5+ è la 1.0.5 compilata dai sorgenti con alcune cose aggiunte di recente, ma si tratta di piccolezze che non riguardano altro.

Io ho Linux quindi non ho né Windows né la possibilità di usare AvrStudio per cui non so se AvrStudio c'entri qualcosa. Ma se l'IDE non trova una toolchain sul sistema dovrebbe usare quella di serie. Forse vede la toolchain di AvrStudio e compila con quella.

PS:
io comunque è dall'anno scorso che uso i long long, anche alcune vecchie versioni del mio leOS ne facevano uso. Però è anche da più di 1 anno che uso la toolchain Atmel. Sarà quello senz'altro.

lestofante

Quote

long long Prova = 12345678901;

error: integer constant is too large for 'long' type

Ma se faccio così il compilatore non da errore:
long long Prova = 12345678901ULL;



scusate ma a me sembra un comportamento normalissimo, di defult i numeri "harcodati" sono intesi come int, o nel caso ci sia un punto come float. e 12345678901 è troppo grande per un  int. noi vogliamo un long long, e quindi bisogna specificarlo con "LL". Occhio che "ULL" siginifica unsigned long long.

IDE 1.0.1 su linux, funziona, però mi sa che usa il compilatore di sistema avr-g++ 4.7.0 e non quello nella cartella arduino. (è installato tramite repository)
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

menniti

Scusate, ma io devo farvi tornare a terra :smiley-mr-green:
Quindi devo ricominciare dal mio dubbio. La FreqCounter, che vi quoto:
Code: [Select]
#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
}

alla fine di tutto mi restituisce FreqCounter::f_freq che è dichiarato come UL, quindi io già qui ho perso i decimali o no? In onestà ricordo che nelle prove iniziali avevo provato una float freq a cui assegnavo il valore di FreqCounter::f_freq, ottenendo risultati indesiderati.
Le domande sono due:
1 - devo modificare questa lib per recuperare i decimali o la UL semplicemente li "nasconde" e mi basta cambiare tipo per vederli?
2 - come faccio a passare questo valore alla BigNumber?

@lesto, in svariate prove fatte con SuperLeo siamo arrivati ad usare uint64_t o come si chiama, ma il problema non si è risolto.
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

lestofante

se è UL sei SENZA decimali.

visto che fai tampo/ripetizioni (se non erro) e che questi sono valori facilmente rappresentati senza errori da arduino, crei due BigNumber a partire da questi e poi li dividi.
Code: [Select]

BigNumber::setScale (10); //vogliamo 10 decimali
BigNumber tempo = micros()-tempoIniziale; //okok qè un esempio, lo so che non è così la lib
BigNumber ripetizioni = f_tics; //a naso
BigNumer risulato = tempo/ripetizoni;


facile no?
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

nid69ita


Code: [Select]

BigNumber::setScale (10); //vogliamo 10 decimali
BigNumber tempo = micros()-tempoIniziale; //okok qè un esempio, lo so che non è così la lib
BigNumber ripetizioni = f_tics; //a naso
BigNumer risultato = tempo/ripetizioni;

Ocio solo che la libreria accetta assegnamenti solo da stringhe o da int.
Credo che la 2° riga non funziona , magari tempoIniziale è int ma micros() non ritorna long?
Credo che la 3° riga funziona solo f_tics è int
my name is IGOR, not AIGOR

menniti

Lesto, il tuo ragionamento mi è chiaro, hai estrapolato in un istante il funzionamento della lib :smiley-eek-blue: e lo hai riassunto nei passaggi fondamentali, mi consigli quindi di modificarli secondo il tuo schema; il problema è che io non ho i tuoi raggi X :smiley-sweat:...
Intanto sto studiando.... ho modificato l'esempio in:
Code: [Select]
// BigNumber test: multiplication
#include "BigNumber.h"

void setup ()
{ Serial.begin (9600);
  Serial.println ();
  BigNumber::begin ();  // initialize library
  BigNumber::setScale (5);
  // test multiplication 
  BigNumber a = "564328376.3325";
  BigNumber b = "18254546.2249";
  BigNumber c = a * b;
  Serial.println (c);
}  // end of setup

void loop () { }

e l'ho verificato con la calcolatrice; il metodo funziona, il che significa che non ha alcuna importanza il dover assegnare i valori come stringhe, la BN le operazioni le fa senza problemi.
Quindi in linea teorica mi basterebbe tirar fuori dalla FreqCounter un FreqCounter::f_freq in formato stringa. La domanda da 100bilioni è: e se io dichiarassi questa variabile come string, la lib FC continuerebbe a funzionare o dovrei adeguare altri campi? Possibilmente non vorrei usare la BN all'intenro della FC ma solo nel mio sketch.
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

lestofante

che non ci fossero differenze tra assegnare stringe e numeri è ok.

allora
Code: [Select]
BigNumber::begin ();  // initialize library
  BigNumber::setScale (5);

diventa
Code: [Select]
BigNumber::begin (5);  // initialize library whit 5 decimal digit

Io farei così, visto che nid69ita ha puntalizzato che la BigNumber non accetta numeri diversi da int, ma è facile giurarci attorno, passando per la String o per la fprintf.

Quote
e se io dichiarassi questa variabile come string, la lib FC continuerebbe a funzionare

Sicuramente non funzionaerebbe più, la domanda mi pare un pò banale da parte tua, mi sfugge qualcosa?
Quote
Possibilmente non vorrei usare la BN all'intenro della FC ma solo nel mio sketch.

la BigNumber è lenterrima, quindi per forza va mesas esternamente.

Ora ho scarivato le lib, vedo cosa salta fuorti
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

lestofante

#22
Jul 06, 2013, 01:46 pm Last Edit: Jul 06, 2013, 01:48 pm by lesto Reason: 1
allora, la libreria ritorna il numero di volte qualcosa è successo (f_freq) in f_tics millisecondi.

Quindi a questo punto per ottenere la frequenza devi fare

Hz = f_freq/(1000*f_tics)
oppure più semplice:
kHz = f_freq/f_tics

quindi il codice diviene:

Code: [Select]
// Frequency Counter Lib example

/*
 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/
 Modified by lesto for BigNumber, also some bugfix
*/
#include <FreqCounter.h>
#include <BigNumber.h>


int cnt;
int pinLed=13;

void setup() {
 pinMode(pinLed, OUTPUT);

 Serial.begin(115200);        // connect to the serial port

 Serial.println("Frequency Counter");

 BigNumber::begin(10); //10 decimal precision
}



void loop() {

 Serial.flush();// wait if any serial is going on
 FreqCounter::f_comp=10;   // Cal Value / Calibrate with professional Freq Counter
 
 unsigned long tempoMs = 100;
 FreqCounter::start(tempoMs);  // 100 ms Gate Time

 while (FreqCounter::f_ready == 0){
   ;//do nothing
 }

 unsigned long frq = FreqCounter::f_freq;
 Serial.print(cnt++);
 Serial.print("  Freq: ");
 Serial.print(frq);
 Serial.print("  Tempo: ");
 Serial.print(tempoMs);
 Serial.print("  kHz: ");
 
 char buf[sizeof(unsigned long)*8+1];
 ultoa(frq, buf, 10); //this is what String use, base 10
 BigNumber v = buf;
 ultoa(tempoMs, buf, 10); //this is what String use, base 10
 BigNumber t = buf;
 Serial.print(v/t);

 delay(20);
 digitalWrite(pinLed,!digitalRead(pinLed));  // blink Led

}  
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

PaoloP


menniti

Lesto, non ti sfugge nulla, le mie domande sono banali perché io ho qualche competenza hw, ma sul sw purtroppo sono molto carente, quindi ovvio che spari zzzz; peraltro ho poche occasioni per cimentarmi, e questa non è propriamente una cosa semplice, per quanto mi riguarda.
Riguardo il tuo codice che, a questo punto provo direttamente sull'apparecchio, implementandolo nel mio, ti dò info che servono per capire se va modificato o meno. Tieni presente che :
1 - uso un LCD quindi cambierò tutti i comandi (no problem)
2 - Come f_comp ho già un valore mio (circa = 1000), calcolato per la massima precisione di lettura
3 - Anche per start uso un valore mio (circa = 1000), in pratica faccio una lettura al secondo
4 - Invece f_freq è già un valore espresso in Hz (cicli/secondo), solo che è un UL e quindi non ha decimali (p.es. 2750000 invece di 2749999,25)

Quindi se ho ben capito, ottenuto f_freq dalla FC_lib devo solo eseguire:
Code: [Select]
char buf[sizeof(unsigned long)*8+1];
  ultoa(frq, buf, 10); //this is what String use, base 10
  BigNumber v = buf;
  ultoa(tempoMs, buf, 10); //this is what String use, base 10
  BigNumber t = buf;
  Serial.print(v/t);

ma io ho il dubbio che mi bastino le sole prime due righe, per trasformare f_freq in una stringa con i decimali corretti (2749999,25), da quel momento in poi riprendo il "controllo" del mio firmware usando "v" invece di f_freq e facendo le operazini con la BN_lib. Quindi perché mi vuoi far dividere la frequenza già bell'e pronta per il tempo trascorso per la lettura?
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

lestofante

a me non torna quello che dici.

1. ok, no problem, forse devi litigare un pò per stampare la bigNumber, ma hey, siamo qui :)
2. per f_comp fai tu, io non ho mica capito a cosa serva dal punto di vista HW, anzi per me è un delay "a caso" (son curioso però)
3. start è la durata della lettura in ms
4. ti ASSICURO (il codice ne è la prova) che f_freq NON è la frequenza, ma  "il numero di overflow del comparatore" * "valore di overflow" + "numero di comparazioni a buon fine", effettuata a dine tempo di start.

QUINDI:

SE usi come 3. 1000ms (ovvero 1sec), otterrai kHz = f_freq/f_tics, ovvero kHz = f_freq/1000, e tutto torna, no?
ovviamente, essendo f_freq la somma delle comparazioni a buon fine, è un numero intero per forza (2750000 o 2749999) . Però se alzi il tempo di lettura da 1000 a 4000, otterrai:
f_freq  = 2749999,25 * 4 = 10999997
ora, con la formula avresti:
kHz = 10999997/4000 = 2749,99925


ah, e mi sono sbagliato su
Hz = f_freq/(1000*f_tics)
che ovviamente è
Hz = f_freq/(f_tics/1000)
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

menniti

Il dubbio che mi viene è che probabilmente tu hai ragione ma non per ciò che dici, ma questo è un altro discorso, oggi è giorno di lab e comincio tra poco qualche prova/verità.
f_comp è un fattore di compensazione, hai ragione, è una sorta di delay in microsecondi, serve per compensare il fattore di imprecisione indotto dal circuito e dal sw stesso. Cioè tu leggi quanti cicli avvengono durante il periodo "start" quindi 1 secondo, ma il risultato è inferiore a quello reale, quindi con f_comp non fai altro che allungare il tempo di start; p.es. se start =1000ms e f_comp = 960µs, la durata effettiva della lettura sarà di quasi 1001 msec, quel "quasi" è un fattore di precisione, infatti con start potrei fare 1000 o 1001, invece con f_comp faccio 1000,960.

Io mi fido di ciò che dici, ma l'esempio della lib alla fine mostra come valore di frequenza f_freq, visualizzandolo sul serial monitor e a me i conti tornano; se sul pin 5 applico un segnale di 1000Hz f_freq=1000, evidentemente quella che hai descritto tu è la loro tecnica per calcolare la frequenza, che ne so io.

A questo punto, prima di spiegare il mio dubbio atroce, voglio fare la prova come l'ho pensata io, in caso negativo aggiungo le altre tre righe, se non va nemmeno così avrò purtroppo ragione io... a dopo
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

nid69ita


1. ok, no problem, forse devi litigare un pò per stampare la bigNumber, ma hey, siamo qui :)


La BigNumber deriva da Printable, perciò puoi usarla tranquillamente con Serial.print()
my name is IGOR, not AIGOR

menniti

Lasciando il comando all'interno della routine di calcolo LCD.PRINT funziona senza problemi.
il guaio è che temo di aver ragione io. =(
Ho integrato le linee di Lesto solo che ho usato f_tics invece di TempoMs, perché mi è sembrato molto chiaro dopo la spiegazione.
Esempio: applico un segnale 123794610 Hz, all'ingresso del micro mi arrivano 309486,5 (con strumenti di misura). La Time Base di 1sec rappresenta anche la risoluzione di lettura del firmware, cioè 1Hz; in pratica io, effettuando i numero di cicli in un secondo non vedrò mai quello 0,5; per vederlo dovrei portare la TB a 10 sec, aumentando in tal modo la risoluzione a 0,1Hz; ma questa soluzione l'ho scartata in fase progettuale, volendo usare una sola frequenza di lettura, perché 10 secondi tra una lettura e l'altra sono davvero troppi, e se si considera che a volte servono due-tre letture, ad uno gli prende sonno finché fa la sua misura.
Con il sistema della BigNumber leggo 309486 o 309487, quindi ho comunque un arrotondamento, che devo moltiplicare x400 (sempre tramite BN) e siccome ad ogni lettura mi dà i due valori alternati (ma lo fa anche se, il risultato finale è sempre ±400Hz, con la differenza che ora vedo anche decine e unità di Hz. Ai fini del funzionamento però è preferibile dichiarare una risoluzione sulla 7a cifra (parliamo di misure oltre 100MHz) e non una risoluzione sulla 9a cifra, avendo poi la 7a ballerina.
Quindi tutti i suggerimenti sono perfetti e funzionano, purtroppo il problema è amonte: i decimali non esistono in quanto vengono scartati dalla lettura stessa, successivamente è impossibile recuperarli.
Grazie del supporto ragazzi, comunque questa BigNumbers è davvero eccellente.
Naturalmente non considero conclusa la discussione, sono a disposizione per chiarimenti e altre prove
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

lestofante

giusto per curiosità, se fai le letture di 10 secondi vedi la parte decimale? perchè non ci sioa mai mi sembra un bell'errore.
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

Go Up