1-phase PV router
Loading...
Searching...
No Matches
utils_display.h
Go to the documentation of this file.
1
12
13#ifndef UTILS_DISPLAY_H
14#define UTILS_DISPLAY_H
15
16#include "config_system.h"
17#include "config.h"
18#include "FastDivision.h"
19
21// General Configuration (Shared by SEG_HW and SEG)
23
24inline constexpr uint8_t noOfDigitLocations{ 4 };
25inline constexpr uint8_t noOfPossibleCharacters{ 14 };
26inline constexpr uint8_t UPDATE_PERIOD_FOR_DISPLAYED_DATA{ 50 }; // mains cycles
27inline constexpr uint8_t DISPLAY_SHUTDOWN_IN_HOURS{ 8 }; // auto-reset after this period of inactivity
28
30inline constexpr uint8_t MAX_DISPLAY_TIME_COUNT{ 10 }; // no of processing loops between display updates
31
32inline uint8_t charsForDisplay[noOfDigitLocations]{ 20, 20, 20, 20 }; // all blank
33
35// The 7-segment display can be driven in two ways:
36// 1. By a set of logic chips (74HC4543 7-segment display driver and 74HC138 2->4 line demultiplexer)
37// 2. By direct control of the segment lines and digit selection lines
38//
40
42// Hardware-Driven Display (SEG_HW)
44
45inline constexpr uint8_t DRIVER_CHIP_DISABLED{ HIGH };
46inline constexpr uint8_t DRIVER_CHIP_ENABLED{ LOW };
47
48// the primary segments are controlled by a pair of logic chips
49inline constexpr uint8_t noOfDigitSelectionLines{ 4 }; // <- for the 74HC4543 7-segment display driver
50inline constexpr uint8_t noOfDigitLocationLines{ 2 }; // <- for the 74HC138 2->4 line demultiplexer
51
52inline constexpr uint8_t enableDisableLine{ 5 }; // <- affects the primary 7 segments only (not the DP)
53inline constexpr uint8_t decimalPointLine{ 14 }; // <- this line has to be individually controlled.
54
55inline constexpr uint8_t digitLocationLine[noOfDigitLocationLines]{ 16, 15 };
56inline constexpr uint8_t digitSelectionLine[noOfDigitSelectionLines]{ 7, 9, 8, 6 };
57
59// The final column of digitValueMap[] is for the decimal point status. In this version,
60// the decimal point has to be treated differently than the other seven segments.
61//
63 LOW, LOW, LOW, LOW, // '0' <- element 0
64 LOW, LOW, LOW, HIGH, // '1' <- element 1
65 LOW, LOW, HIGH, LOW, // '2' <- element 2
66 LOW, LOW, HIGH, HIGH, // '3' <- element 3
67 LOW, HIGH, LOW, LOW, // '4' <- element 4
68 LOW, HIGH, LOW, HIGH, // '5' <- element 5
69 LOW, HIGH, HIGH, LOW, // '6' <- element 6
70 LOW, HIGH, HIGH, HIGH, // '7' <- element 7
71 HIGH, LOW, LOW, LOW, // '8' <- element 8
72 HIGH, LOW, LOW, HIGH, // '9' <- element 9
73 HIGH, HIGH, HIGH, HIGH, // ' ' <- element 10
74 LOW, HIGH, HIGH, HIGH, // 'F' <- element 11
75 HIGH, LOW, HIGH, LOW, // 'r' <- element 12
76 LOW, LOW, HIGH, LOW, // 'C' <- element 13
77};
78
79// a tidy means of identifying the DP status data when accessing the above table
80inline constexpr uint8_t DPstatus_columnID{ noOfDigitSelectionLines };
81
83 LOW, LOW, // Digit 1
84 LOW, HIGH, // Digit 2
85 HIGH, LOW, // Digit 3
86 HIGH, HIGH, // Digit 4
87};
88
107{
108 // Configure the IO drivers for the 4-digit display
109 pinMode(decimalPointLine, OUTPUT); // The 'decimal point' line
110
111 // Set up the control lines for the 74HC4543 7-segment display driver
112 for (uint8_t i = 0; i < noOfDigitSelectionLines; ++i)
113 {
114 pinMode(digitSelectionLine[i], OUTPUT);
115 }
116
117 // Set up the enable line for the 74HC4543 7-segment display driver
118 pinMode(enableDisableLine, OUTPUT);
120
121 // Set up the control lines for the 74HC138 2->4 demultiplexer
122 for (uint8_t i = 0; i < noOfDigitLocationLines; ++i)
123 {
124 pinMode(digitLocationLine[i], OUTPUT);
125 }
126}
127
142{
143 static uint8_t digitLocationThatIsActive = 0;
144
145 // 1. Disable the Decimal Point driver line
147
148 // 2. Disable the driver chip while changes are taking place
150
151 // 3. Determine the next digit location to be active
152 if (++digitLocationThatIsActive == noOfDigitLocations)
153 {
154 digitLocationThatIsActive = 0;
155 }
156
157 // 4. Set up the digit location drivers for the new active location
158 for (uint8_t line = 0; line < noOfDigitLocationLines; ++line)
159 {
160 const auto& lineState{ digitLocationMap[digitLocationThatIsActive][line] };
161 setPinState(digitLocationLine[line], lineState);
162 }
163
164 // 5. Determine the character to be displayed at this new location
165 const auto& digitVal{ charsForDisplay[digitLocationThatIsActive] };
166
167 // 6. Configure the 7-segment driver for the character to be displayed
168 for (uint8_t line = 0; line < noOfDigitSelectionLines; ++line)
169 {
170 const auto& lineState{ digitValueMap[digitVal & 0x7F][line] };
171 setPinState(digitSelectionLine[line], lineState);
172 }
173
174 // 7. Set up the Decimal Point driver line
175 setPinState(decimalPointLine, digitVal & 0x80); // DP
176
177
178 // 8. Enable the 7-segment driver chip
180}
181
182// End of config for the version with the extra logic chips
184
186// Software-Driven Display (SEG)
188
189inline constexpr uint8_t ON{ HIGH };
190inline constexpr uint8_t OFF{ LOW };
191
192inline constexpr uint8_t noOfSegmentsPerDigit{ 8 }; // includes one for the decimal point
193
199
200inline constexpr uint8_t digitSelectorPin[noOfDigitLocations]{ 16, 10, 13, 11 };
201inline constexpr uint8_t segmentDrivePin[noOfSegmentsPerDigit]{ 2, 5, 12, 6, 7, 9, 8, 14 };
202
204// The final column of segMap[] is for the decimal point status. In this version,
205// the decimal point is treated separately from the other seven segments.
206//
208 ON, ON, ON, ON, ON, ON, OFF, // '0' <- element 0
209 OFF, ON, ON, OFF, OFF, OFF, OFF, // '1' <- element 1
210 ON, ON, OFF, ON, ON, OFF, ON, // '2' <- element 2
211 ON, ON, ON, ON, OFF, OFF, ON, // '3' <- element 3
212 OFF, ON, ON, OFF, OFF, ON, ON, // '4' <- element 4
213 ON, OFF, ON, ON, OFF, ON, ON, // '5' <- element 5
214 ON, OFF, ON, ON, ON, ON, ON, // '6' <- element 6
215 ON, ON, ON, OFF, OFF, OFF, OFF, // '7' <- element 7
216 ON, ON, ON, ON, ON, ON, ON, // '8' <- element 8
217 ON, ON, ON, ON, OFF, ON, ON, // '9' <- element 9
218 OFF, OFF, OFF, OFF, OFF, OFF, OFF, // ' ' <- element 10
219 ON, OFF, OFF, OFF, ON, ON, ON, // 'F' <- element 11
220 OFF, OFF, OFF, OFF, ON, OFF, ON, // 'r' <- element 12
221 ON, OFF, OFF, ON, ON, ON, OFF, // 'C' <- element 13
222};
223
241{
242 // Set the pin mode for each segment drive pin
243 for (uint8_t i = 0; i < noOfSegmentsPerDigit; ++i)
244 {
245 pinMode(segmentDrivePin[i], OUTPUT);
246 }
247
248 // Set the pin mode for each digit selector pin
249 for (uint8_t i = 0; i < noOfDigitLocations; ++i)
250 {
251 pinMode(digitSelectorPin[i], OUTPUT);
252 }
253
254 // Disable all digit selector pins initially
255 for (uint8_t i = 0; i < noOfDigitLocations; ++i)
256 {
258 }
259
260 // Turn off all segment drive pins initially
261 for (uint8_t i = 0; i < noOfSegmentsPerDigit; ++i)
262 {
264 }
265}
266
286{
287 static uint8_t digitLocationThatIsActive{ 0 };
288
289 // 1. Deactivate the location which is currently being displayed
290 setPinState(digitSelectorPin[digitLocationThatIsActive], (uint8_t)DigitEnableStates::DIGIT_DISABLED);
291
292 // 2. Determine the next digit location to be displayed
293 if (++digitLocationThatIsActive == noOfDigitLocations)
294 {
295 digitLocationThatIsActive = 0;
296 }
297
298 // 3. Determine the relevant character for the new active location
299 const auto& digitVal{ charsForDisplay[digitLocationThatIsActive] };
300
301 // 4. Set up the segment drivers for the character to be displayed (includes the DP)
302 for (uint8_t segment = 0; segment < noOfSegmentsPerDigit - 1; ++segment)
303 {
304 const auto& segmentState{ segMap[digitVal & 0x7F][segment] };
305 setPinState(segmentDrivePin[segment], segmentState);
306 }
307 setPinState(segmentDrivePin[noOfSegmentsPerDigit - 1], digitVal & 0x80); // DP
308
309
310 // 5. Activate the digit-enable line for the new active location
311 setPinState(digitSelectorPin[digitLocationThatIsActive], (uint8_t)DigitEnableStates::DIGIT_ENABLED);
312}
313
314// End of config for the version without the extra logic chips
316
318// Shared Functions
320
329inline void initializeDisplay()
330{
331 if constexpr (TYPE_OF_DISPLAY == DisplayType::SEG_HW)
332 {
334 }
335 else if constexpr (TYPE_OF_DISPLAY == DisplayType::SEG)
336 {
338 }
339}
340
350inline void displayOff()
351{
353 {
354 return;
355 }
356
357 // Set display to " OFF" (right-aligned)
358 charsForDisplay[0] = 10; // Blank
359 charsForDisplay[1] = 0; // 'O' (reusing '0' character)
360 charsForDisplay[2] = 11; // 'F'
361 charsForDisplay[3] = 11; // 'F'
362}
363
372inline void displayForced()
373{
375 {
376 return;
377 }
378
379 // Set display to "FORC"
380 charsForDisplay[0] = 11; // 'F'
381 charsForDisplay[1] = 0; // 'O' (reusing '0' character)
382 charsForDisplay[2] = 12; // 'r'
383 charsForDisplay[3] = 13; // 'C'
384}
385
413inline void configureValueForDisplay(const bool _EDD_isActive, const uint16_t _ValueToDisplay, const bool _diversionEnabled = false,
414 const bool _loadForced = false)
415{
417 {
418 return;
419 }
420
421 // Check for forced load first
422 if (_loadForced)
423 {
425 return;
426 }
427
428 // If diversion is disabled, show "OFF"
429 if (!_diversionEnabled)
430 {
431 displayOff();
432 return;
433 }
434
435 if (!_EDD_isActive)
436 {
437 static uint8_t locationOfDot{ 0 };
438
439 // "walking dots" display
440 charsForDisplay[0] = 10;
441 charsForDisplay[1] = 10;
442 charsForDisplay[2] = 10;
443 charsForDisplay[3] = 10;
444
445 if (++locationOfDot == noOfDigitLocations)
446 {
447 locationOfDot = 0;
448 }
449
450 charsForDisplay[locationOfDot] |= 0x80; // dot
451
452 return;
453 }
454
455 const auto energyValueExceeds10kWh{ _ValueToDisplay > 9999u };
456
457 uint32_t tmpVal{ energyValueExceeds10kWh ? divu10(_ValueToDisplay) : _ValueToDisplay };
458
459 divmod10(tmpVal, tmpVal, charsForDisplay[3]); // Extract units place
460 divmod10(tmpVal, tmpVal, charsForDisplay[2]); // Extract tens place
461 divmod10(tmpVal, tmpVal, charsForDisplay[1]); // Extract hundreds place
462 charsForDisplay[0] = tmpVal; // Remaining value is the thousands place
463
464 // assign the decimal point location
465 if (energyValueExceeds10kWh)
466 {
467 charsForDisplay[1] |= 0x80;
468 } // dec point after 2nd digit
469 else
470 {
471 charsForDisplay[0] |= 0x80;
472 } // dec point after 1st digit
473}
474
494{
495 // This routine keeps track of which digit is being displayed and checks when its
496 // display time has expired. It then makes the necessary adjustments for displaying
497 // the next digit.
498 // The two versions of the hardware require different logic.
499
501 {
502 static uint8_t displayTime_count{ 0 };
503 if (++displayTime_count != MAX_DISPLAY_TIME_COUNT)
504 {
505 return;
506 }
507 displayTime_count = 0;
508 }
509
510 if constexpr (TYPE_OF_DISPLAY == DisplayType::SEG_HW)
511 {
513 }
514 else if constexpr (TYPE_OF_DISPLAY == DisplayType::SEG)
515 {
517 }
518}
519
520#endif /* UTILS_DISPLAY_H */
void divmod10(uint32_t in, uint32_t &div, uint8_t &mod)
uint16_t divu10(uint16_t n)
Configuration values to be set by the end-user.
constexpr DisplayType TYPE_OF_DISPLAY
Definition config.h:51
Basic configuration values to be set by the end-user.
constexpr uint32_t mainsCyclesPerHour
void initializeDisplay()
Initializes the display for hardware-driven 7-segment displays.
void initializeDisplaySW()
Initializes the display for software-driven 7-segment displays.
void configureValueForDisplay(const bool _EDD_isActive, const uint16_t _ValueToDisplay, const bool _diversionEnabled=false, const bool _loadForced=false)
Configures the value for display on a 7-segment display.
void displayForced()
Displays "FORC" on the 7-segment display for forced load override.
void update7SegmentSWDisplay()
Updates the 7-segment display for the next digit (software-driven).
void initializeDisplayHW()
Initializes the display for hardware-driven 7-segment displays.
void update7SegmentHWDisplay()
Updates the 7-segment display for the next digit (hardware-driven).
void refresh7SegDisplay()
Refreshes the display by updating the active digit and its segments.
void displayOff()
Displays "OFF" on the 7-segment display.
uint8_t i
constexpr uint8_t noOfSegmentsPerDigit
constexpr uint8_t digitValueMap[noOfPossibleCharacters][noOfDigitSelectionLines]
constexpr uint8_t segMap[noOfPossibleCharacters][noOfSegmentsPerDigit - 1]
constexpr uint8_t decimalPointLine
constexpr uint8_t enableDisableLine
constexpr uint8_t UPDATE_PERIOD_FOR_DISPLAYED_DATA
constexpr uint8_t DRIVER_CHIP_DISABLED
constexpr uint8_t noOfDigitSelectionLines
constexpr uint8_t digitLocationLine[noOfDigitLocationLines]
constexpr uint8_t digitSelectionLine[noOfDigitSelectionLines]
constexpr uint8_t noOfDigitLocationLines
constexpr uint8_t ON
constexpr uint8_t digitSelectorPin[noOfDigitLocations]
uint8_t charsForDisplay[noOfDigitLocations]
constexpr uint8_t DPstatus_columnID
constexpr uint8_t noOfDigitLocations
constexpr uint8_t OFF
constexpr uint8_t noOfPossibleCharacters
constexpr uint8_t digitLocationMap[noOfDigitLocations][noOfDigitLocationLines]
DigitEnableStates
constexpr uint8_t DRIVER_CHIP_ENABLED
constexpr uint32_t displayShutdown_inMainsCycles
constexpr uint8_t DISPLAY_SHUTDOWN_IN_HOURS
constexpr uint8_t segmentDrivePin[noOfSegmentsPerDigit]
constexpr uint8_t MAX_DISPLAY_TIME_COUNT
constexpr void setPinState(const uint8_t pin, const bool bState)
Set the Pin state for the specified pin.
Definition utils_pins.h:111