Shifting IN e Shifting OUT [Sto impazzendo!]

Salve community,

sono 2 giorni che tento inutilmente senza successo, di utilizzare gli shift in ed out...
incomincio:
ho 2 cd4021 messi in cascata, con data > D2, latch > D3, clock > D4.
a questi ci sono collegati: al primo cd4021 8 pulsanti, più le resistenze di pull down (10k) su ogni ingresso, e sul secondo 6 interruttori, più resistenze di pull down...
in una subroutine che ho chiamato readshiftin(), dovrei vedere lo stato di ogni pulsante e interruttore, che se premuto (o chiuso), deve fare una determinata azione, modificare una variabile booleana, oppure incrementare una variabile intera, ecc...
ma dopo una marea di codici che ho testato, non ho avuto successo...

stessa cosa per i 74hc595 (sempre 2 in cascata) con data > D10, latch > D11, clock > D12.
a questi ci sono collegati 16 leds ed un transistor npn bc337 con resistenza di base da 150ohm.
vorrei gestire i leds ed il transistor, in modo indipendente, ovvero cambiare una sola uscita, senza intaccare le altre... (con un array (byte), sarebbe semplice, ma non ci sono riuscito -.- in quanto nell'istruzione shiftout devi mettere una variabile byte, o una sola variabile dell'array)

ho trovato qualche codice, ma anche qui non ho avuto fortuna... :frowning:

chiedo cortesemente il vostro aiuto per risolvere questi problemi.

Ciao!
UP2

dacci il codice che hai provato

Comunque se metti 2 in cascata non puoi mettere i DATA in paralello ma devfi mettere Din in cascata col Dout
Hai messo resistenze in serie a LED?

Ciao Uwe

Per i 595 aiutati con questo tutorial:

Per i CD4021 invece guarda qua:

Ricorda comunque di mettere le resistenze di pulldown su tutti gli ingressi, anche di quelli che non usi

vorrei gestire i leds ed il transistor, in modo indipendente, ovvero cambiare una sola uscita, senza intaccare le altre... (con un array (byte), sarebbe semplice, ma non ci sono riuscito -.- in quanto nell'istruzione shiftout devi mettere una variabile byte, o una sola variabile dell'array)

Usa un unica variabile a 16 bit che rappresenta le singole uscite degli shift register, ad esempio:

uint16_t PORTS        = 0x0000;

Quando vuoi cambiare una uscita (senza intaccare le altre) usi la tecnica del bitwise.
Ad esempio:

 PORTS |= (1 << 2);    // ON - mette a "1" il bit n.2, che corrisponde alla terza uscita degli SR (uscite numerate da 1 a 16)
 PORTS &= ~(1 << 2);  // OFF - mette a "0" il bit n.2, che corrisponde alla terza uscita degli SR (uscite numerate da 1 a 16)

Puoi più opportunamente definire delle costanti che rappresentino le uscite per una maggiore chiarezza di codice:

#define LED0   0
#define LED1   1
....
#define BJT    15

Ad ogni modifica di PORTS invii la variabile agli SR con una routine tipo:

void sendToShiftReg() {
    digitalWrite(SR_LATCH, LOW);
    shiftOut(SR_DATA, SR_CLOCK, MSBFIRST, highByte(PORTS)); 
    shiftOut(SR_DATA, SR_CLOCK, MSBFIRST, lowByte(PORTS));
    digitalWrite(SR_LATCH, HIGH);    
}

@uwe, leo e pelletta, ho usato le guide descritte sia per i collegamenti (uwe certamente ho collegato il din col dout, non hanno il data in comune, e certamente i diodi leds hanno ognuno una resistenza da 330ohm in serie), sia per i primi tests, ma poi ho creato codici di testa mia, basandomi su quel pò di teoria di elettronica digitale fatta quest'anno a scuola, anche se senza risultati... (ed ho anche scoperto, che le funzioni shiftin e shiftout, utilizzavano un codice con un ciclo molto simile a quello che avevo pensato io...)

@dalubar: non ci ho capito molto su quello che hai scritto, e non ho capito soprattutto, come associare i define dei leds al codice riportato... ti chiederei, di essere un po più clemente, e spiegarmi meglio come fare, grazie

ringrazio tutti per le risposte! :slight_smile:

P.S. il code lo posto domani, perchè c'è l'ho nell'altro pc...

grazie ancora
UP2

Ciao ragazzi scusate se mi intrometto ma la cosa interessa anche me,

