]>
fbox.kageds.com Git - richie-water-pump.git/blob - sevseg.cpp
3 Copyright 2017 Dean Reading
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
17 This library allows an Arduino to easily display numbers in decimal format on
18 a 7-segment display without a separate 7-segment display controller.
20 Direct any questions or suggestions to deanreading@hotmail.com
21 See the included readme for instructions.
22 https://github.com/DeanIsMe/SevSeg
25 Version 3.3.0 - February 2017
26 Added the ability to keep leading zeros. This is now an extra
27 parameter in the begin() function.
29 Version 3.2.0 - December 2016
30 Updated to Arduino 1.5 Library Specification
31 New display function - no longer consumes processor time with delay()
32 Now supports hexadecimal number printing
33 The decimal point can now be omitted with a negative decPlaces
34 decPlaces is now optional in setNumber
35 Alphanumeric strings can be displayed (inaccurately) with setChars()
36 Removed #define RESISTORS_ON_SEGMENTS. Now a begin() input
37 Can now blank() the display
39 Version 3.1 - September 2016
40 Bug Fixes. No longer uses dynamic memory allocation.
41 Version 3.0 - November 2014
42 Library re-design. A display with any number of digits can be used.
43 Floats are supported. Support for using transistors for switching.
44 Much more user friendly. No backwards compatibility.
45 Uploaded to GitHub to simplify any further development.
46 Version 2.3; Allows for brightness control.
47 Version 2.2; Allows 1, 2 or 3 digit displays to be used.
48 Version 2.1; Includes a bug fix.
49 Version 2.0; Now works for any digital pin arrangement.
50 Supports both common anode and common cathode displays.
55 #include "pico/stdlib.h"
57 #define BLANK_IDX 36 // Must match with 'digitCodeMap'
63 static const long powersOf10
[] = {
76 static const long powersOf16
[] = {
87 // The codes below indicate which segments must be illuminated to display
89 static const byte digitCodeMap
[] = {
90 // GFEDCBA Segments 7-segment map:
103 // Constant pointers to constant data
104 const byte
* const numeralCodes
= digitCodeMap
;
106 // SevSeg Constructor
107 /******************************************************************************/
111 ledOnTime
= 2000; // Corresponds to a brightness of 100
116 updateWithDelays
= 0;
121 /******************************************************************************/
122 // Saves the input pin numbers to the class and sets up the pins to be used.
123 // If you use current-limiting resistors on your segment pins instead of the
124 // digit pins, then set resOnSegments as true.
125 // Set updateWithDelays to true if you want to use the 'pre-2017' update method
126 // That method occupies the processor with delay functions.
127 void SevSeg::begin(byte hardwareConfig
, byte numDigitsIn
, byte digitPinsIn
[],
128 byte segmentPinsIn
[], bool resOnSegmentsIn
,
129 bool updateWithDelaysIn
, bool leadingZerosIn
) {
131 resOnSegments
= resOnSegmentsIn
;
132 updateWithDelays
= updateWithDelaysIn
;
133 leadingZeros
= leadingZerosIn
;
135 numDigits
= numDigitsIn
;
136 //Limit the max number of digits to prevent overflowing
137 if (numDigits
> MAXNUMDIGITS
) numDigits
= MAXNUMDIGITS
;
139 switch (hardwareConfig
) {
141 case 0: // Common cathode
146 case 1: // Common anode
151 case 2: // With active-high, low-side switches (most commonly N-type FETs)
156 case 3: // With active low, high side switches (most commonly P-type FETs)
163 segmentOff
= !segmentOn
;
165 // Save the input pin numbers to library variables
166 for (byte segmentNum
= 0 ; segmentNum
< 8 ; segmentNum
++) {
167 segmentPins
[segmentNum
] = segmentPinsIn
[segmentNum
];
170 for (byte digitNum
= 0 ; digitNum
< numDigits
; digitNum
++) {
171 digitPins
[digitNum
] = digitPinsIn
[digitNum
];
174 // Set the pins as outputs, and turn them off
175 for (byte digit
= 0 ; digit
< numDigits
; digit
++) {
176 gpio_init(digitPins
[digit
]);
177 gpio_set_dir(digitPins
[digit
], GPIO_OUT
);
178 gpio_put(digitPins
[digit
], segmentOff
);
181 for (byte segmentNum
= 0 ; segmentNum
< 8 ; segmentNum
++) {
182 gpio_init(segmentPins
[segmentNum
]);
183 gpio_set_dir(segmentPins
[segmentNum
], GPIO_OUT
);
184 gpio_put(segmentPins
[segmentNum
], digitOff
);
187 setNewNum(0, 0); // Initialise the number displayed to 0
192 /******************************************************************************/
193 // Turns on the segments specified in 'digitCodes[]'
194 // There are 4 versions of this function, with the choice depending on the
195 // location of the current-limiting resistors, and whether or not you wish to
196 // use 'update delays' (the standard method until 2017).
197 // For resistors on *digits* we will cycle through all 8 segments (7 + period),
198 // turning on the *digits* as appropriate for a given segment, before moving on
199 // to the next segment.
200 // For resistors on *segments* we will cycle through all __ # of digits,
201 // turning on the *segments* as appropriate for a given digit, before moving on
202 // to the next digit.
203 // If using update delays, refreshDisplay has a delay between each digit/segment
204 // as it cycles through. It exits with all LEDs off.
205 // If not using updateDelays, refreshDisplay exits with a single digit/segment
206 // on. It will move to the next digit/segment after being called again (if
207 // enough time has passed).
209 void SevSeg::refreshDisplay() {
211 if (!updateWithDelays
) {
213 // Exit if it's not time for the next display change
214 if (time_us_32() - prevUpdateTime
< ledOnTime
) return;
215 prevUpdateTime
= time_us_32();
217 if (!resOnSegments
) {
218 /**********************************************/
219 // RESISTORS ON DIGITS, UPDATE WITHOUT DELAYS
222 // Turn all lights off for the previous segment
223 for (byte digitNum
= 0 ; digitNum
< numDigits
; digitNum
++) {
224 gpio_put(digitPins
[digitNum
], digitOff
);
226 gpio_put(segmentPins
[prevUpdateIdx
], segmentOff
);
229 if (prevUpdateIdx
>= 8) prevUpdateIdx
= 0;
231 byte segmentNum
= prevUpdateIdx
;
233 // Illuminate the required digits for the new segment
234 gpio_put(segmentPins
[segmentNum
], segmentOn
);
235 for (byte digitNum
= 0 ; digitNum
< numDigits
; digitNum
++) {
236 if (digitCodes
[digitNum
] & (1 << segmentNum
)) { // Check a single bit
237 gpio_put(digitPins
[digitNum
], digitOn
);
242 /**********************************************/
243 // RESISTORS ON SEGMENTS, UPDATE WITHOUT DELAYS
246 // Turn all lights off for the previous digit
247 for (byte segmentNum
= 0 ; segmentNum
< 8 ; segmentNum
++) {
248 gpio_put(segmentPins
[segmentNum
], segmentOff
);
250 gpio_put(digitPins
[prevUpdateIdx
], digitOff
);
253 if (prevUpdateIdx
>= numDigits
) prevUpdateIdx
= 0;
255 byte digitNum
= prevUpdateIdx
;
257 // Illuminate the required segments for the new digit
258 gpio_put(digitPins
[digitNum
], digitOn
);
259 for (byte segmentNum
= 0 ; segmentNum
< 8 ; segmentNum
++) {
260 if (digitCodes
[digitNum
] & (1 << segmentNum
)) { // Check a single bit
261 gpio_put(segmentPins
[segmentNum
], segmentOn
);
268 if (!resOnSegments
) {
269 /**********************************************/
270 // RESISTORS ON DIGITS, UPDATE WITH DELAYS
271 for (byte segmentNum
= 0 ; segmentNum
< 8 ; segmentNum
++) {
273 // Illuminate the required digits for this segment
274 gpio_put(segmentPins
[segmentNum
], segmentOn
);
275 for (byte digitNum
= 0 ; digitNum
< numDigits
; digitNum
++) {
276 if (digitCodes
[digitNum
] & (1 << segmentNum
)) { // Check a single bit
277 gpio_put(digitPins
[digitNum
], digitOn
);
281 //Wait with lights on (to increase brightness)
284 //Turn all lights off
285 for (byte digitNum
= 0 ; digitNum
< numDigits
; digitNum
++) {
286 gpio_put(digitPins
[digitNum
], digitOff
);
288 gpio_put(segmentPins
[segmentNum
], segmentOff
);
292 /**********************************************/
293 // RESISTORS ON SEGMENTS, UPDATE WITH DELAYS
294 for (byte digitNum
= 0 ; digitNum
< numDigits
; digitNum
++) {
296 // Illuminate the required segments for this digit
297 gpio_put(digitPins
[digitNum
], digitOn
);
298 for (byte segmentNum
= 0 ; segmentNum
< 8 ; segmentNum
++) {
299 if (digitCodes
[digitNum
] & (1 << segmentNum
)) { // Check a single bit
300 gpio_put(segmentPins
[segmentNum
], segmentOn
);
304 //Wait with lights on (to increase brightness)
307 //Turn all lights off
308 for (byte segmentNum
= 0 ; segmentNum
< 8 ; segmentNum
++) {
309 gpio_put(segmentPins
[segmentNum
], segmentOff
);
311 gpio_put(digitPins
[digitNum
], digitOff
);
319 /******************************************************************************/
320 // This function only receives the input and passes it to 'setNewNum'.
321 // It is overloaded for all number data types, so that floats can be handled
324 void SevSeg::setNumber(long numToShow
, char decPlaces
, bool hex
) //long
326 setNewNum(numToShow
, decPlaces
, hex
);
329 void SevSeg::setNumber(unsigned long numToShow
, char decPlaces
, bool hex
) //unsigned long
331 setNewNum(numToShow
, decPlaces
, hex
);
334 void SevSeg::setNumber(int numToShow
, char decPlaces
, bool hex
) //int
336 setNewNum(numToShow
, decPlaces
, hex
);
339 void SevSeg::setNumber(unsigned int numToShow
, char decPlaces
, bool hex
) //unsigned int
341 setNewNum(numToShow
, decPlaces
, hex
);
344 void SevSeg::setNumber(char numToShow
, char decPlaces
, bool hex
) //char
346 setNewNum(numToShow
, decPlaces
, hex
);
349 void SevSeg::setNumber(byte numToShow
, char decPlaces
, bool hex
) //byte
351 setNewNum(numToShow
, decPlaces
, hex
);
354 void SevSeg::setNumber(float numToShow
, char decPlaces
, bool hex
) //float
356 char decPlacesPos
= decPlaces
;
358 numToShow
= numToShow
* powersOf16
[decPlacesPos
];
361 numToShow
= numToShow
* powersOf10
[decPlacesPos
];
363 // Modify the number so that it is rounded to an integer correctly
364 numToShow
+= (numToShow
>= 0) ? 0.5f
: -0.5f
;
365 setNewNum(numToShow
, decPlaces
, hex
);
370 /******************************************************************************/
371 // Changes the number that will be displayed.
373 void SevSeg::setNewNum(long numToShow
, char decPlaces
, bool hex
) {
374 byte digits
[numDigits
];
375 findDigits(numToShow
, decPlaces
, hex
, digits
);
376 setDigitCodes(digits
, decPlaces
);
381 /******************************************************************************/
382 // Sets the 'digitCodes' that are required to display the desired segments.
383 // Using this function, one can display any arbitrary set of segments (like
384 // letters, symbols or animated cursors). See setDigitCodes() for common
387 // Bit-segment mapping: 0bHGFEDCBA
394 // E C 4 2 (Segment H is often called
395 // DDDD H 3333 7 DP, for Decimal Point)
397 void SevSeg::setSegments(byte segs
[])
399 for (byte digit
= 0; digit
< numDigits
; digit
++) {
400 digitCodes
[digit
] = segs
[digit
];
405 /******************************************************************************/
406 // Displays the string on the display, as best as possible.
407 // Only numeric characters are supported
408 void SevSeg::setChars(char str
[])
410 for (byte digit
= 0; digit
< numDigits
; digit
++) {
411 digitCodes
[digit
] = 0;
414 for (byte digitNum
= 0; digitNum
< numDigits
; digitNum
++) {
415 char ch
= str
[digitNum
];
416 if (ch
== '\0') break; // NULL string terminator
417 if (ch
>= '0' && ch
<= '9') { // Numerical
418 digitCodes
[digitNum
] = numeralCodes
[ch
- '0'];
424 /******************************************************************************/
425 void SevSeg::blank(void) {
426 for (byte digitNum
= 0 ; digitNum
< numDigits
; digitNum
++) {
427 digitCodes
[digitNum
] = digitCodeMap
[BLANK_IDX
];
433 /******************************************************************************/
434 // Decides what each digit will display.
435 // Enforces the upper and lower limits on the number to be displayed.
437 void SevSeg::findDigits(long numToShow
, char decPlaces
, bool hex
, byte digits
[]) {
438 const long * powersOfBase
= hex
? powersOf16
: powersOf10
;
439 const long maxNum
= powersOfBase
[numDigits
] - 1;
440 const long minNum
= -(powersOfBase
[numDigits
- 1] - 1);
442 // If the number is out of range, just display dashes
443 if (numToShow
> maxNum
|| numToShow
< minNum
) {
444 for (byte digitNum
= 0 ; digitNum
< numDigits
; digitNum
++) {
445 digits
[digitNum
] = DASH_IDX
;
451 // Convert all number to positive values
453 digits
[0] = DASH_IDX
;
454 digitNum
= 1; // Skip the first iteration
455 numToShow
= -numToShow
;
458 // Find all digits for base's representation, starting with the most
460 for ( ; digitNum
< numDigits
; digitNum
++) {
461 long factor
= powersOfBase
[numDigits
- 1 - digitNum
];
462 digits
[digitNum
] = numToShow
/ factor
;
463 numToShow
-= digits
[digitNum
] * factor
;
466 // Find unnnecessary leading zeros and set them to BLANK
467 if (decPlaces
< 0) decPlaces
= 0;
469 for (digitNum
= 0 ; digitNum
< (numDigits
- 1 - decPlaces
) ; digitNum
++) {
470 if (digits
[digitNum
] == 0) {
471 digits
[digitNum
] = BLANK_IDX
;
473 // Exit once the first non-zero number is encountered
474 else if (digits
[digitNum
] <= 9) {
485 /******************************************************************************/
486 // Sets the 'digitCodes' that are required to display the input numbers
488 void SevSeg::setDigitCodes(byte digits
[], char decPlaces
) {
490 // Set the digitCode for each digit in the display
491 for (byte digitNum
= 0 ; digitNum
< numDigits
; digitNum
++) {
492 digitCodes
[digitNum
] = digitCodeMap
[digits
[digitNum
]];
493 // Set the decimal place segment
494 if (decPlaces
>= 0) {
495 if (digitNum
== numDigits
- 1 - decPlaces
) {
496 digitCodes
[digitNum
] |= 0x80;