Hello I got an old circuit card I need to create an small code for to confirme its still is working.
It has 3 Parallel output and 6 parallel load shift registers connected in serial together.
I need to write to the 3 first parallel shift registers then read from the next 6 shift registers.
Is there an easy way using an arduino to do this?
I found a way to read, but not read and write at the same time.
Ref. image added that shows how its connected together.
What have you found. Technically speaking, you do not do both at the same time.
You write to the first 3 registers until the final pin of the 3rd is triggered and then you read from the registers 1 by one. Does what you read depend on what you have written, or could you read first and write after ?
Maybe you should separate the trigger for the 74HC165 from the QH of the 74HC164 and use a separate pin for that.
On spliting it up is not possible this is how the circuit card is designed. It cant be changed.
Its and 15-20 year old card.
Read.
const byte latchPin = 9; // to latch the inputs into the registers
const byte clockPin = 13; // I choose the SCK pin
const byte dataPin = 12; // I choose the MISO pin
uint32_t oldOptionSwitch = 0; // previous state of all the inputs
const int pulseWidth = 10; // pulse width in microseconds
void setup ()
{
Serial.begin( 115200);
Serial.println( "Turn on and off the switches");
Serial.println( "Top row is switch 0 (right) to switch 7 (left)");
Serial.println( "Second row is 8 to 15, and so on");
pinMode( clockPin, OUTPUT); // clock signal, idle LOW
pinMode( latchPin, OUTPUT); // latch (copy input into registers), idle HIGH
digitalWrite( latchPin, HIGH);
}
void loop ()
{
// Give a pulse to the parallel load latch of all 74HC165
digitalWrite( latchPin, LOW);
delayMicroseconds( pulseWidth);
digitalWrite( latchPin, HIGH);
// Reading one 74HC165 at a time and combining them into a 32 bit variable
// The last 74HC165 is at the bottom, but the switches start numbering
// at the top. So the first byte has to be shifted into the highest place.
uint32_t optionSwitch = 0;
for( int i=24; i>=0; i-=8)
{
optionSwitch |= ((uint32_t) ReadOne165()) << i;
}
for( int i = 0; i<32; i++)
{
if( bitRead( optionSwitch, i) != bitRead( oldOptionSwitch,i))
{
Serial.print( "Switch ");
if( i < 10)
Serial.print( " ");
Serial.print( i);
Serial.print( " is now ");
Serial.println( bitRead( optionSwitch, i) == 0 ? "down ↓" : "up ↑");
}
}
oldOptionSwitch = optionSwitch;
delay( 25); // slow down the sketch to avoid switch bounce
}
// The ReadOne165() function reads only 8 bits,
// because of the similar functions shiftIn() and SPI.transfer()
// which both use 8 bits.
//
// The shiftIn() can not be used here, because the clock is set idle low
// and the shiftIn() makes the clock high to read a bit.
// The 74HC165 require to read the bit first and then give a clock pulse.
//
byte ReadOne165()
{
byte ret = 0x00;
// The first one that is read is the highest bit (input D7 of the 74HC165).
for( int i=7; i>=0; i--)
{
if( digitalRead( dataPin) == HIGH)
bitSet( ret, i);
digitalWrite( clockPin, HIGH);
delayMicroseconds( pulseWidth);
digitalWrite( clockPin, LOW);
}
return( ret);
}
const byte latchPin = 9; // to latch the inputs into the registers
const byte clockPin = 13; // I choose the SCK pin
const byte dataPin = 12; // I choose the MISO pin
uint32_t oldOptionSwitch = 0; // previous state of all the inputs
const int pulseWidth = 10; // pulse width in microseconds
void setup ()
{
Serial.begin( 115200);
Serial.println( "Turn on and off the switches");
Serial.println( "Top row is switch 0 (right) to switch 7 (left)");
Serial.println( "Second row is 8 to 15, and so on");
pinMode( clockPin, OUTPUT); // clock signal, idle LOW
pinMode( latchPin, OUTPUT); // latch (copy input into registers), idle HIGH
digitalWrite( latchPin, HIGH);
}
void loop ()
{
// Give a pulse to the parallel load latch of all 74HC165
digitalWrite( latchPin, LOW);
delayMicroseconds( pulseWidth);
digitalWrite( latchPin, HIGH);
// Reading one 74HC165 at a time and combining them into a 32 bit variable
// The last 74HC165 is at the bottom, but the switches start numbering
// at the top. So the first byte has to be shifted into the highest place.
uint32_t optionSwitch = 0;
for( int i=24; i>=0; i-=8)
{
optionSwitch |= ((uint32_t) ReadOne165()) << i;
}
for( int i = 0; i<32; i++)
{
if( bitRead( optionSwitch, i) != bitRead( oldOptionSwitch,i))
{
Serial.print( "Switch ");
if( i < 10)
Serial.print( " ");
Serial.print( i);
Serial.print( " is now ");
Serial.println( bitRead( optionSwitch, i) == 0 ? "down ↓" : "up ↑");
Serial.println(optionSwitch, BIN);
}
}
oldOptionSwitch = optionSwitch;
delay(250); // slow down the sketch to avoid switch bounce
}
// The ReadOne165() function reads only 8 bits,
// because of the similar functions shiftIn() and SPI.transfer()
// which both use 8 bits.
//
// The shiftIn() can not be used here, because the clock is set idle low
// and the shiftIn() makes the clock high to read a bit.
// The 74HC165 require to read the bit first and then give a clock pulse.
//
byte ReadOne165()
{
byte ret = 0x00;
// The first one that is read is the highest bit (input D7 of the 74HC165).
for( int i=7; i>=0; i--)
{
if( digitalRead( dataPin) == HIGH)
bitSet( ret, i);
digitalWrite( clockPin, HIGH);
delayMicroseconds( pulseWidth);
digitalWrite( clockPin, LOW);
}
return( ret);
}
That works fine.
Only thing to do now is to find out how to add the rest.
I found out the last 4 ICs are on a seperat card. so can test by itself. but not the mix of 165 and 164 on the first card.
If you compare the timing diagrams of the HC164 and the HC595 (datasheets from Diodes Incorporated), you'll notice that both work the same except the HC164 doesn't have an output latch. If it works for the '595, it will work for the '164.
Now, i'd like to comment on your code:
The only binaryNumber = stringBinary.toInt(); that is necessary is the 8th one, all previous ones store data in a variable that won't be used before it is overwritten.
When assigning the same value to several variables, use the result instead of calling the function again and again:
You should "clean" your variables before using them, not after. Besides, only stringBinary needs cleaning.
Considering all these, your function should be:
uint8_t data = 0b00000001; // data is an unsigned 8-bit integer (a byte) with value 0x01
data = data << 2; // The content of data has been shifted 2 bits to the left
// its value is now 0b00000100 or 0x04
In your case:
void ReadSwitchesU1() {
uint8_t data = digitalRead(SW1);
data = (data << 1) + digitalRead(SW2);
data = (data << 1) + digitalRead(SW3);
data = (data << 1) + digitalRead(SW4);
data = (data << 1) + digitalRead(SW5);
data = (data << 1) + digitalRead(SW6);
data = (data << 1) + digitalRead(SW7);
data = (data << 1) + digitalRead(SW8);
dataArrayToFGC[0] = data;
}
Wokwi on that:
Now, if you declare your pins in an array, the code can be:
// Pin connected to ST_CP of 74HC595/164
int latchPin = 8;
// Pin connected to SH_CP of 74HC595/164
int clockPin = 12;
// Pin connected to DS of 74HC595/164
int dataPin = 11;
// Clear 164 output
int Clear = 9;
// holders for information you're going to pass to shifting function
byte dataRED;
byte dataGREEN;
byte dataYELLOW;
// Data to FGC Controller
byte dataToFGCU1;
byte dataToFGCU2;
byte dataToFGCU3;
byte dataArrayToFGC[4];
// Switches
enum : uint8_t {U1, U2, U3}; // U1 = 0, U2 = 1, U3 = 2
const int U_SW[][8] = {
{ 7, 6, 5, 4, 3, 2, 22, 23}, // dataArrayYELLOW
{24, 25, 26, 27, 28, 29, 30, 31}, // dataArrayGREEN
{32, 33, 34, 35, 36, 37, 38, 39} // dataArrayRED
};
// Switches to binary/hex converter
int bitVal;
String stringBit;
String stringBinary;
long binaryNumber;
int decimalNumber;
void setup()
{
// set pins to output because they are addressed in the main loop
pinMode(latchPin, OUTPUT);
digitalWrite(latchPin, LOW);
pinMode(Clear, OUTPUT);
digitalWrite(Clear, LOW); // Set low to sett 164 to LOW out. Set HIGH to receiver data.
dataArrayToFGC[0] = 0x00; // U1
dataArrayToFGC[1] = 0x00; // U2
dataArrayToFGC[2] = 0x00; // U3
Serial.begin(115200);
}
void loop()
{
ReadSwitches(U1);
Serial.print("U1 data: ");
Serial.print(dataArrayToFGC[U1], HEX);
ReadSwitches(U2);
Serial.print(" ");
Serial.print("U2 data: ");
Serial.print(dataArrayToFGC[U2], HEX);
ReadSwitches(U3);
Serial.print(" ");
Serial.print("U3 data: ");
Serial.println(dataArrayToFGC[U3], HEX);
// set latch pin Low
digitalWrite(latchPin, LOW);
digitalWrite(Clear, HIGH);
// send data to 595/
shiftOut(dataPin, clockPin, dataArrayToFGC[U1]); // Yellow Lights
shiftOut(dataPin, clockPin, dataArrayToFGC[U2]); // Green Light
shiftOut(dataPin, clockPin, dataArrayToFGC[U3]); // Red Light
// return the latch pin high to signal chip that it
// no longer needs to listen for information
digitalWrite(latchPin, HIGH);
digitalWrite(Clear, LOW);
delay(200); // only show to see LED data.
}
// 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, LOW);
digitalWrite(myClockPin, LOW);
// 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, LOW);
// 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, HIGH);
// zero the data pin after shift to prevent bleed through
digitalWrite(myDataPin, LOW);
}
// stop shifting
digitalWrite(myClockPin, LOW);
}
void ReadSwitches(uint8_t switchesRow) {
uint8_t data = 0;
for (uint8_t switchIndex = 0; switchIndex < sizeof(U_SW[switchesRow]) / sizeof(*U_SW[switchesRow]); switchIndex++) {
data = (data << 1) + digitalRead(U_SW[switchesRow][switchIndex]);
}
dataArrayToFGC[switchesRow] = data;
}
and the relevant Wokwi:
As it's now late, I didn't use a for() statement in the main loop but it would be relevant...