shiftOut(SR_DATA, SR_CLOCK, MSBFIRST, highByte(PORTS));
shiftOut(SR_DATA, SR_CLOCK, MSBFIRST, lowByte(PORTS));

nella prima riga dello shiftOut,con highByte(PORTS) si inviano gli otto bit più significativi che compongono la variabile unit_16 PORTS,di conseguenza con lowByte(PORTS) si inviano gli otto bit meno significativi,ho capito bene o dico una fesseria? Grazie

@ultra:
si tratta di manipolazione diretta dei bit di una variabile.
Se le cose ti sembrano difficili, lascia perdere per ora e cerca di far funzionare il circuito nel modo a te più congeniale e comprensibile. In un secondo tempo ti studierai i bit e la manipolazione degli stessi. :wink:
http://arduino.cc/en/Reference/Bit

non ci ho capito molto su quello che hai scritto

XD
Allora, cerco di spiegarmi meglio. Il concetto è quello di associare ognuna delle 16 uscite degli Shift Register (SR) ad uno specifico bit di una variabile denominata PORTS. Supponendo che stai collegando 16 LED numerati da 1 a 16, allora potresti definire qualcosa di simile:

#define LED1     0
#define LED2     1
#define LED3     2
............
#define LED16   15

In questo modo, quando vuoi accendere (o spegnere) un particolare LED puoi usare direttamente il suo nome. Se il codice che ho postato ti sembra troppo complicato allora puoi usare le comode e semplici istruzioni bitSet() e bitClear().
Quindi, ad esempio, se vuoi accendere il led 5 puoi scrivere semplicemente:

  bitSet(PORTS, LED5);

mentre se vuoi spegnere il led 1:

  bitClear(PORTS, LED1);

Quando hai finito le modifiche invii PORTS agli SR con la funzione che ti ho scritto.
Nota che nella natura intrinseca degli shift register, il bit inviato per PRIMO si trovera nell'ULTIMA uscita, ecco perchè si inviano prima i bit più significativi e poi quelli meno significativi.

Sono stato più chiaro, adesso? :stuck_out_tongue_closed_eyes:

@leo e dalubar, molte grazie, adesso ho capito tutto :slight_smile:
@dalubar sapevo che il primo bit inviato va all'ultima uscita dell'ultimo shift =)

