Hello,
I'm coming from an AVR world and trying to port over my code to work on a Photon 2. I'm taking baby steps trying to get the shift registers working first. The code below works great on an 8 bit AVR but I'm having issues with the photon. This will be a shift register library but I put the code in the main to keep it simple. I will ultimately have 5 shift registers (l74hc595) wired together controlling LEDs but I currently have 3 wired up connected through a level translator. Two registers seem to work ok but when I add a third, things get wacky. Random LEDs light up and I can't figure out what the issue is. Any help with my code would be appreciated.
#define L74HC595_SERPIN D16
#define L74HC595_RCLKPIN D17 //ST_CP
#define L74HC595_SRCLKPIN D18
#define L74HC595_ICNUMBER 3
uint8_t l74hc595_icarray[L74HC595_ICNUMBER];
SerialLogHandler logHandler;
SYSTEM_THREAD(ENABLED);
void setup() {
l74hc595_init();
}
void loop() {
l74hc595_setregalloff();
l74hc595_shiftout();
l74hc595_setreg(15,1);
l74hc595_shiftout();
// for(uint8_t x = 0; x < 16; x++){
// l74hc595_setreg(x,1);
// l74hc595_shiftout();
// delay(750);
// }
delay(3000);
}
void l74hc595_setreg(uint16_t regindex, uint8_t val) {
//get valid byteindex, first byte is for first ic attached
uint16_t byteindex = (L74HC595_ICNUMBER-1)-regindex/8;
//bit address 0 is Qa
uint8_t bitindex = (8-1) - regindex % 8;
uint8_t current = l74hc595_icarray[byteindex];
current &= ~(1 << bitindex); //clear the bit
current |= val << bitindex; //set the bit
l74hc595_icarray[byteindex] = current; //set the new value
}
//set all registers off
void l74hc595_setregalloff() {
for(uint16_t i = 0; i < L74HC595_ICNUMBER*8; i++){
l74hc595_setreg(i, 0);
}
}
//set all registers on
void l74hc595_setregallon() {
for(uint16_t i = 0; i < L74HC595_ICNUMBER*8; i++){
l74hc595_setreg(i, 1);
}
}
//init the shift register
void l74hc595_init() {
//output
pinMode(L74HC595_SERPIN, OUTPUT);
pinMode(L74HC595_RCLKPIN, OUTPUT);
pinMode(L74HC595_SRCLKPIN, OUTPUT);
//low
digitalWrite(L74HC595_SERPIN, LOW);
digitalWrite(L74HC595_RCLKPIN, LOW);
digitalWrite(L74HC595_SRCLKPIN, LOW);
//init registers
l74hc595_setregalloff();
}
//shift out data
void l74hc595_shiftout() {
digitalWrite (L74HC595_RCLKPIN, LOW); //set the register-clock pin low
for(uint8_t i = 0; i < L74HC595_ICNUMBER; i++){
//iterate through the bits in each registers
for(uint8_t j = 0; j < 8; j++){
digitalWrite (L74HC595_SRCLKPIN, LOW); //set the serial-clock pin low
uint8_t val = (l74hc595_icarray[i] & (1 << j))>>j;
digitalWrite (L74HC595_SERPIN, val);
digitalWrite (L74HC595_SRCLKPIN, HIGH); //set the serial-clock pin high
digitalWrite (L74HC595_SERPIN, LOW); //set the datapin low again
}
}
digitalWrite (L74HC595_RCLKPIN, HIGH); //set the register-clock pin high to update the output of the shift-register
}
@Tydebox, have you considered using the built-in "Shift-Out" function for doing the work? You simply feed it one byte at a time and it does the hard work.
Also, you may be able to get away with not using a level translator as the L75HC595 operates at both 3.3v and 5v and since you are only driving inputs, the 3.3v level of the Photon2 (HIGH and LOW voltages) may work just fine.
And, I have to say it, make sure your third L74HC595 is correctly wired
I tried using shiftout() but I really need to be able to just feed the function the LED number that I need to turn on (For example shiftout(5) to turn on LED #5). I couldn't get Shiftout() to work this way.
I could get away without using the level translator but I already have LED boards made and using 3.3V would make the LEDs too dim.
@Tydebox, my comment re the 3.3v was not to change the operating voltage of the HC595 to 3.3v. Instead, it was in regards to its inputs likely being CMOS (3.3v) logic compatible while it is running with a 5v supply.
As for using Shiftout(), it is a byte-oriented function and since the HC595 is an 8-bit device, the function is well suited for this device. You already have the l74hc595_icarray[] byte array which represents the bit/byte data for all your HC595. You simply need to modify your l74hc595_shiftout() function to use the DeviceOS shiftOut() function instead of the inner for(uint8_t j ...) loop. This, of course, is entirely optional.
As for having a shiftout(5) capability (which your code doesn't currently have). A new function, say l74hc595_wireLED() would need to:
Set the desired bit (passed in the argument) in the in the l74hc595_icarray[] array, which I believe the uses l74hc595_setreg()` function does.
Disable the HC595 outputs (blank the LEDs) by setting OE* high.
Write out the entire array to the HC595 shift registers using the (updated as above) l74hc595_shiftout()
Enable the HC595 outputs (light the LEDs) by setting OE* low.
Hope that makes sense. Do you have an oscilloscope or logic analyzer to look at the data going from one HC595 to the next?
BTW, there is a lovely Arduino library (which you can easily port) you can use that does exactly what you want here:
Ah ok, I'll keep that in mind but I'm ok with the level translator for now.
You are correct, I should have said if I want to turn on LED #6 run l74hc595_shiftout(5,1); I'd still like to get my code working so is this what you had in mind for the placing Shiftout() inside my l74hc595_shiftout()?
I do have an oscilloscope so I might have to break it out.
void l74hc595_shiftout() {
digitalWrite (L74HC595_RCLKPIN, LOW); //set the register-clock pin low
for(uint8_t i = 0; i < L74HC595_ICNUMBER; i++){
//iterate through the bits in each registers
for(uint8_t j = 0; j < 8; j++){
uint8_t value = (l74hc595_icarray[i] & (1 << j))>>j;
shiftOut(L74HC595_SERPIN, L74HC595_SRCLKPIN, MSBFIRST, value);
}
digitalWrite (L74HC595_RCLKPIN, HIGH); //set the register-clock pin high to update the output of the shift-register
}
@Tydebox, you don't need the inner for() loop since you will be outputting whole bytes (one per HC595) at a time. Look that the Shifty library code to get the idea: