generare una sequenza di bit a frequenza variabile

@ astrobed:
sei un pozzo di scienza! mi sono riguardato quest'argomento su un testo di calcolatori, giusto per "fissarlo" con qualche esempio, spieghi meglio tu di Bucci!
@ lesto e leo72:
grazie per la soluzione ed i ragguagli: oggi la provo, riguardo la precisione, non devo realizzare uno strumento di lettura, bensì convertire il periodo in frequenza, in realtà mi basterebbero addirittura i soli interi (11364 (Hz), p.es., se poi ottengo un valore con 3 cifre decimali, e mi dite che sono abbastanza significative, ho fatto molto più di quanto mi serve. Vi ricordo che alla fine devo solo capire con che frequenza "indicativa" si ripete la sequenza che sto generando.
Certo questa disquisizione tornerà utilissima quando sarà necessaria, in altri casi, una lettura precisa, ma un buon frequenzimetro di rado mostra oltre le 5 cifre decimali, quindi hai voglia ad accontentarsi!
Infine mi sono reso conto di un errore a monte: per ottenere la frequenza in Hz devo prima rapportare i µs in s, quindi devo dividere seq_time per 1000000, poiché stiamo parlando di KHz, in realtà mi basta rapportarli a ms, dividendo per 1000. Pensavo quindi di fare:
Serial.println((float)1)/seq_time/1000;
il dubbio che ho: il solo float iniziale mi rende tutta l'espressione in virgola mobile? Inoltre vorrei far uscire tutto sulla stessa riga con l'indicazione della parola "frequenza" e l'unità di misura, penso mi basti "giocare" con , e ;
Proverò oggi e vi faccio sapere come va a finire. Intanto inizio a fare qualche prova con uno shift da 8 bit ed un dip, in attesa dell'uovo di pasqua di uwe :slight_smile:
Grazie a tutti.

Premesso che l'unico modo semplice per ottenere quello che desideri è usare degli shift register con ingresso seriale e uscita sia seriale che parallela (SIPO shift register) per ottenere un ring shift register della desiderata dimensione, però c'è un punto oscuro da risolvere prima di disegnare lo schema.
La frequenza di 10 MHz è riferita al singolo bit del pacchetto che devi trasmettere oppure è la frequenza di ripetizione di tutto il pacchetto ?

In effetti c'era confusione su questa cosa, poi mi sono chiarito le idee, e da lì è nata la discussione sulla misura della frequenza. I 10MHz riguardano la velocità alla quale devono essere "sparati" i singoli bit in seriale, considerando che sono una trentina (circa, come ho già spiegato) credo che l'intera sequenza si ripeta ogni 300-350KHz, quindi il clock sarà di 10MHz. Poiché carichiamo in seriale ad una velocità decisamente inferiore, bisognerebbe prima caricare lo shift e poi renderlo circolare (serve a questo la sezione parallela?), l'eventuale cambio sequenza per me rappresenta una prova ex novo.
Aspetto aiuti. Grazie.

menniti:
Serial.println((float)1)/seq_time/1000;

a parte che è sbagliata per via della parentesi del println che si chiude prima delle divisioni (quindi in pratica stampi 1 in float e poi provi a dividere una funzione, credo che il compilatore si incavoli un pò :slight_smile:

al solito... se non erro il compilatore, in caso di pari priorità degli operatori, parte da DESTRA.
quindi prima fa seq_time/1000
e poi 1/quelchel'è
come vedi però hai perso precisione per la storia degli interi nella /1000, quindi o usi i cast o fai 1000.0

per evitare mille parentesi e cast inutili (che vengono fatti a runtime, se non erro, facendo perdere qualche ciclo CPU) fai:
Serial.println( 1.0/seq_time/1000.0 );
e vai sicuro

Ho risolto così:
Serial.print("Tempo della sequenza: ");
Serial.print(seq_time);
Serial.print("Frequenza (KHz): ");
Serial.println(1.0/(seq_time/1000.0));
quindi l'operazione viene fatta regolarmente da sx verso dx (se non metto le () alla 2a divisione mi dà 0.
Ma il risultato è con 2 decimali, ne volevo almeno 3, probabilmente non ho capito qualcosa nella discussione precedente. :~

I due decimali sono un limite della serial.println, in realtà il numero ha tutti i decimali del caso, per vederne di più moltiplica il valore per 10-100-1000 e poi fai la serial.println, ovviamente dovrai riposizionare mentalmente la virgola.
Esempio pratico se faccio 7/3 ottengo 2.33 se moltiplico per 1000 la variabile che contiene il risultato ottengo 2333.33

Come non detto, mi sono appena ricordato che basta specificare dopo la virgola il numero dei decimali desiderati, se scrivo Serial.println(a,4) e a contiene 32.12345 mi viene inviato 32.1234.

Perfetto, ora funziona bene; speriamo che troviate anche il tempo di aiutarmi col circuito esterno.
Grazie

Per il momento prendilo come schema di principio, è una cosa che ho buttato giù al volo, ma dovrebbe andare bene.
Le tre linee in ingresso se lasciate a 1 logico fanno funzionare lo ring shift register come serve a te, portando Enable a 0 logico viene bloccato sia il clock a 10 MHz che il ricircolo dei dati, ogni volta che mandi un impulso negativo sulla linea clock il valore presente su DATA viene trasferito all'interno dello shift register, attenzione che vengono negati quindi o lo prevedi da software oppure aggiungi un inverter.
Fornendo 30 impulsi sul clock carichi completamente lo shift register, è possibile variare la lunghezza del pacchetto modificando l'out per il ricircolo dati.
Gli shift register sono dei 54HC4094 (oppure 74HC4094) da 8 bit l'uno, le porte logiche sono contenute in un singolo 54HC00, l'oscillatore è del tipo quarzato ibrido, ma puoi metterci quello che ti pare.

WOW! alla faccia del "volo"!
Allora alcuni chiarimenti: per caricare lo shift con i miei 30 impulsi da Arduino, visto che devo farne passare uno per volta, mi conviene abilitare un altro pin che porto a 0 prima di ogni bit della sequenza, e che collego all'ENABLE, dopo lo porto a 1, e così via; dopo il 30mo impulso devo però bloccare il loop, non potrei mettere il code sotto SETUP invece che sotto loop? In questo modo potrei tenere ENABLE a 0 per l'intera durata del ciclo oppure funziona su fronte e quindi serve proprio l'impulso?
Con questa tipologia di schema posso decidere di variare i bit della sequenza (avendo necessità di un range 25-32) semplicemente scegliendo una delle uscite Q1 (4) ÷ Q8 (11)? Potrei usare un dip commutando un solo pin per volta verso l'OUT.
Infine, per fare alcune prove oggi, dispongo di due comunissimi cd4094, di un cd4011 (nand, anche se con pinatura delle porte leggermente diversa), di un generatore di funzioni a 10MHz (ma penso che i CMOS non reggano questa frequenza, potrei provare a 1MHz); il dubbio che ho è se questi componenti possono andar bene per una simulazione con sequenza a 16 bit (o meno) e se i livelli logici dell'Arduino vengono riconosciuti dalle porte CMOS.
Che dici?
Grazie di tutto, mi hai fatto davvero un grande regalo!

menniti:
dopo il 30mo impulso devo però bloccare il loop, non potrei mettere il code sotto SETUP invece che sotto loop? In questo modo potrei tenere ENABLE a 0 per l'intera durata del ciclo oppure funziona su fronte e quindi serve proprio l'impulso?

Sarà che oggi ho la testa un pochino sconfusionata da un bel raffreddore, ma non ti seguo :slight_smile:
Il software su Arduino deve seguire una logica di questo tipo:
Nel setup inizializzi tutti i vari pin come serve.
All'interno del loop dovrai attendere un evento che causa il cambio sequenza, dato che non hai specificato come questo avviene posso solo ipotizzare che lo fai a intervalli fissi di tempo oppure tramite uno specifico comando premendo un pulsante o un carattere che arriva dalla seriale.
Comunque sia non devi fare altro che aspettare l'evento, cioè inserisci un controllo, e quando questo avviene chiami la funzione che genera l'eventuale sequenza random, oppure specifichi un array precaricato in memoria che contiene la sequenza, oppure la ricevi dalla porta seriale, dopo di che chiami la funzione che la carica nello shift register.
La funzione che carica la sequenza non deve fare altro che eseguire queste operazioni partendo dal presupposto che le tre linee di controllo, ENABLE, DATA, CLOCK, si trovano tutte quante 1 logico durante il normale funzionamento dello shift register:

  1. portare ENABLE a 0 logico
  2. mettere su DATA il valore caricare prelevandolo dall'array che contiene la sequenza.
  3. Portare CLOCK da 1 a 0
  4. Attendere 10us
  5. Portare CLOCK da 0 a 1
  6. Ripetere dal punto 2 per tante volte quanti sono i bit da caricare.
  7. Riportare DATA, CLOCK, ENABLE a 1 logico per riavviare lo shift register.

In pratica nella funzione che carica la sequenza usi una for(i=0;i<n;i++) ove n è il numero dei bit da caricare.

Con questa tipologia di schema posso decidere di variare i bit della sequenza (avendo necessità di un range 25-32) semplicemente scegliendo una delle uscite Q1 (4) ÷ Q8 (11)? Potrei usare un dip commutando un solo pin per volta verso l'OUT.

Si, in teoria puoi avere da 2 a 32 bit, basta che cambi il bit usato per il ricircolo e per l'out.

Infine, per fare alcune prove oggi, dispongo di due comunissimi cd4094, di un cd4011 (nand, anche se con pinatura delle porte leggermente diversa), di un generatore di funzioni a 10MHz (ma penso che i CMOS non reggano questa frequenza, potrei provare a 1MHz)

Direi che hai tutto quello che serve, la massima frequenza di lavoro dipende dalla serie, se sono i vecchi CD4xxx sarà difficile che arrivi oltre i 5 MHz, però per provare va bene lo stesso.

il dubbio che ho è se questi componenti possono andar bene per una simulazione con sequenza a 16 bit (o meno) e se i livelli logici dell'Arduino vengono riconosciuti dalle porte CMOS.

Anche se le soglie di tensione per 1 e 0 sono leggermente diverse tra l'ATmega e i CMOS della serie CD4xxx non dovrebbero esserci problemi.

Non è il raffreddore, sono io...
Dunque la parte elettronica ora mi è chiara. I problemi sono sulla parte Arduino (ancora non ci ho capito molto, come ben vedi!)
Il mio sistema deve funzionare in modo semplice e manuale:
Carico il code su Arduino, lo invio al tuo circuito, stop, a quel punto il tuo circuito dovrebbe vivere di vita propria e l'altro che ho realizzato (il riconoscitore di sequenze) legge i dati provenienti da esso e mi avvisa quando riconosce una delle sequenze che sto cercando; quindi non ho comandi automatici da mandare o controllare; la sequenza la imposto su Arduino e mi vale per tutta la sperimentazione; se decido di cambiarla semplicemente rimando il code ad Arduino e tutto ricomincia daccapo. Spero di essere stato più chiaro così. :astonished:
Ho provato a tradurre le tue indicazioni

#define DATA 12
#define ENABLE 13
#define CLOCK 7
byte sequenza[] = {
  1, 1, 1, 0, 1, 1, 0, 0};

void setup() {                
  pinMode(DATA, OUTPUT);  // attivo le uscite
  pinMode(ENABLE, OUTPUT);
  pinMode (CLOCK, OUTPUT);
  digitalWrite(ENABLE, LOW); //blocco tutto
  digitalWrite(DATA, LOW);
  digitalWrite(CLOCK, LOW);
}

void loop() 
{
  for(int i=0; i<8; i++)  //ciclo per 8 bit
  {
    digitalWrite(ENABLE, LOW); 
    digitalWrite(DATA, sequenza[i]);
    digitalWrite(CLOCK, LOW);
    delay (10);
    digitalWrite(CLOCK, HIGH);
  }
  digitalWrite(ENABLE, HIGH); //riavvio tutto
  digitalWrite(DATA, HIGH);
  digitalWrite(CLOCK, HIGH);
}

Il mio dubbio è che in questo stesso thread mi hano spiegato che ciò che è nella sezione loop si ripete all'infinito, ma questo mi creerebbe problemi; io vorrei eseguire tutto una sola volta in modo da non "disturbare" più il tuo circuito. Mi spieghi come fare e soprattutto se quando ho postato è corretto?

Meglio così :slight_smile:

#define DATA 12
#define ENABLE 13
#define CLOCK 7
byte sequenza[] = {
  1, 1, 1, 0, 1, 1, 0, 0};

void setup() {                
  pinMode(DATA, OUTPUT);  // attivo le uscite
  pinMode(ENABLE, OUTPUT);
  pinMode (CLOCK, OUTPUT);
  digitalWrite(ENABLE, LOW); //blocco tutto
  digitalWrite(DATA, HIGH);
  digitalWrite(CLOCK, HIGH);
}

void loop() 
{
  digitalWrite(ENABLE, LOW); // fermi ciclo shift
 
 for(int i=0; i<8; i++)  //ciclo per 8 bit
  {
    digitalWrite(DATA, sequenza[i]);
    digitalWrite(CLOCK, LOW);
    delay (10);
    digitalWrite(CLOCK, HIGH);
  }

  digitalWrite(ENABLE, HIGH); //riavvio tutto
  digitalWrite(DATA, HIGH);
  digitalWrite(CLOCK, HIGH);

  while(1);  // loop infinito e blocca il ciclo.

}

Naturalmente....
Grazie di tutto, ormai devo lasciare il mio angolo di pace (ho un piccolo lab fuori casa :D) e tornare alla cruda realtà (moglie, mutuo, ecc =(), posso continuare a gironzolare sul forum, ma per le prove ormai se ne parla nei prox giorni; naturalmente appena ho finito il mini-circuito posto i risultati, poi realizzerò quello completo con i componenti che mi hai indicato. Siete stati tutti davvero molto disponibili, a te un ringraziamento particolare per non avermi mandato un virus della rabbia invece del circuito...mi armerò della tua pazienza prima di rientrare :wink:

Carissimo Astrobeed,
funziona alla grande! Per il momento ho testato con due soli cd4094 e un cd4011, in configurazione "full", cioè sfruttando tutti i 16 bit, in quanto prelevo dal pin 9 del secondo Shift; in effetti la frequenza max è di 3MHz, ma dipende dai cmos, come prevedibile.
Confermando quanto dicevi lo stato dei bit è invertito, poiché non ho porte disponibili mi "secca" mettere un inverter nel circuito finale, poiché mi viene scomodo "ragionare" al contrario per inserire la sequenza, ho pensato di invertirla via soft; mi sembrava una cosa facile :astonished: col seguente codice:

for(int k=0; k<16; k++)
{ if (sequenza [k] == 0)
(sequenza [k] = 1);
else
(sequenza [k] = 0);
}

invece non funziona per niente :. mi trasforma la sequenza in un'altra che non c'entra niente, ho fatto decine di prove (ho provato a metterla sia in setup che in loop ma non cambia nulla); comunque se non riesco metto l'inverter, però mi pare davvero una cosa banale, dove sbaglio?
In ogni caso moltissime grazie, già solo questo problema risolto mi vale l'acquisto dell'Arduino.

Anche se hai scelto il modo più "macchinoso" per farlo mi sembra corretto, prova a inserire queste righe di codice in setup:

for(int k=0; k<16; k++)
   {
      sequenza[i] ^= 1;
   }

Eseguire l'Xor con 1 di un valore logico lo inverte e viene usata una singola istruzione assembler.

Ciao, al momento sono senza PC nel lab e non posso provare, in ogni caso ho realizzato l'oscillatore a 10MHz con 3 nand, uso il 4° per invertire il segnale, ma comunque voglio risolverlo il problema, ti faccio sapere al più presto.
Intanto ho serie difficoltà a trovare il 5/74hc4094, hai un riferimenti in italia? mi pare eccessivo ordinare all'estero; a questo punto integrerei con altro materiale.
In alternativa potrei usare il più semplice (anche se concuma un po' più corrente) 74ls91 o altro similare? non ha le uscite parallele, ma a questo punto a me basta il dip per selezionare 8-16-24 bit.
Vorrei inoltre sapere se, una volta inviata la sequenza e caricati gli shift, è possibile memorizzare lo status in modo da non perdere tutto allo spegnimento. L'idea è questa: collego lo schedino (già realizzato) all'Arduino, lo programmo con la sequenza che mi serve, memorizzo la stato dei bit, spengo tutto e mi porto il solo schedino, senza necessità di pc e arduino.
Forse potrei mettere proprio il micro di Arduino, ma non so se sia conveniente e se sia fattibile senza tutta la circuiteria dell'ArduinoUno.
Peraltro ho fatto finalmente un po' di prove sul campo ed in realtà con 24 bit ce la faccio, infatti ho previsto 3 shift.
Potresti aiutarmi ancora, sempre che la cosa non ti faccia perdere troppo tempo?
Grazie

Io i componenti elettronici li compro solo da Digikey o da Mouser, hanno praticamente tutto a stock, prezzi ottimi, spedizione gratuita se si acquista più di 70 Euro, magazzini in Europa quindi niente sorprese di dogana e lunghe attese, di solito la merce arriva dopo 2-3 giorni lavorativi dall'ordine.
Non è possibile memorizzare la sequenza sugli shift register, se togli l'alimentazione va persa, una alternativa è realizzare un sistema totalmente stand alone, sullo stesso pcb metti anche un ATmega 328 col relativo quarzo, ogni volta che accendi il tutto come prima cosa carica la sequenza, volendo puoi usare dei dip switch per impostarne un certo numero a scelta, 8 dip switch ti permettono di selezionare fino a 256 diverse sequenze.
Il cambio di sequenza lo puoi fare quando ti pare, imposti il nuovo valore e premi reset, oppure temporizzato, ogni tot secondi/minuti la sequenza cambia da sola.
Per cambiare le sequenze memorizzate basta riprogrammare l'ATmega.
Una curiosità, a cosa ti serve questa sequenza ad una frequenza così elevata ?

Ho cercato di capire come funziona il quote, non ho idea di quale sia il risultato, speriamo bene... :blush:

Io i componenti elettronici li compro solo da Digikey o da Mouser, hanno praticamente tutto a stock, prezzi ottimi, spedizione gratuita se si acquista più di 70 Euro, magazzini in Europa quindi niente sorprese di dogana e lunghe attese, di solito la merce arriva dopo 2-3 giorni lavorativi dall'ordine.

Allora stasera mi metto alla ricerca di queste Aziende, ma una spesa di 70 euro non saprei davvero come raggiungerla e se è inferiore mi sa che mi costa più il trasporto del poco che mi serve. Ho a disposizione questi TTL della serie 74LS: 91 (ma solo 1pz), 164, 299; pensavo di poter usare uno di questi tipi al posto del 4094, ma non capisco se c'è o meno corrispondenza di logica. :~

Non è possibile memorizzare la sequenza sugli shift register, se togli l'alimentazione va persa, una alternativa è realizzare un sistema totalmente stand alone, sullo stesso pcb metti anche un ATmega 328 col relativo quarzo, ogni volta che accendi il tutto come prima cosa carica la sequenza, volendo puoi usare dei dip switch per impostarne un certo numero a scelta, 8 dip switch ti permettono di selezionare fino a 256 diverse sequenze.
Il cambio di sequenza lo puoi fare quando ti pare, imposti il nuovo valore e premi reset, oppure temporizzato, ogni tot secondi/minuti la sequenza cambia da sola.
Per cambiare le sequenze memorizzate basta riprogrammare l'ATmega.

Quello che intendevo dire era memorizzare gli stati degli shift su qualcosa tipo una o più prom da aggiungere al circuito, ma penso sia complicato. Mi pare molto più semplice l'idea dell'ATmega 328 + quarzo + pulsante reset; invece la programmazione la farei sempre da Arduino (immagino mettendo l'ATMega al posto di quello di serie), il cambio sequenza devo farlo periodicamente e non frequentemente. Ma tecnicamente mi basta aggiungere l'AT, collegare il quarzo, un pulsante reset, l'alimentazione ed i pin che mi servono ed è fatta? in caso contrario potresti darmi un chiarimento maggiore? :~

Una curiosità, a cosa ti serve questa sequenza ad una frequenza così elevata ?

All'Università abbiamo un macchinario in laboratorio che legge dei dati cerebrali e li manda sotto forma numerica o grafica ad un PC, ha inoltre la possibilità di inviarli sotto forma di lunghissime sequenze binarie, lavora a circa 10MHz in uscita; parte del nostro lavoro consiste nel verificare la periodicità di dati che non sempre conosciamo a priori. Ho realizzato diversi riconoscitori di sequenze base, ma probabilmente ricorrerò ad Arduino anche per questa operazione. Mi serve simulare in modo più realistico possibile questa uscita per fare le prove nel mio piccolo lab, tutto qui. Come vedi stai rendendo un servizio alla Scienza :), naturalmente si opera a livello gratuito, purtroppo, ma con la scusa unisco lavoro e passione per l'elettronica (ma a livello di logica digitale di base, come avrai ormai capito, oltre ci siete tu e gli altri "mostri" di questo forum :D)
Un'ultima cosa: ma c'è modo di allargare questo quadro dei post che mi fa impazzire :0 ogni volta che scrivo troppo, o è fatto apposta? :~
Grazie per il grande aiuto, fino a qualche giorno fa mi sembravaimpossibile fare questa cosa....

ciao menniti

Altri fornitori veloci, ma non sempre a miglior prezzo sono distrele.it e it.rs-online.com e sono sicuro che forniscono anche a privati. Distrelec e RS forniscono su specificazione anche materiale di cataloghi di altri paesi. (RS c'é in tantissimi paesi. distrelec anche in Germania o Austria con una gamma di prodotti maggiori.
Altro fornitore, ma Ti serve partita IVA é farnell.it

Non Ti ho piú risposto perché astrobeed Ti ha fornito uno schema funzionante simile a quello che pensavo di fare io.

Ciao Uwe