Vai al contenuto
PLC Forum


Contatori veloci


roberto8303

Messaggi consigliati

NO, con ndx <<= i; non legge gli ingressi 12 e 13 anche se il codice sarebbe poi matematicamente corretto, forse ci sono problemi di latenza nel simulatore o chissà...

 

Lo so che gli ultimi due bit sono per il quarzo, infatti mica li voglio leggere, io sto parlando dei 5 inclusi nell'intervallo...

 

Uso SIMULINO con Proteus, fino ad oggi (latenza a parte), tutte le simulazioni sono andate a buon fine, se poi @roberto8303 ha deciso di seguire un metodo diverso, allora Amen!!!

 

Io ho solo segnalato a te quanto riscontrato, so che ci tieni ad essere preciso, inoltre se qualche lettore copiasse il codice, si ritroverebbe spiazzato anche se lo hai definito da prendere con i guanti...:thumb_yello:

Link al commento
Condividi su altri siti


  • Risposte 127
  • Created
  • Ultima risposta

Top Posters In This Topic

  • roberto8303

    56

  • ilguargua

    32

  • Livio Orsini

    26

  • GiRock

    9

6 minuti fa, GiRock scrisse:

NO, con ndx <<= i; non legge gli ingressi 12 e 13 anche se il codice sarebbe poi matematicamente corretto, forse ci sono problemi di latenza nel simulatore o chissà...

E cambiando porta , leggendo tipo la C? A logica dovrebbe essere uguale, se ti va di provare...

 

9 minuti fa, GiRock scrisse:

inoltre se qualche lettore copiasse il codice, si ritroverebbe spiazzato anche se lo hai definito da prendere con i guanti...:thumb_yello:

:thumb_yello: Concordo al 1000% !

 

Ciao, Ale.

Link al commento
Condividi su altri siti

5 ore fa, roberto8303 scrisse:

il 74hc14 é possibile alimentarlo con i 5 volt di arduino nano?

 

Si

3 ore fa, roberto8303 scrisse:

comunque pensandoci al fatto che il7414 lavora al contrario non saprei come modificare il mio programma perchè è una libreria che utilizza il pin di arduino e campiona l ingresso al livello alto

 

Se c'è un livello alto che ne è anche uno basso. Se gli impulsi sono simmetrici invertendo il segnale hai solo u ritardo di 90° costanti. Differente il caso se sono asimmetrici, dipende da quanto riman e alto il segnale dopo l'inverter. nel caso puoi scegliere o di raddoppiare le negazioni mettendo in cascata 2 stadi, o di usare un buffer non invertente, so che c'è anche l'ex trigger non invertente solo che non ricordo a memoria la sigla.

Link al commento
Condividi su altri siti

1 ora fa, GiRock scrisse:

stesso identico funzionamento su PORTC e PORTD, su PORTC non funziona neanche la mia modifica...

Grazie, a questo punto se trovo il tempo faccio qualche prova "dal vivo", giusto perchè sono curioso.

 

Ciao, Ale.

Link al commento
Condividi su altri siti

1 ora fa, GiRock scrisse:

Ci sono il 4010 ed il 4050 che sono Non Invertenti...

Ma non schmitt triggers... che in effetti non invertenti sembrano essere rari. C'è il 7014 o il più noto 74LS244, che è un 3 state line buffer quindi bisogna ricordarsi di abilitare le uscite. Anche abbastanza ingombrante con i suoi 20 pin (per 8 buffers).

 

Ciao, Ale.

Link al commento
Condividi su altri siti

 

 

Scusa ilgargua, perchè complicarsi le cose? basta scrivere le cose in modo elementare.

Ad ogni interrupt di timer si legge lo stato degli ingressi con un semplice digitalRead(x), se è "1" si confronta con la memoria dello stato precedente, se è diversa significa che l'ingresso è passato da 0 a 1, si incrementa il contatore corrispondente e si memorizza lo stato attuale nella memoria; si ripete la sequenza 5 volte senza fare nessun loop con indici e altro. Si scrive un poco più di codice ma la velocità di esecuzione è maggiore e risulta più semplice da capire 8anche in caso di errori).

 

Il codice non lo riporto volutamente ma io questa funzione la uso, in asm, PLM, PAscal, "C" e VB con vari micro da almeno 30 anni per farci i debouncing degli ingressi, con la differenza che incece di testare la differenza testo l'eguaglianza.

Link al commento
Condividi su altri siti

