The byte behind a digit
Ten bytes is the whole font. Why they are written 0x3F rather than 0b00111111, which bit reaches which bar, and what one wrong word in shiftOut does to all of them.
Ten bytes and you are done
The sketch's font is one line long:
const uint8_t d[] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F
};Index 0 is the byte for a zero, index 9 for a nine, and there is nothing else
to it. 0x80 — bit 7 alone — is the decimal point, which is why you sometimes
see it added on: d[3] | 0x80 is a 3 with a point after it.
0x3F is shorter to type than 0b00111111 and means the same thing. Write the table either way; the compiler cannot tell the difference.Slide through the digits and the pattern is legible once you know the order.
Bit 0 is segment A, bit 1 is B, and so on up to bit 6 for G, with
bit 7 the point. A 1 lights that bar.
Why hexadecimal
Two hex characters are exactly eight bits, which is exactly one byte, which is
exactly one digit's worth of segments. That is the only reason. 0x3F and
0b00111111 are the same number and the compiler cannot tell them apart —
write the table in binary if you find it easier to read, and many people do,
because a column of ones and zeros is a picture of which bars are on.
The one word that ruins it
shiftOut() takes a bit order, and both spellings are valid:
shiftOut(SER, CLK, MSBFIRST, d[n]); // bit 7 goes out first
shiftOut(SER, CLK, LSBFIRST, d[n]); // bit 0 goes out firstThis board wants MSBFIRST. Send it the other way and every bit lands on the
segment that should have held its mirror image: bit 0, meant for segment A,
travels all the way to the decimal point.
Switch the figure above to LSBFIRST and look at what that actually produces. It is not a blank display and it is not a broken one. It is a different valid pattern — sometimes even a different digit — which is precisely why the mistake survives so long. Nothing looks wrong enough to suspect one word in one call.
Building your own table
If you want letters, work it out on the drawing rather than hunting for a list.
An E is A, D, E, F and G, so bits 0, 3, 4, 5 and 6, so 0b01111001, so
0x79. Hexadecimal for the ten digits comes out at A, b, C, d, E, F — those six
are the letters seven bars can draw, which is not a coincidence: it is why
hexadecimal is displayed this way everywhere.
When it does not work
Try LSBFIRST in place of MSBFIRST, or the other way round. It is one word, both spellings compile, and getting it wrong mirrors every byte: 0x3F becomes 0xFC, which is a real pattern that lights real segments and looks like a broken display rather than a bit order.
It is the six segments that draw a zero — A, B, C, D, E and F — with bits 0 to 5 set and bits 6 and 7 clear. Written in binary that is 0b00111111, which is the same number. Hexadecimal is shorter to type and nothing else.
Set bit 7 on top of the digit's own byte: d[3] | 0x80 shows a 3 with the point. 0x80 on its own is the point with no digit behind it, which is what the demo sketch flashes between counts.
Segment G alone, which is 0x40. A blank is 0x00. Between them you can write a negative number across a chain by putting 0x40 in the leftmost module and the digits in the rest.
What happens to the first byte when you send a second one, and why that is the whole trick of chaining.
DATAOUT to DATAIN →Edit this page — content/books/4-inch-7-segment/the-byte-behind-a-digit.mdx
Questions about this product
See what other owners have asked, and read their solutions.
4″ 7-Segment LED Display with 74HC595
Loading discussions…
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.