-
Notifications
You must be signed in to change notification settings - Fork 13
/
LedDisplay.cpp
322 lines (255 loc) · 8.61 KB
/
LedDisplay.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
/*
LedDisplay -- controller library for Avago HCMS-297x displays -- version 0.2
Copyright (c) 2009 Tom Igoe. Some right reserved.
Revisions on version 0.2 and 0.3 by Mark Liebman, 27 Jan 2010
* extended a bit to support up to four (4) 8 character displays.
vim: set ts=4:
Controls an Avago HCMS29xx display. This display has 8 characters, each 5x7 LEDs
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "LedDisplay.h"
// Pascal Stang's 5x7 font library:
#include "font5x7.h"
// The font library is stored in program memory:
#include <avr/pgmspace.h>
#include <string.h>
/*
* Constructor. Initializes the pins and the instance variables.
*/
LedDisplay::LedDisplay(uint8_t _dataPin,
uint8_t _registerSelect,
uint8_t _clockPin,
uint8_t _chipEnable,
uint8_t _resetPin,
uint8_t _displayLength)
{
// Define pins for the LED display:
this->dataPin = _dataPin; // connects to the display's data in
this->registerSelect = _registerSelect; // the display's register select pin
this->clockPin = _clockPin; // the display's clock pin
this->chipEnable = _chipEnable; // the display's chip enable pin
this->resetPin = _resetPin; // the display's reset pin
this->displayLength = _displayLength; // number of bytes needed to pad the string
this->cursorPos = 0; // position of the cursor in the display
// do not allow a long multiple display to use more than LEDDISPLAY_MAXCHARS
if (_displayLength > LEDDISPLAY_MAXCHARS) {
_displayLength = LEDDISPLAY_MAXCHARS;
}
// fill stringBuffer with spaces, and a trailing 0:
for (unsigned int i = 0; i < sizeof(stringBuffer); i++) {
stringBuffer[i] = ' ';
}
this->setString(stringBuffer); // give displayString a default buffer
}
/*
* Initialize the display.
*/
void LedDisplay::begin() {
// set pin modes for connections:
pinMode(dataPin, OUTPUT);
pinMode(registerSelect, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(chipEnable, OUTPUT);
pinMode(resetPin, OUTPUT);
// reset the display:
digitalWrite(resetPin, LOW);
delay(10);
digitalWrite(resetPin, HIGH);
// load dot register with lows
loadDotRegister();
// set control register 0 for max brightness, and no sleep:
loadAllControlRegisters(B01111111);
}
/*
* Clear the display
*/
void LedDisplay::clear() {
this->setString(stringBuffer);
for (int displayPos = 0; displayPos < displayLength; displayPos++) {
// put the character in the dot register:
writeCharacter(' ', displayPos);
}
// send the dot register array out to the display:
loadDotRegister();
}
/*
* set the cursor to the home position (0)
*/
void LedDisplay::home() {
// set the cursor to the upper left corner:
this->cursorPos = 0;
}
/*
* set the cursor anywhere
*/
void LedDisplay::setCursor(int whichPosition){
this->cursorPos = whichPosition;
}
/*
* return the cursor position
*/
int LedDisplay::getCursor() {
return this->cursorPos;
}
/*
* write a byte out to the display at the cursor position,
* and advance the cursor position.
*/
#if ARDUINO >= 100
size_t LedDisplay::write(uint8_t b) {
#else
void LedDisplay::write(uint8_t b) {
#endif
// make sure cursorPos is on the display:
if (cursorPos >= 0 && cursorPos < displayLength) {
// put the character into the dot register:
writeCharacter(b, cursorPos);
// put the character into the displayBuffer
// but do not write the string constants pass
// to us from the user by setString()
if (this->displayString == stringBuffer && cursorPos < LEDDISPLAY_MAXCHARS) {
stringBuffer[cursorPos] = b;
}
cursorPos++;
// send the dot register array out to the display:
loadDotRegister();
}
#if ARDUINO >= 100
return 1;
#endif
}
/*
* Scroll the displayString across the display. left = -1, right = +1
*/
void LedDisplay::scroll(int direction) {
cursorPos += direction;
// length of the string to display:
int stringEnd = strlen(displayString);
// Loop over the string and take displayLength characters to write to the display:
for (int displayPos = 0; displayPos < displayLength; displayPos++) {
// which character in the strings you want:
int whichCharacter = displayPos - cursorPos;
// which character you want to show from the string:
char charToShow;
// display the characters until you have no more:
if ((whichCharacter >= 0) && (whichCharacter < stringEnd)) {
charToShow = displayString[whichCharacter];
} else {
// if none of the above, show a space:
charToShow = ' ';
}
// put the character in the dot register:
writeCharacter(charToShow, displayPos);
}
// send the dot register array out to the display:
loadDotRegister();
}
/*
* set displayString
*/
void LedDisplay::setString(const char * _displayString) {
this->displayString = _displayString;
}
/*
* return displayString
*/
const char * LedDisplay::getString() {
return displayString;
}
/*
* return displayString length
*/
int LedDisplay::stringLength() {
return strlen(displayString);
}
/*
* set brightness (0 - 15)
*/
void LedDisplay::setBrightness(uint8_t bright)
{
// Limit the brightness
if (bright > 15) {
bright = 15;
}
// set the brightness:
loadAllControlRegisters(B01110000 + bright);
}
/* this method loads bits into the dot register array. It doesn't
* actually communicate with the display at all,
* it just prepares the data:
*/
void LedDisplay::writeCharacter(char whatCharacter, byte whatPosition) {
// calculate the starting position in the array.
// every character has 5 columns made of 8 bits:
byte thisPosition = whatPosition * 5;
// copy the appropriate bits into the dot register array:
for (int i = 0; i < 5; i++) {
dotRegister[thisPosition+i] = (pgm_read_byte(&Font5x7[((whatCharacter - 0x20) * 5) + i]));
}
}
// This method sends 8 bits to one of the control registers:
void LedDisplay::loadControlRegister(uint8_t dataByte) {
// select the control registers:
digitalWrite(registerSelect, HIGH);
// enable writing to the display:
digitalWrite(chipEnable, LOW);
// shift the data out:
shiftOut(dataPin, clockPin, MSBFIRST, dataByte);
// disable writing:
digitalWrite(chipEnable, HIGH);
}
// This method sends 8 bits to the control registers in all chips:
void LedDisplay::loadAllControlRegisters(uint8_t dataByte) {
// Each display can have more than one control chip, and displays
// can be daisy-chained into long strings. For some operations, such
// as setting the brightness, we need to ensure that a single
// control word reaches all displays simultaneously. We do this by
// putting each chip into simultaneous mode - effectively coupling
// all their data-in pins together. (See section "Serial/Simultaneous
// Data Output D0" in datasheet.)
// One chip drives four characters, so we compute the number of
// chips by diving by four:
int chip_count = displayLength / 4;
// For each chip in the chain, write the control word that will put
// it into simultaneous mode (seriel mode is the power-up default).
for (int i = 0; i < chip_count; i++) {
loadControlRegister(B10000001);
}
// Load the specified value into the control register.
loadControlRegister(dataByte);
// Put all the chips back into serial mode. Because they're still
// all in simultaneous mode, we only have to write this word once.
loadControlRegister(B10000000);
}
// this method originally sent 320 bits to the dot register: 12_30_09 ML
void LedDisplay::loadDotRegister() {
// define max data to send, patch for 4 length displays by KaR]V[aN
int maxData = displayLength * 5;
// select the dot register:
digitalWrite(registerSelect, LOW);
// enable writing to the display:
digitalWrite(chipEnable, LOW);
// shift the data out:
for (int i = 0; i < maxData; i++) {
shiftOut(dataPin, clockPin, MSBFIRST, dotRegister[i]);
}
// disable writing:
digitalWrite(chipEnable, HIGH);
}
/*
version() returns the version of the library:
*/
int LedDisplay::version(void)
{
return 4;
}