comunque, resta il problema per gli shiftin, i codici che ho usato sono questi:
code1 (basato su questo http://arduino.cc/en/Tutorial/ShftIn12)

 digitalWrite(latchin,1);
  delayMicroseconds(20);
    digitalWrite(latchin,0);
shiftin1 = shiftIn(datain, clockin);
  shiftin2 = shiftIn(datain, clockin);
for (int n=0; n<=7; n++)
  {
   
    if (shiftin1 & (1 << n) ){
     switch(n){
    case 0:
    block3=false;
    break;
    case 1:
    block2=false;
    break;
    case 2:
    block1=false;
    break;
    case 3:
    if (block3==false && manual==true){
    if (start3 == true){
      start3=false;
      }else{
        start3=true;
        }
        }else {
          start3=false;
          }
          break;
          case 4:
          if (block2==false && manual==true){
    if (start2 == true){
      start2=false;
      }else{
        start2=true;
        }
        }else {
          start2=false;
          }
          break;
          case 5:
          if (block1==false && manual==true){
    if (start1 == true){
      start1=false;
      }else{
        start1=true;
        }
        }else {
          start1=false;
          }
          break;
          case 6:
        
    if (manual == true){
      manual=false;
      }else{
        manual=true;
        }
          break;
    }
    }
  }
  for (int n=0; n<=7; n++)
  {
    //so, when n is 3, it compares the bits
    //in switchVar1 and the binary number 00001000
    //which will only return true if there is a 
    //1 in that bit (ie that pin) from the shift
    //register.
    if (shiftin2 & (1 << n) ){
      //print the value of the array location
      //Serial.println(note2sing[n]);
    }
  }
   
  delay(500);

poi ho provato con questo:

for (int x=15; x >=0; x--){
    digitalWrite(clockin,LOW);
    if (digitalRead(datain)==HIGH) {
  switch(x){
    case 0:
    block3=false;
    break;
    case 1:
    block2=false;
    break;
    case 2:
    block1=false;
    break;
    case 3:
    if (block3==false && manual==true){
    if (start3 == true){
      start3=false;
      }else{
        start3=true;
        }
        }else {
          start3=false;
          }
          break;
          case 4:
          if (block2==false && manual==true){
    if (start2 == true){
      start2=false;
      }else{
        start2=true;
        }
        }else {
          start2=false;
          }
          break;
          case 5:
          if (block1==false && manual==true){
    if (start1 == true){
      start1=false;
      }else{
        start1=true;
        }
        }else {
          start1=false;
          }
          break;
          case 6:
    if (manual == true){
      manual=false;
      }else{
        manual=true;
        }
          break;
    }
    
    }
    }
    digitalWrite(clockin,HIGH);
     delay(200);

e poi ho provato con un code basato su questo http://arduino.cc/en/Tutorial/ShftIn23, k però ho cancellato :confused:

e non ho avuto successo con nessuno u.u
P.S.
@pelletta, gli ingressi che non uso sono collegati a gnd
ciao
UP2

Una domanda: ma ciò che leggi è ciò che devi fare? Ossia, c'è una corrispondenza fra gli ingressi e le uscite?
Se è così potresti semplicemente spedire in uscita i 2 byte letti in ingresso per cui se ad esempio 1 bit in ingresso va alto, lo mandi in uscita per attivare il corrispondente dispositivo (led, relè ecc..).

c'è una corrispondenza, ma i button mi servono anche per altro...

comunque, finalmente sono riuscito a far funzionare gli shiftin, anche se non mi spiego 2 cose

  1. perchè l'ingresso 6 (piedino n°15) del 4021, ha come indice 0? l'ingresso 7 (piedino 1) che indice avrà?
  2. perchè cliccando i pulsanti, a volte è come se non li clicchi, ovvero non viene registrato il passaggio di stato?

ecco il code:

boolean getBit(byte myVarIn, byte whatBit) {
  boolean bitState;
  bitState = myVarIn & (1 << whatBit);
  return bitState;
}
void readshiftin() {
  digitalWrite(latchin,1);
  delayMicroseconds(20);
    digitalWrite(latchin,0);
 shiftin1 = shiftIn(datain, clockin);
  shiftin2 = shiftIn(datain, clockin);
 if (getBit(shiftin1, 6)) {
   block3=false;
  }
  if (getBit(shiftin1, 5)) {
   block2=false;
  }
  if (getBit(shiftin1, 4)) {
   block1=false;
  }
  if (getBit(shiftin1, 3)) {
  if (block3==false && manual==true){
    if (start3 == true){
      start3=false;
      }else{
        start3=true;
        }
        }else {
          start3=false;
          }
  }
  if (getBit(shiftin1, 2)) {
   if (block2==false && manual==true){
    if (start2 == true){
      start2=false;
      }else{
        start2=true;
        }
        }else {
          start2=false;
          }
  }
  if (getBit(shiftin1, 1)) {
    if (block1==false && manual==true){
    if (start1 == true){
      start1=false;
      }else{
        start1=true;
        }
        }else {
          start1=false;
          }
  }
  if (getBit(shiftin1, 0)) {
   if (manual == true){
      manual=false;
      start1=false;
      start2=false;
      start3=false;
      digitalWrite(m1, LOW);
      digitalWrite(m2, LOW);
      digitalWrite(m3, LOW);
      }else{
        manual=true;
        }
  }
delay(20);
}

ciao
UP2

Il piedino 15 è denominato P7, non è il 6° ingresso, è l'7°, dato che la numerazione va da P1 a P8. Se parliamo di "posizione" del bit che lo indica, allora è il 6° bit.

  1. perchè cliccando i pulsanti, a volte è come se non li clicchi, ovvero non viene registrato il passaggio di stato?

Probabilmente è un problema di bounce, cioè di "rimbalzo" elettrico del pulsantino. Prova effettuando 2 letture distanziate di 30 ms e poi prendi per buone solo quelle che in entrambi i casi sono risultate HIGH.

@leo, anch'io credo sia un problema di bounce, grazie della risposta, proverò...

per quanto riguarda il cd4021 il p7 nella funzione getbit, ha come indice 0, il p6 ha indice 1, il p1 ha indice 6, il p8 che indice avrà? 7? non ho provato perchè in entrambi gli shift l'ho cortocircuitato col gnd, in quanto non lo uso, ma era per un chiarimento...

Non ho usato i 4021 ma mi pare un problema di cablaggio, perché generalmente i pin nei registri a scorrimento corrispondono ai bit interni.

beh problemi di cablaggio non credo...
comunque grazie di tutto