displaying a sequence of characters on one 7segment display?

I was learning about shift registers and 7 segment displays so I put together this code using bits of examples I found plus added a bit of my own characters.

QUESTION: It’s nice to be able to display all these characters using simple code like

for(int j=0; j<37; j++){
			digitalWrite(LATCH, LOW);
			shiftOut(DATA, CLK, LSBFIRST, ~digitOne[j]); // ~digitOne for COMMON ANODE or remove ~ for COMMON CATHODE
			digitalWrite(LATCH, HIGH);
			delay(200);
		}

BUT… How do I display JUST the sequence of numbers or letters I want?
In other words, how would I get it to display the sequence H E L L O on a single display? (I’m not using 5 separate 7segs here)
I don’t want to have to use…
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLK, LSBFIRST, ~digitOne[18]);
digitalWrite(LATCH, HIGH);
delay(200);
just to display an H then do the whole thing again for the E etc…

Is there an easier way to do this when using a shift register and a 7 segment display?

Here’s the code I’m working with.

/*
Shift Register Wiring Schematic
 Q1 -|    |- VCC
 Q2 -|    |- Q0
 Q3 -|    |- DS
 Q4 -|    |- OE
 Q5 -|    |- ST_CP
 Q6 -|    |- SH_CP
 Q7 -|    |- MR
VSS -|    |- Q' 
 
Key:
Q0 - Q7: Parallel Out Pins
Q': Cascade Pin
DS: Serial Data In Pin
OE: Output Enable (Active Low)
ST_CP: Latch Pin
SH_CP: Clock Pin
MR: Master Reset  (Active Low)

use ~digitOne (Bitwise Operator NOT) for COMMON ANODE or remove ~ for COMMON CATHODE
to invert the bits 
*/

#define LATCH 2
#define CLK 4
#define DATA 3


// Define the characters for COMMON ANODE 7-segment displays
const byte digitOne[43] =
{
	// Bin digits
	B11111100, B01100000, B11011010, B11110010,   // 0123
	B01100110, B10110110, B10111110, B11100000,   // 4567
	B11111110, B11110110, B11101110, B00111110,   // 89AB
	B00011010, B01111010, B10011110, B10001110,   // CDEF
	B10111110, B01101110, B01100000, B01110000,   // GHIJ
	B01101110, B00011100, B11101100, B11101100,   // KLMN
	B11111100, B11001110, B11100110, B11101110,   // OPQR
	B10110110, B11100000, B01111100, B01111100,   // STUV
	B01111110, B01101110, B01001110, B11011010,   // WXYZ
	
	B00000000, B10000000, B01000000, B00100000,   // SPACE, SPIN
	B00010000, B00001000, B00000100,
};

void setup(){
	pinMode(LATCH, OUTPUT);
	pinMode(CLK, OUTPUT);
	pinMode(DATA, OUTPUT);	
}

void loop()

{
	for(int j=0; j<37; j++){
			digitalWrite(LATCH, LOW);
			shiftOut(DATA, CLK, LSBFIRST, ~digitOne[j]); // ~digitOne for COMMON ANODE or remove ~ for COMMON CATHODE
			digitalWrite(LATCH, HIGH);
			delay(200);
		}
	
	for(int i=0; i<3; i++){
		for(int j=37; j<43; j++){
			digitalWrite(LATCH, LOW);
			shiftOut(DATA, CLK, LSBFIRST, ~digitOne[j]); // ~digitOne for COMMON ANODE or remove ~ for COMMON CATHODE
			digitalWrite(LATCH, HIGH);
			delay(100);
			}
		}
	for(int i=0; i<3; i++){
		for(int j=42; j>36; j--){
			digitalWrite(LATCH, LOW);
			shiftOut(DATA, CLK, LSBFIRST, ~digitOne[j]); // ~digitOne for COMMON ANODE or remove ~ for COMMON CATHODE
			digitalWrite(LATCH, HIGH);
			delay(100);
			}
		}

}

Seems you want to set up a second array containing the indices of the characters you want to display, and perform a double indirection, reading each array element in turn and using that as an index into your character array to display that.

Fairly straightforward.

An alternative - more complex - would be to read characters from a string and make a calculation as to what each character should correspond to in your primary array.

Interesting.

I'm going to have to learn about strings because it seems like a more usable technique but I might be able to cobble together something that uses an array of arrays of sorts just to see if I can figure it out.

