I have two 74HC595 driving two 7 segment LED displays and I wrote a simple C program to either display a specified number (00-99) from argv or count from 00 to 99.
When specifying a value from the command line, it always works perfectly, even in a loop (edit: actually if I remove the clear from init()
then it fails intermittently in a shell loop). However, if I just run with no argv, which make it just count from 00 to 99 with 300ms between iterations, every now an then an led will not be lit, or the DP will be lit. I'm always shifting 8 bits two times so I'm not sure why there would be missing or extra bits.
Example debug out:
cur val: 15
shifting: 109
cur: 0
cur: 1
cur: 1
cur: 0
cur: 1
cur: 1
cur: 0
cur: 1
shifting: 6
cur: 0
cur: 0
cur: 0
cur: 0
cur: 0
cur: 1
cur: 1
cur: 0
In this case the left vertical of the 5 was missing (i.e. the most significant 1 in 109) even though the bits I sent to the DS
were correct as show above.
Code:
#include <wiringPi.h>
#include <stdlib.h>
#include <stdio.h>
#define SDI 0 //serial data input
#define RCLK 1 //memory clock input(STCP)
#define SRCLK 2 //shift register clock input(SHCP)
unsigned char SegCode[11] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};
void write_to_dual(int value);
void init(void)
{
pinMode(SDI, OUTPUT); //make P0 output
pinMode(RCLK, OUTPUT); //make P0 output
pinMode(SRCLK, OUTPUT); //make P0 output
write_to_dual(-1);
digitalWrite(SDI, LOW);
digitalWrite(RCLK, LOW);
digitalWrite(SRCLK, LOW);
}
void shift_data()
{
digitalWrite(SRCLK, HIGH);
delay(1);
digitalWrite(SRCLK, LOW);
}
void write_data()
{
digitalWrite(RCLK, HIGH);
delay(1);
digitalWrite(RCLK, LOW);
}
void hc595_shift(unsigned char dat)
{
int i;
printf("shifting: %d\n", dat);
for(i=0;i<8;i++){
/* unsigned int to_write = (0x80 & (dat << i)); */
unsigned int to_write = (0x80 & (dat << i)) >> 7;
printf("cur: %d\n", to_write);
digitalWrite(SDI, to_write);
shift_data();
digitalWrite(SDI, LOW);
}
}
unsigned char *calc_2byte_base10(int value)
{
unsigned char *bytes = malloc(2 * sizeof(unsigned char));
if (value == -1) {
bytes[0] = 11;
bytes[1] = 11;
} else {
int ones = value % 10;
int tens = (value / 10) % 10;
bytes[0] = ones;
bytes[1] = tens;
}
return bytes;
}
void write_to_dual(int value)
{
unsigned char *bytes;
bytes = calc_2byte_base10(value);
hc595_shift(SegCode[bytes[0]]);
hc595_shift(SegCode[bytes[1]]);
write_data();
free(bytes);
}
int main(int argc, char **argv)
{
int i;
if(wiringPiSetup() == -1){
printf("setup wiringPi failed !");
return 1;
}
init();
if (argc > 1) {
int value = atoi(argv[1]);
write_to_dual(value);
} else {
int i;
for (i = 0; i < 100; i++) {
printf("cur val: %d\n", i);
write_to_dual(i);
delay(600);
}
}
return 0;
}
Given that it works if I run it on individual values (init()
clears the two displays) or if I add write_to_dual(-1);
at the end of every loop iteration, it works fine, it seems that not clearing the displays is somehow leaving some cruft or something. Is anyone seeing anything obvious in this code (largely borrowed from the Sunfounder source (https://github.com/sunfounder/Sunfounder_SuperKit_C_code_for_RaspberryPi/blob/master/11_Segment/segment1.c) or could one of the shift registers be busted?
EDIT: if I remove write_to_dual(-1);
from init()
then I do get intermittent issues whether it be individual invocations or in a shell loop. It must be the code.