utilizzo corretto shift register

Ciao a tutti,

volevo chiedere un chiarimento su di un mio progetto. Seguendo il tutorial https://www.arduino.cc/en/tutorial/ShiftOut ho costruito un piccolo circuito con uno shift register che mi permette di gestire 8 uscite sfruttando solo 3 pin di Arduino UNO.

Il tutto funziona benone e per richiamare le uscite utilizzo le variabili byte. Ad esempio per attivare:

OUT1 = 0b11111110
OUT2 = 0b11111101
OUT3 = 0b11111011
OUT4 = 0b11110111
...
...
OUT8 = 0b01111111

attivo le uscite con il codice

shiftOut(UscitaDatoSeriale, DataClock, LSBFIRST, OUT1);

PRIMA DOMANDA
Se io volessi attivare ad esempio contemporaneamente OUT1 che OUT2 dovrò fare:

shiftOut(UscitaDatoSeriale, DataClock, LSBFIRST, OUT1+OUT2+1);

Se io volessi attivare ad esempio contemporaneamente OUT1, OUT2 e OUT3 dovrò fare:

shiftOut(UscitaDatoSeriale, DataClock, LSBFIRST, OUT1+OUT2+OUT3+2);

Se io volessi attivare ad esempio contemporaneamente OUT1, OUT2, OUT3 e OUT4 dovrò fare:

shiftOut(UscitaDatoSeriale, DataClock, LSBFIRST, OUT1+OUT2+OUT3+OUT4+3);

Cosi funziona tutto, ma esistono metodi più eleganti?

SECONDA DOMANDA

se voglio espandere le uscite da 8 a 16 basta ampliare il circuito come segue:


ma in tal caso come posso richiamare solamente le uscite 9, 10, 11, 12, 13, 14, 15, 16? quale indirizzo in byte dovrei utilizzare??

Vi ringrazio in anticipo

Usa la manipulazione diretta dei Bit della variablie byte.
Se non ti senti di farlo con un AND e OR logico allora usa la funzione bitset()
https://www.arduino.cc/en/Reference/BitSet

Ciao Uwe

uwefed:
Usa la manipulazione diretta dei Bit della variablie byte.
Se non ti senti di farlo con un AND e OR logico allora usa la funzione bitset()
https://www.arduino.cc/en/Reference/BitSet

Ciao Uwe

Grazie per la risposta ma perdonami, non mi è molto chiaro cosa intendi :slight_smile:

max95:
Il tutto funziona benone e per richiamare le uscite utilizzo le variabili byte. Ad esempio per attivare:

OUT1 = 0b11111110

...
OUT8 = 0b01111111



attivo le uscite con il codice

Questo è già anomalo. Con quello schema i LED si dovrebbero accendere con uscita alta, quindi trasmettendo il valore 0b11111110 si dovrebbero accendere tutti i LED tranne quello pilotato dal bit meno significativo, che usando la modalità LSBFIRST esce sul pin Q7 dello shift register (il primo bit che entra scorre fino all'uscita più lontana). Per accendere solo Q7 si dovrebbe trasmettere il valore 0b00000001

Se io volessi attivare ad esempio contemporaneamente OUT1 che OUT2 dovrò fare:

shiftOut(UscitaDatoSeriale, DataClock, LSBFIRST, OUT1+OUT2+1);

Per attivare contemporaneamente Q6 e Q7 dello shift register bisognerebbe trasmettere il valore 0b00000011

se voglio espandere le uscite da 8 a 16 basta ampliare il circuito come segue:
...
ma in tal caso come posso richiamare solamente le uscite 9, 10, 11, 12, 13, 14, 15, 16? quale indirizzo in byte dovrei utilizzare??

Vanno trasmessi sempre due byte. I bit del primo byte trasmesso usciranno sullo shift register più lontano. Ad esempio trasmettendo prima il valore 0b10000010 e poi 0b00101000 si devono accendere i LED corrispondenti a Q0/Q6 del registro in basso (il più lontano da Arduino) e Q2/Q4 del registro in alto (il più vicino).

Claudio_FF:
Questo è già anomalo. Con quello schema i LED si dovrebbero accendere con uscita alta, quindi trasmettendo il valore 0b11111110 si dovrebbero accendere tutti i LED tranne quello pilotato dal bit meno significativo, che usando la modalità LSBFIRST esce sul pin Q7 dello shift register (il primo bit che entra scorre fino all'uscita più lontana). Per accendere solo Q7 si dovrebbe trasmettere il valore 0b00000001

Chiedo scusa, ho omesso che utilizzo una scheda 16 relay che attiva la bobina quando ho 0V in uscita

Claudio_FF:
Vanno trasmessi sempre due byte. I bit del primo byte trasmesso usciranno sullo shift register più lontano. Ad esempio trasmettendo prima il valore 0b10000010 e poi 0b00101000 si devono accendere i LED corrispondenti a Q0/Q6 del registro in basso (il più lontano da Arduino) e Q2/Q4 del registro in alto (il più vicino).

Ecco, anche io avevo capito questo... ma evidentemente sbaglio qualcosa. Quindi ho provato con le cose semplici: direttamente sul tutorial presente sul portale arduino... e anche li non mi tornano molte cose:

//**************************************************************//
//  Name    : shiftOutCode, Predefined Dual Array Style         //
//  Author  : Carlyn Maw, Tom Igoe                              //
//  Date    : 25 Oct, 2006                                      //
//  Version : 1.0                                               //
//  Notes   : Code for using a 74HC595 Shift Register           //
//          : to count from 0 to 255                            //
//****************************************************************

//Pin connected to ST_CP of 74HC595
int latchPin = 7;
//Pin connected to SH_CP of 74HC595
int clockPin = 5;
////Pin connected to DS of 74HC595
int dataPin = 6;

//holders for infromation you're going to pass to shifting function
byte dataRED;
byte dataGREEN;
byte dataArrayRED[10];
byte dataArrayGREEN[10];

void setup() {
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  Serial.begin(9600);

  //Arduino doesn't seem to have a way to write binary straight into the code 
  //so these values are in HEX.  Decimal would have been fine, too. 
  dataArrayRED[0] = 0xFF; //11111111
  dataArrayRED[1] = 0xFE; //11111110
  dataArrayRED[2] = 0xFD; //11111101
  dataArrayRED[3] = 0xFB; //11111011
  dataArrayRED[4] = 0xF7; //11110111
  dataArrayRED[5] = 0xEF; //11101111
  dataArrayRED[6] = 0xDF; //11011111
  dataArrayRED[7] = 0x7F; //10111111
  dataArrayRED[8] = 0x00; //00000000
  dataArrayRED[9] = 0xE0; //11100000

  //Arduino doesn't seem to have a way to write binary straight into the code 
  //so these values are in HEX.  Decimal would have been fine, too. 
  dataArrayGREEN[0] = 0xFF; //11111111
  dataArrayGREEN[1] = 0x7F; //01111111
  dataArrayGREEN[2] = 0xBF; //10111111
  dataArrayGREEN[3] = 0xDF; //11011111
  dataArrayGREEN[4] = 0xF7; //11110111
  dataArrayGREEN[5] = 0xFB; //11111011
  dataArrayGREEN[6] = 0xFD; //11111101
  dataArrayGREEN[7] = 0xFE; //11111110
  dataArrayGREEN[8] = 0x00; //00000000
  dataArrayGREEN[9] = 0x07; //00000111

  //function that blinks all the LEDs
  //gets passed the number of blinks and the pause time
//  blinkAll_2Bytes(2,500); 
}

void loop() {


  
    dataRED = dataArrayRED[1];
    dataGREEN = dataArrayGREEN[0];
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, dataRED);   
    shiftOut(dataPin, clockPin, dataGREEN);
    digitalWrite(latchPin, 1);
    delay(1000);
    
}



// the heart of the program
void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
  // This shifts 8 bits out MSB first, 
  //on the rising edge of the clock,
  //clock idles low

  //internal function setup
  int i=0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, OUTPUT);

  //clear everything out just in case to
  //prepare shift register for bit shifting
  digitalWrite(myDataPin, 0);
  digitalWrite(myClockPin, 0);

  //for each bit in the byte myDataOut�
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights. 
  for (i=7; i>=0; i--)  {
    digitalWrite(myClockPin, 0);

    //if the value passed to myDataOut and a bitmask result 
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000 
    // and proceeds to set pinState to 1.
    if ( myDataOut & (1<<i) ) {
      pinState= 1;
    }
    else {  
      pinState= 0;
    }

    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(myDataPin, pinState);
    //register shifts bits on upstroke of clock pin  
    digitalWrite(myClockPin, 1);
    //zero the data pin after shift to prevent bleed through
    digitalWrite(myDataPin, 0);
  }

  //stop shifting
  digitalWrite(myClockPin, 0);
}


//blinks the whole register based on the number of times you want to 
//blink "n" and the pause between them "d"
//starts with a moment of darkness to make sure the first blink
//has its full visual effect.
void blinkAll_2Bytes(int n, int d) {
  digitalWrite(latchPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  digitalWrite(latchPin, 1);
  delay(200);
  for (int x = 0; x < n; x++) {
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, 255);
    shiftOut(dataPin, clockPin, 255);
    digitalWrite(latchPin, 1);
    delay(d);
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, 0);
    shiftOut(dataPin, clockPin, 0);
    digitalWrite(latchPin, 1);
    delay(d);
  }
}

Le variabili chiave sono:

    dataRED = dataArrayRED[1];
    dataGREEN = dataArrayGREEN[0];

Problemi:

Se cambio dataArrayRED da 0 a 7 mi si attivano i "led rossi" e anche i "led verdi" corrisponedenti (1 rosso = 1 verde, 2 rossi = 2 verde,....)

Se dataArrayGREEN da 0 a 7 va in palla tutto e si attivano casualmente rossi e verdi....

dove sto sbagliando?