Pensa che a pochi chilometri da casa mia e da quella di Livio vendono il 4050, mentre dei tuoi purtroppo nessuna traccia in provincia :superlol::

 

CD4050

 

Diciamo che esistono in commercio, è che si usano molto di raro, solitamente tutti usano il 40106 o siimilari mettendo due stadi in cascata...

Link al commento
Condividi su altri siti

Caspita @ilguargua, ci hai preso veramente per sprovveduti senza nessuna esperienza???

 

E' vero che ogni tanto si può incorrere in qualche inesattezza involontaria, ma non è che siamo uscito di casa proprio ieri con decorrenza a domani!!!

Link al commento
Condividi su altri siti

31 minuti fa, Livio Orsini scrisse:

Ad ogni interrupt di timer si legge lo stato degli ingressi con un semplice digitalRead(x), se è "1" si confronta con la memoria dello stato precedente, se è diversa significa che l'ingresso è passato da 0 a 1, si incrementa il contatore corrispondente e si memorizza lo stato attuale nella memoria; si ripete la sequenza 5 volte senza fare nessun loop con indici e altro.

E' quello che fa il codice che ho postato, solo che per ottimizzare, anzichè fare 5 digitalRead() leggo una sola volta la porta. E' una soluzione che in realtà non mi è mai capitato di usare, ma mi da l'impressione che possa essere più veloce, ma non ho riscontri pratici. L'ho postata proprio perchè speravo venisse commentata e criticata. Appena posso faccio qualche test e posto i risultati.

 

Ciao, Ale.

Link al commento
Condividi su altri siti

3 minuti fa, GiRock scrisse:

Caspita @ilguargua, ci hai preso veramente per sprovveduti senza nessuna esperienza???

 

Vabbè via, mi metto da solo in ginocchio sui ceci....:worthy:

 

4 minuti fa, GiRock scrisse:

Pensa che a pochi chilometri da casa mia e da quella di Livio vendono il 4050, mentre dei tuoi purtroppo nessuna traccia in provincia :superlol::

Perché siete, appunto, provinciali...  :) se cerchi da chi li vende li trovi, poi di 74ls244, 74ls245 e 74ls374 ne ho letteralmente cassetti strapieni da roba di recupero (poi, come la solito ne avrò usato si e no 1...:superlol:)

 

Ciao, Ale.

Link al commento
Condividi su altri siti

chiedo scusa ma il cd4050 va bene?cioe è non invertente? posso entrare con il positivo ed esce positivo?

allora ho simulato il pezzo da leggere cioe un perno di ferro e l albero come diametro in linea di massima. Ho alimentato momentaneamente il sensore a 24vdc e all oscilloscopio il segnale sembra bello pulito, perchè nella pratica devo aspettarmi delle sorprese? da cosa puo dipendere dalla tensione di alimentazione del sensore "sporca"...?

image-23-01-18-19-10-1.jpeg

image-23-01-18-19-10.jpeg

Link al commento
Condividi su altri siti

25 minuti fa, GiRock scrisse:

Si devi stare attento alla B finale CD4050B, se è UB è invertente pure lui...

Dove l'hai trovato 'sto dettaglio , mi sembra senza logica :huh:

Link al commento
Condividi su altri siti

chiedo scusa ma siccome non li ho mai utilizzati ma se invece del sensore pnp utilizzo un npn e poi il trigger invertente non mi ritroverei con il positivo su arduino?

Link al commento
Condividi su altri siti

13 ore fa, roberto8303 scrisse:

allora ho simulato il pezzo da leggere cioe un perno di ferro e l albero come diametro in linea di massima.

 

Roberto visto il segnale è meglio che lo inverti perchè è rettangolare ed è molto stretto. Dato che leggi gli "1" se lo inverti hai più tempo per leggerlo, quindi maggior sicurezza.

13 ore fa, ilguargua scrisse:

E' quello che fa il codice che ho postato, solo che per ottimizzare, anzichè fare 5 digitalRead() leggo una sola volta la porta.

 

Sembra più veloce perchè metti una riga, però se vai a vedere cosa fa la macchina è più lento perchè deve eseguire una reiterazione di istruzioni, quindi deve eseguire confronto e salto, oltre alla lettura.

Sarà perchè io ho iniziato a programmare quando si scrivevano i programmi in asm, se andava bene, altrimenti in codice macchina, che tutte queste cose mi son rimaste "in automatico".

Poi però bisognerebbe vedere cosa fa in realtà la piattaforma Arduino, come Java traduce le righe di pseudo "C" in codice macchina.