Unless - at some point -you feel a strict need for strings, I would go for the arrays - there appear to be problems (excess RAM use) with string handling and it seems they are better avoided.

I ended up e-mailing someone who actually knows how to write C code and he helped me get it working using strings.

/*
Shift Register Wiring Schematic
 Q1 -|    |- VCC
 Q2 -|    |- Q0
 Q3 -|    |- DS
 Q4 -|    |- OE
 Q5 -|    |- ST_CP
 Q6 -|    |- SH_CP
 Q7 -|    |- MR
VSS -|    |- Q' 
 
Key:
Q0 - Q7: Parallel Out Pins
Q': Cascade Pin
DS: Serial Data In Pin
OE: Output Enable (Active Low)
ST_CP: Latch Pin
SH_CP: Clock Pin
MR: Master Reset  (Active Low)

use ~digitOne (Bitwise Operator NOT) for COMMON ANODE or remove ~ for COMMON CATHODE
to invert the bits 
*/

#define LATCH 2
#define CLK 4
#define DATA 3


// Define the segment-patterns for COMMON ANODE 7-segment displays
const byte digitOne[44] =
{
	// Bin digits
	B11111100, B01100000, B11011010, B11110010,   // 0123
	B01100110, B10110110, B10111110, B11100000,   // 4567
	B11111110, B11110110, B11101110, B00111110,   // 89AB
	B00011010, B01111010, B10011110, B10001110,   // CDEF
	B10111110, B01101110, B01100000, B01110000,   // GHIJ
	B01101110, B00011100, B11101100, B11101100,   // KLMN
	B11111100, B11001110, B11100110, B11101110,   // OPQR
	B10110110, B11100000, B01111100, B01111100,   // STUV
	B01111110, B01101110, B01001110, B11011010,   // WXYZ
	
	B00000000, B10000000, B01000000, B00100000,   // SPACE, single segments
	B00010000, B00001000, B00000100, B00000010
};

void setup(){
	pinMode(LATCH, OUTPUT);
	pinMode(CLK, OUTPUT);
	pinMode(DATA, OUTPUT);	
}

// This doesn’t handle the single segments yet!
void showCharacter(char character)
{
	byte pattern = 0;


	if(character >= '0' && character <= '9')
	{
		pattern = digitOne[character - '0'];
	}
	else if (character >= 'A' && character <= 'Z')
	{
		pattern = digitOne[character - 'A' + 10];
	}
	else if (character == ' ')
	{
		pattern = digitOne[36];
	}


	// If the character does not match any of the cases above,
	// you get the 0 pattern (the space character).


	digitalWrite(LATCH, LOW);
	shiftOut(DATA, CLK, LSBFIRST, ~pattern);
	digitalWrite(LATCH, HIGH);
	delay (400);
}


void loop()
{
	char string[] = "TEST STRING  ";
	// Leave out the terminating NUL character in the string
	for(int i = 0; i < sizeof(string) - 1; i++)
	{
		showCharacter(string[i]);
	}
}

Yes. An extension to that code maps lower case characters in the string to upper case as well, so that it displays something for whichever case you happened to type - given that some characters are displayed as upper case and some as lower case anyway. :grinning:

	if(character >= '0' && character <= '9')
	{
		pattern = digitOne[character - '0'];
	}
	else if (character >= 'A' && character <= 'Z')
	{
		pattern = digitOne[character - 'A' + 10];
	}
	else if (character >= 'a' && character <= 'z')
	{
		pattern = digitOne[character - 'a' + 10];
	}
	else if (character == ' ')
	{
		pattern = digitOne[36];
	}

Nice, I just added it to my code.
Considering I will never be able to make upper and lower case versions of each character because 7 segment displays are horrible for letters anyway this would be useful.

Paul__B:
Yes. An extension to that code maps lower case characters in the string to upper case as well, so that it displays something for whichever case you happened to type - given that some characters are displayed as upper case and some as lower case anyway. :grinning:

	if(character >= '0' && character <= '9')
{
	pattern = digitOne[character - '0'];
}
else if (character >= 'A' && character <= 'Z')
{
	pattern = digitOne[character - 'A' + 10];
}
else if (character >= 'a' && character <= 'z')
{
	pattern = digitOne[character - 'a' + 10];
}
else if (character == ' ')
{
	pattern = digitOne[36];
}

If you want more characters, use a 14-segment or 16-segment display. (You will need to add one more shift register for the extra segments.)