-
Notifications
You must be signed in to change notification settings - Fork 2
/
LEDDisplay74HC595.cpp
138 lines (117 loc) · 3.54 KB
/
LEDDisplay74HC595.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
LEDDisplay74HC595.cpp
Library for presenting number values using a
4-Bit LED Digital Tube Module with two 74HC595.
Created by Chrizzzzz January 2016.
Released into the public domain.
*/
#include "Arduino.h"
#include "LEDDisplay74HC595.h"
#define NEG_SIGN 10
#define EMPTY 11
#define CHAR_E 12
#define CHAR_R 13
#define MAX_DECIMAL_PLACES 3
const byte CHARS[] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111, // 9
0b01000000, // -
0b00000000, // <empty>
0b01111001, // E
0b01010000, // r
};
const byte POS[] = {
0b00001000, // first digit in diplay
0b00000100, // second digit
0b00000010, // third digit
0b00000001, // forth digit
};
LEDDisplay74HC595::LEDDisplay74HC595(int sclk, int rclk, int dio)
{
pinMode(sclk, OUTPUT);
pinMode(rclk, OUTPUT);
pinMode(dio, OUTPUT);
_shiftClock = sclk;
_resetClock = rclk;
_displayIO = dio;
_refreshDigitIndex = 0;
}
void LEDDisplay74HC595::refresh(float number, int decimalPlaces)
{
boolean isNegative = number < 0;
boolean hasDecimal = decimalPlaces > 0;
int decimalPos = MAX_DECIMAL_PLACES - decimalPlaces;
float absNumber = isNegative ? -number : number;
// make sure we have a valid decimalPlaces argument
if(decimalPlaces > MAX_DECIMAL_PLACES || decimalPlaces < 0) {
setError();
return;
}
// let's move the decimal point out of the number and
// handle the decimal point separately
// e.g. 123.45 with one decimal place -> 1235
int flatNumber = (int)(absNumber * pow(10, decimalPlaces) + 0.5);
// make sure the display number is not too big to fit in the display
if((isNegative && flatNumber > 999) || !isNegative && flatNumber > 9999) {
setError();
return;
}
// build the display values
byte displayBytes[] {
CHARS[flatNumber / 1000 % 10],
CHARS[flatNumber / 100 % 10],
CHARS[flatNumber / 10 % 10],
CHARS[flatNumber % 10],
};
// remove leading zeroes
int i = 0;
while(displayBytes[i] == CHARS[0] && i < decimalPos) {
displayBytes[i] = CHARS[EMPTY];
i++;
}
// add the neg sign if needed
if(isNegative) {
// special case if we have a zero on pos 0 and the decimal point as well,
// then we use the space of the zero for the neg sign to save space
if(displayBytes[0] == CHARS[0] && decimalPos == 0) {
displayBytes[0] = CHARS[NEG_SIGN];
} else {
// if not special case, then we simply put the neg sign before the first non-empty display byte
for(i = 0; i < 4; i++) {
int prevPos = i - 1;
// set negative sign before the first digit we encounter
if(prevPos >= 0 && displayBytes[prevPos] == CHARS[EMPTY] && displayBytes[i] != CHARS[EMPTY]) {
displayBytes[prevPos] = CHARS[NEG_SIGN];
}
}
}
}
// put the decimal sign at the right position
if(hasDecimal) {
displayBytes[decimalPos] ^= 0x80; // add decimal point bit at the decimal position
}
// set the current digit character to the LED display
byte digitIndex = _refreshDigitIndex++ % 4;
setDisplayByte(displayBytes[digitIndex], digitIndex);
}
void LEDDisplay74HC595::setError()
{
setDisplayByte(CHARS[CHAR_E], 0);
setDisplayByte(CHARS[CHAR_R], 1);
setDisplayByte(CHARS[CHAR_R], 2);
}
void LEDDisplay74HC595::setDisplayByte(byte displayByte, int pos)
{
shiftOut(_displayIO, _shiftClock, MSBFIRST, ~displayByte);
shiftOut(_displayIO, _shiftClock, MSBFIRST, POS[pos]);
digitalWrite(_resetClock, LOW);
digitalWrite(_resetClock, HIGH);
}