Comunque facendo le 5 letture risulta più comprensibile e facilmente debaggabile, almeno a mio giudizio

Link al commento
Condividi su altri siti

Allora, ho trovato il tempo di fare qualche prova. Ho usato 2 Arduino nano , 1 per generare 5 treni di impulsi a frequenze diverse e 1 per la lettura.

Questo è il codice del generatore :

#include <MsTimer2.h>

byte outs[5] = {9,10,11,12,13};

void t2isr(void)
{
  static unsigned long cnt = 1;
  static unsigned long stops[5] = {0,0,0,0,0};
  for(byte i=0;i<5;i++)
  {
    if( stops[i] == cnt) digitalWrite(outs[i],LOW);
  }
  for(byte i=15;i<40;i+=5)
  {
    if( cnt % i == 0)
    {
      digitalWrite(outs[(i/5)-3],HIGH);
      stops[(i/5)-3] = cnt + (i/10);
    }
    
  }
  cnt++;
}



void setup() {
  // put your setup code here, to run once:
  for(byte i=9;i<14;i++) pinMode(i,OUTPUT);
  MsTimer2::set(1,t2isr);
  MsTimer2::start();

}

void loop() {
  // put your main code here, to run repeatedly:

}

Gli impulsi vengono generati ogni 15/20/25/30/35 millisecondi, con durata di circa 1/10 del periodo (la granularità è a 1 ms)

Ho capito perché il codice postato non leggeva (giustamente)  i bit 4 e 5, l'ho corretto e questo è il risultato :

#include <MsTimer2.h>

volatile int rpms[5] = {0,0,0,0,0};
volatile int cnt = 1;
char buf[40];
volatile unsigned long diff = 0;

void t2isr(void)
{
  static byte prev_pb = 0;
  unsigned long st = micros();
  byte pb = PINB & B00111110;
  pb >>= 1;
  byte ndx=1;
  for(byte i=0;i<5;i++)
  {
    if(pb & ndx && !(prev_pb & ndx)) rpms[i]++;
    ndx <<= 1;
  };
  cnt++;
  prev_pb = pb;   
  diff = micros() - st;       
}


void t2isr_2(void)
{
  static bool prev_state[5] = {LOW,LOW,LOW,LOW,LOW};
  unsigned long st = micros();
  bool t ;
  for(byte i=0;i<5;i++)
  {
    t = digitalRead(9+i); 
    if( t && ! prev_state[i])
    {
      rpms[i]++;
    }
    prev_state[i] = t;
  }  
  cnt++;
  diff = micros() - st;       
}

void setup() {
  // put your setup code here, to run once:
  for(byte i=0;i<5;i++) pinMode(9+i, INPUT);
  Serial.begin(9600);
  MsTimer2::set(5,t2isr);
  MsTimer2::start();

}

void loop() {
  // put your main code here, to run repeatedly:
  if(cnt == 200)
  {
    MsTimer2::stop();
    snprintf(buf,40,"1:%i 2:%i 3:%i 4:%i 5:%i",rpms[0] * 60,
                                               rpms[1] * 60,
                                               rpms[2] * 60,
                                               rpms[3] * 60,
                                               rpms[4] * 60);
    for(byte i=0;i<5;i++) rpms[i]=0;
    cnt=1;
    MsTimer2::start();
    Serial.println(buf);
    Serial.println(diff);
  }
  }

L'output del monitor seriale (usando la lettura diretta della porta) :

1:3960 2:3000 3:2400 4:1920 5:1620
8
1:4020 2:3000 3:2400 4:1980 5:1620
8
1:3960 2:3000 3:2400 4:1980 5:1560
12
1:3960 2:2940 3:2340 4:1980 5:1620
8
1:4020 2:3000 3:2400 4:2040 5:1560
12
1:3960 2:3000 3:2400 4:1920 5:1620
8
1:3960 2:3000 3:2400 4:1980 5:1620
8

Questo invece con digitalRead() :

1:3540 2:3000 3:2400 4:2040 5:1680
28
1:3480 2:3000 3:2400 4:1980 5:1740
28
1:3540 2:2940 3:2400 4:1980 5:1680
28
1:3540 2:3000 3:2400 4:1980 5:1740
28
1:3540 2:3000 3:2400 4:2040 5:1680
28
1:3600 2:3000 3:2400 4:1980 5:1740
28
1:3480 2:3000 3:2400 4:1980 5:1740
28

