is it necessary to connect all 32 LEDs (solenoids) to the 32 outputs of the registers in order to get the code working right?
No the code will work anyway.
The code always works. Whether it does what you want is another matter.
void outputBytes(){
Is totally wrong.
shiftOut(data, clock, MSBFIRST, dataValues);
shifts out all 8 bits of data.
It is in a for loop that does it 8 times, so that is 64 bits you are outputting.
Then each time through the loop you do this:-
dataValues = dataValues << 1; // Shift the bits one place to the left
I don't live on the arduino reservation, I don't know $^*@ from libraries and I can live without "shields". It's a nice platform, but you can go your own way, and I do.
I think that the Latch should be kept low. When it's desired to transfer the data to the storage register then the Latch should be brought high and right back low (ting, ting.)
Here is some code that I wrote early on while working out my display board's programming. The orthodoxy may get loud and chide me for not using "shiftOut", and that's OK (I just don't want to.)
Maybe it'll confuse you more than help.
I used different pins for datapin, clockpin, and latchpin.
So, for what it's worth (hold your cat calls) ?
byte infobyte = 0; // byte to "shiftout" ! ! !
byte idxbit = 0; // indexed bit to mask out
byte infobit = 0;
const int datapin = 3; // to IC p14
const int clockpin = 5; // to IC p11
const int latchpin = 7; // to IC p12
void setup()
{
pinMode(datapin, OUTPUT);
pinMode(clockpin, OUTPUT);
pinMode(latchpin, OUTPUT);
digitalWrite(datapin, LOW);
digitalWrite(clockpin, LOW);
digitalWrite(latchpin, LOW);
}
void loop()
{
idxbit = 0;
infobyte = B01010101;
while (idxbit <= 7)
{
shiftroutine();
}
latchcycle();
// ---0---0---0---0---0---
idxbit = 0;
infobyte = B10101010;
while (idxbit <= 7)
{
shiftroutine();
}
latchcycle();
// ---0---0---0---0---0---
idxbit = 0;
infobyte = B11000011;
while (idxbit <= 7)
{
shiftroutine();
}
latchcycle();
// ---0---0---0---0---0---
idxbit = 0;
infobyte = B00111100;
while (idxbit <= 7)
{
shiftroutine();
}
latchcycle();
// ---0---0---0---0---0---
}
void clocktoggle()
{
digitalWrite(clockpin, HIGH);
digitalWrite(clockpin, LOW);
}
void latchcycle()
{
digitalWrite(latchpin, HIGH);
digitalWrite(latchpin, LOW);
delay(500); // *** this is the dwell time ***
}
void shiftroutine()
{
infobit = bitRead(infobyte, idxbit);
digitalWrite(datapin, infobit);
clocktoggle();
idxbit++;
}
I have working code here: 404 Error
(it's a directory, the source is thermo.c)
This is not Arduino source code, however, only the code which outputs a char (or byte)
is hardware dependent. You only need to replace this routine with Arduino code.
If you can read C language, then here you have a working example,
shifting out 24 bits, 8 at a time.
/* code for sending data to 4 shift register which are daisy chained together
MOSI goes to Serial In on chip 1 (pin 14), Q7/ (pin 9) goes to Serial In on chip 2, etc.
SCK goes to ShiftClock on all 4 devices (pin 11)
ss goes to RegisterClock on all 4 devices (pin 12)
SerialClear (pin 10) is pulled high on all 4 devices
Output Enable (pin 13) is pulled low on all 4 devices
0.1uF capacitor from each chip's Vcc to GND
*/
// used Sketch:Import Library:SPI to make this show up
#include <SPI.h>
int ss = 10;
int i = 0;
int shiftreg = 0;
byte byte1 = 1;
byte byte2 = 1;
byte byte3 = 1;
byte byte4 = 1;
void setup() {
pinMode (ss, OUTPUT);
SPI.begin(); // library takes care of D11 MOSI, D12 MISO, D13 SCK
}
void loop(){
// loop thru 8 times, walk a 1 across all 4 registers
for(i = 0; i < 8; i=i+1){
digitalWrite (ss, LOW);
SPI.transfer (byte1);
SPI.transfer (byte2);
SPI.transfer (byte3);
SPI.transfer (byte4);
digitalWrite (ss, HIGH); // all outputs change on ss going low to high
delay(1000);
byte1 = byte1 <<1; // update the data
byte2 = byte2 <<1;
byte3 = byte3 <<1;
byte4 = byte4 <<1;
}
// after all 8 outputs are high one time, reset for the next pass
byte1 = 1; // update the data
byte2 = 1;
byte3 = 1;
byte4 = 1;
}
I found a solution as well, the only weird thing now is, that as soon as I am opening a Serial communication and check for a Serial.available() the whole thing gets messed up completely and goes crazy, meaning the wrong pins get activated, and stay activated and before even sending something over the serial port it sort of starts...
How can the serial communication influence some pins of some registers?
#include <SPI.h>
int ss = 10;
int nrOfRegisters = 4;
byte dataValues[4];
void setup() {
Serial.begin(9600);
pinMode (ss, OUTPUT);
SPI.begin();
SPI.setBitOrder(MSBFIRST);
// set all to 0 in order to start
for(int i = 0; i < nrOfRegisters; i++){
dataValues[i] = B00000000;
}
}
void loop(){
// if (Serial.available() > 0) {
sendToRegister(0, 0);
// }
}
int sendToRegister(int whichRegister, int valueForSolenoid) {
digitalWrite(ss,LOW);
for(int i = 0; i < nrOfRegisters; i++){
// set all and everything to 0
dataValues[i] = B00000000;
// set the pin for the unique register
if(i == whichRegister){
dataValues[i] = B00000001;
if(valueForSolenoid >= 1){
dataValues[i] = dataValues[i] << valueForSolenoid;
}
}
SPI.transfer(dataValues[i]);
}
digitalWrite(ss,HIGH);
delay(200);
digitalWrite(ss,LOW);
for(int i = 0; i < nrOfRegisters; i++){
// set all and everything again to 0
dataValues[i] = B00000000;
SPI.transfer(dataValues[i]); // find registers
}
digitalWrite(ss,HIGH);
delay(200);
}
How can the serial communication influence some pins of some registers?
Because what ever you receive you send out to the shift register.
The serial input uses ASCII characters not numbers so if you send a 1 you will actually receive 49 and so send the bit pattern 0011 0001 to the shift registers.
You said you had 4 shift registers.
Whatever you clock in always get pushed along to the next one when you clock in new data.
It sounds like what you want to do is be able to address the 4 of them individually.
In that case, define & use 4 ss pins (ss1, ss2, ss3, ss4) so you shift data into 1 part at a time.
// can make them an array even
ssPin[ ] = {7,8,9,10}; // the 4 ss pins
dataByte [ ] = {0,0,0,0};
// so you can address them as a variable
void setup(){
for (int x =0; x<4; x=x+1){
pinMode (ssPin[x], OUTPUT);
digitalWrite (ssPin[x], LOW);
}
}
// then in void loop(), or your function call:
digitalWrite (ssPin[x], LOW);
SPI.transfer (dataByte[x]);
digitalWrite(ssPin[x], HIGH);
thanks CrossRoads, but i guess this would change also the whole wiring, right?
It works actually fine, the only issue I'm having now is that the Serial thing messes with my idea of sending an ascii character from Processing in order to trigger one specific solenoid. And I guess this wouldn't be too hard, but since the whole thing already starts acting strangly when opening the Serial.available() in arduino I'm asking myself if there are other solutions to communicate with processing or to use serial communication without influencing the arduino/register thing...
If you currently have the 4 of them daisychained, then yes, it changes the wiring.
So keeping it the same:
Now that you've stated what you want to do a little more, you can take this approach:
when the command comes in, have a specific byte changed in the data array, but be sure to shift out all 4 bytes every time:
if (Serial.available()>1){ // look for 2 bytes - 1st is register, 2nd is the data it gets
register = Serial.read();
newData = Serial.read();
dataByte[register] = newData;
updateOutput = 1;
}
then clock all 4 out when a change happens
if (updateOutput ==1){
updateOutput = 0; // clear for next time
for (int x = 0; x<4; x=x+1){
digitalWrite (ssPin[x], LOW);
SPI.transfer (dataByte[x]);
digitalWrite(ssPin[x], HIGH);
}
or do similar, but look for 4 bytes to come in every time:
if (Serial.available()>3){ // look for 4 bytes - update the data array
dataByte[0] = Serial.read();
dataByte[1] = Serial.read();
dataByte[2] = Serial.read();
dataByte[3] = Serial.read();
updateOutput = 1;
}
I saw a post on the Hitech C forum, there was an extra I2C bit, someone hooked it up to a logic analyzer. We figured out it was due to wrong tristating sequence before initializing the serial port.
Setting the tristate right before writing to the serial port register, not after writing, solved the problem!
I have one project where instead of a LED 7seg display, I tried to install a 5x5 LED matrix. Driven through 2x 74hc595. However it is using 5 sink lines not 4 so the PCB is patched.
It was a nightmare (in assembler) just to get to a point displaying a pattern on the matrix!
I use C now (it's a year ago when I wrote it), but I know the experience, trying around for hours to archieve something very simple.
I took the advice from CrossRoads and send now every 4th byte from Processing, which looks like this:
void loop(){
if (Serial.available() > 3) {
// shoot off feedback LED
digitalWrite(feedbackLED,HIGH);
// Register range from 0-3
// Pins range from 0-7
int arrivingByte = Serial.read();
Serial.println(arrivingByte);
int registerByte = 0; // will host the serial from processing
int pinByte = 0; // will host the serial from processing
// to do! find the right register+pin
sendToRegister(registerByte, pinByte);
// end and start again, so it doesn't get triggered by the serials used within the sendToRegister() function, which would start the Serial.available() again
Serial.end();
Serial.begin(9600);
}
digitalWrite(feedbackLED,LOW);
}