Per il secondo caso ho dovuto anche modificare la frequenza del timer, portandolo ad 1 ms, altrimenti la prima lettura rimaneva sempre a zero.

Come si evince dai dati, usare digitalRead() rispetto alla lettura diretta della porta comporta il triplicarsi (circa) dei tempi di esecuzione.

 

Ciao, Ale.

Link al commento
Condividi su altri siti

Scusa ma questa prova, così come l'hai fatta, non è significativa.

Per fare una misura corretta bisogna alzare un segnale all'inizio della procedura e riabbassarlo immediatamente al termine (o viceversa). Misurando la durata dello stato a "1", o a zero, si determina esattamente il tempo occorrente all'elaborazione. L'uso di timer e scrittura seriale fa commettere molti errori di misura e non è detto che gli errori siano comunque eguali.

Poi hai fatto uso di loop anche quando hai usato i digitalRead. Il risparmo di tempo si ha nel non fare loops.;)

Link al commento
Condividi su altri siti

2 ore fa, Livio Orsini scrisse:

Poi hai fatto uso di loop anche quando hai usato i digitalRead. Il risparmo di tempo si ha nel non fare loops.;)

Provato anche facendo l'unroll del loop, il risultato non cambia. Si, che il test non è troppo significativo me ne rendo conto, comunque le condizioni sono le stesse con entrambe le opzioni, quindi un termine di raffronto ci sta.

 

Ciao, Ale.

Link al commento
Condividi su altri siti

@ilguargua hai usato un simulatore??? :whistling:

 

Ti dico questo perché i valori simulati sono identici ai tuoi, guarda tu stesso:

 

1:3900 2:3000 3:2400 4:1980 5:1680
8
1:3960 2:3000 3:2400 4:1980 5:1680
12
1:3900 2:3000 3:2400 4:1980 5:1680
8
1:3960 2:2940 3:2400 4:1980 5:1680
12
1:3960 2:3000 3:2340 4:1980 5:1680
12
1:3900 2:3000 3:2400 4:1980 5:1680
12
1:3960 2:3000 3:2400 4:1920 5:1680
8
1:3960 2:3000 3:2400 4:1980 5:1620
12
1:3960 2:2940 3:2400 4:1980 5:1680
8
1:3900 2:3000 3:2400 4:1980 5:1680
8


//////////////////////////////////


1:3960 2:3000 3:2400 4:1980 5:1680
28
1:3900 2:3000 3:2400 4:1980 5:1680
32
1:3960 2:2940 3:2400 4:1980 5:1680
32
1:3960 2:3000 3:2340 4:1980 5:1680
32
1:3960 2:3000 3:2400 4:1980 5:1680
32
1:3900 2:3000 3:2400 4:1920 5:1680
32
1:3960 2:3000 3:2400 4:1980 5:1620
32
1:3960 2:2940 3:2400 4:1980 5:1680
28
1:3900 2:3000 3:2400 4:1980 5:1680
32

 

Penso che la funzione digitalRead faccia più o meno questo:

 

digitalRead(X); // qui c'è una Call

byte digitalRead(byte X) { // funzione digitalRead
  
  byte v = PIN(X); // Legge lo stato dei PIN di PORTX

  v >>= (X - OFFSETPORT); // OFFSETPORT calcolato dal precompilatore

  v &= 0x01; // ottiene il valore sul pin X

  return v; // ritorna il valore del pin X
  
}


In effetti ci sono circa 4us in più per ogni chiamata:

 

(5 * 4) + 8 = 28us
(5 * 4) + 12 = 32us

 

quindi a rigore di logica, meglio leggere la porta in un colpo solo piuttosto che 5 volte, lo shift e l'and dei byte è un'operazione rapida da meno di 1/2us e non porta via tempo prezioso, l'unica incriminata è davvero la Call a questo punto, probabilmente salva lo stato dei registri per poi ripristinarli perciò perde altro tempo prezioso, bisognerebbe fare una tabella con tutti i tempi delle varie operazioni da mettere bene in vista qui sul Forum...

 

 

P.S. Ho trovato pure io l'errore, quel maledetto ndx<<=i; non c'entrava proprio... :superlol:

Link al commento
Condividi su altri siti

Crea un account o accedi per commentare

Devi essere un utente per poter lasciare un commento

Crea un account

Registrati per un nuovo account nella nostra comunità. è facile!

Registra un nuovo account

Accedi

Hai già un account? Accedi qui.

Accedi ora

×
×
  • Crea nuovo/a...