diff --git a/README.md b/README.md index bf70648..927888a 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,14 @@ Here some features contributed by the community regarding the original one: Please see the examples for details. +### Digit select inversion support + +Some Multi Function Shield clones use inverted digit select logic. If the display digits are selected incorrectly on your board, enable the following option before compiling: + +```cpp +#define MFS_INVERT_DIGIT_SELECT 1 +``` + ## PlatformIO full Demo project Please install first [PlatformIO](http://platformio.org/) open source ecosystem for IoT development compatible with **Arduino** IDE and its command line tools (Windows, MacOs and Linux). Also, you may need to install [git](http://git-scm.com/) in your system. diff --git a/examples/03 Applications/Alarm_Clock/Alarm_Clock.ino b/examples/03 Applications/Alarm_Clock/Alarm_Clock.ino index 4bbb208..111dcf6 100644 --- a/examples/03 Applications/Alarm_Clock/Alarm_Clock.ino +++ b/examples/03 Applications/Alarm_Clock/Alarm_Clock.ino @@ -1,16 +1,20 @@ -#include #include #include /* - - 24h Alarm Clock sample + 24h Alarm Clock sample - adaptado para hpsaturn/MultiFuncShield button 1 : hold to set time or alarm button 2 : press to view alarm time or cancel alarm if in progress - button 3 : increment hour / minute when setting (alarm) time. Hold to toggle alarm setting. - + button 3 : increment hour / minute when setting (alarm) time. + Hold to toggle alarm setting. + LED1 : on = alarm enabled + + Ajuste feito: + - Removido #include + - Removido Timer1.initialize() + - Trocado MFS.initialize(&Timer1) por MFS.initialize() */ volatile unsigned int clockMilliSeconds = 0; @@ -25,7 +29,6 @@ volatile byte alarmEnabled = false; byte alarmTogglePressed = false; - enum displayModeValues { MODE_CLOCK_TIME, @@ -41,193 +44,195 @@ byte displayMode = MODE_CLOCK_TIME; //-------------------------------------------------------------------------------------------------- void setup() { - Timer1.initialize(); + /* + Na biblioteca hpsaturn, initialize() não recebe TimerOne. + A própria biblioteca já cuida da interrupção interna. + */ MFS.userInterrupt = clockISR; - MFS.initialize(&Timer1); - + MFS.initialize(); + MFS.blinkDisplay(DIGIT_ALL); //MFS.beep(500); } - void loop() { - // put your main code here, to run repeatedly: - byte btn = MFS.getButton(); - + switch (displayMode) { case MODE_CLOCK_TIME: - displayTime(clockHours, clockMinutes); - - if (btn == BUTTON_2_PRESSED) - { - MFS.beep(0); // cancel the alarm. - displayMode = MODE_ALARM_TIME; - } - else if (btn == BUTTON_1_LONG_PRESSED) - { - MFS.blinkDisplay(DIGIT_ALL, OFF); - MFS.blinkDisplay(DIGIT_1 | DIGIT_2); - displayMode = MODE_CLOCK_TIME_SET_HOUR; - clockEnabled = false; - clockMilliSeconds = 0; - clockSeconds = 0; - } - else if (btn == BUTTON_3_LONG_PRESSED && !alarmTogglePressed) - { - alarmTogglePressed = true; - alarmEnabled = !alarmEnabled; - MFS.writeLeds(LED_1, alarmEnabled); - } - else if (btn == BUTTON_3_LONG_RELEASE) - { - alarmTogglePressed = false; - } - break; - + displayTime(clockHours, clockMinutes); + + if (btn == BUTTON_2_PRESSED) + { + MFS.beep(0); // cancel the alarm. + displayMode = MODE_ALARM_TIME; + } + else if (btn == BUTTON_1_LONG_PRESSED) + { + MFS.blinkDisplay(DIGIT_ALL, OFF); + MFS.blinkDisplay(DIGIT_1 | DIGIT_2); + displayMode = MODE_CLOCK_TIME_SET_HOUR; + clockEnabled = false; + clockMilliSeconds = 0; + clockSeconds = 0; + } + else if (btn == BUTTON_3_LONG_PRESSED && !alarmTogglePressed) + { + alarmTogglePressed = true; + alarmEnabled = !alarmEnabled; + MFS.writeLeds(LED_1, alarmEnabled); + } + else if (btn == BUTTON_3_LONG_RELEASE) + { + alarmTogglePressed = false; + } + break; + case MODE_CLOCK_TIME_SET_HOUR: - if (btn == BUTTON_1_PRESSED) + if (btn == BUTTON_1_PRESSED) + { + MFS.blinkDisplay(DIGIT_1 | DIGIT_2, OFF); + MFS.blinkDisplay(DIGIT_3 | DIGIT_4); + displayMode = MODE_CLOCK_TIME_SET_MINUTE; + } + else if (btn == BUTTON_3_PRESSED || btn == BUTTON_3_LONG_PRESSED) + { + clockHours++; + if (clockHours >= 24) { - MFS.blinkDisplay(DIGIT_1 | DIGIT_2, OFF); - MFS.blinkDisplay(DIGIT_3 | DIGIT_4); - displayMode = MODE_CLOCK_TIME_SET_MINUTE; + clockHours = 0; } - else if (btn == BUTTON_3_PRESSED || btn == BUTTON_3_LONG_PRESSED) - { - clockHours++; - if (clockHours >= 24) - { - clockHours = 0; - } - displayTime(clockHours, clockMinutes); - } - break; - + displayTime(clockHours, clockMinutes); + } + break; + case MODE_CLOCK_TIME_SET_MINUTE: - if (btn == BUTTON_1_PRESSED) - { - MFS.blinkDisplay(DIGIT_3 | DIGIT_4, OFF); - displayMode = MODE_CLOCK_TIME; - clockEnabled = true; - } - else if (btn == BUTTON_3_PRESSED || btn == BUTTON_3_LONG_PRESSED) + if (btn == BUTTON_1_PRESSED) + { + MFS.blinkDisplay(DIGIT_3 | DIGIT_4, OFF); + displayMode = MODE_CLOCK_TIME; + clockEnabled = true; + } + else if (btn == BUTTON_3_PRESSED || btn == BUTTON_3_LONG_PRESSED) + { + clockMinutes++; + if (clockMinutes >= 60) { - clockMinutes++; - if (clockMinutes >= 60) - { - clockMinutes = 0; - } - displayTime(clockHours, clockMinutes); + clockMinutes = 0; } - break; - + displayTime(clockHours, clockMinutes); + } + break; + case MODE_ALARM_TIME: - displayTime(alarmHours, alarmMinutes); + displayTime(alarmHours, alarmMinutes); + + if (btn == BUTTON_2_SHORT_RELEASE || btn == BUTTON_2_LONG_RELEASE) + { + displayMode = MODE_CLOCK_TIME; + } + else if (btn == BUTTON_1_LONG_PRESSED) + { + MFS.blinkDisplay(DIGIT_ALL, OFF); + MFS.blinkDisplay(DIGIT_1 | DIGIT_2); + displayMode = MODE_ALARM_TIME_SET_HOUR; + alarmEnabled = false; + } + break; - if (btn == BUTTON_2_SHORT_RELEASE || btn == BUTTON_2_LONG_RELEASE) - { - displayMode = MODE_CLOCK_TIME; - } - else if (btn == BUTTON_1_LONG_PRESSED) - { - MFS.blinkDisplay(DIGIT_ALL, OFF); - MFS.blinkDisplay(DIGIT_1 | DIGIT_2); - displayMode = MODE_ALARM_TIME_SET_HOUR; - alarmEnabled = false; - } - break; - case MODE_ALARM_TIME_SET_HOUR: - if (btn == BUTTON_1_PRESSED) - { - MFS.blinkDisplay(DIGIT_1 | DIGIT_2, OFF); - MFS.blinkDisplay(DIGIT_3 | DIGIT_4); - displayMode = MODE_ALARM_TIME_SET_MINUTE; - } - else if (btn == BUTTON_3_PRESSED || btn == BUTTON_3_LONG_PRESSED) + if (btn == BUTTON_1_PRESSED) + { + MFS.blinkDisplay(DIGIT_1 | DIGIT_2, OFF); + MFS.blinkDisplay(DIGIT_3 | DIGIT_4); + displayMode = MODE_ALARM_TIME_SET_MINUTE; + } + else if (btn == BUTTON_3_PRESSED || btn == BUTTON_3_LONG_PRESSED) + { + alarmHours++; + if (alarmHours >= 24) { - alarmHours++; - if (alarmHours >= 24) - { - alarmHours = 0; - } - displayTime(alarmHours, alarmMinutes); + alarmHours = 0; } - break; - + displayTime(alarmHours, alarmMinutes); + } + break; + case MODE_ALARM_TIME_SET_MINUTE: - if (btn == BUTTON_1_PRESSED) - { - MFS.blinkDisplay(DIGIT_3 | DIGIT_4, OFF); - displayMode = MODE_CLOCK_TIME; - alarmEnabled = true; - MFS.writeLeds(LED_1, ON); - } - else if (btn == BUTTON_3_PRESSED || btn == BUTTON_3_LONG_PRESSED) + if (btn == BUTTON_1_PRESSED) + { + MFS.blinkDisplay(DIGIT_3 | DIGIT_4, OFF); + displayMode = MODE_CLOCK_TIME; + alarmEnabled = true; + MFS.writeLeds(LED_1, ON); + } + else if (btn == BUTTON_3_PRESSED || btn == BUTTON_3_LONG_PRESSED) + { + alarmMinutes++; + if (alarmMinutes >= 60) { - alarmMinutes++; - if (alarmMinutes >= 60) - { - alarmMinutes = 0; - } - displayTime(alarmHours, alarmMinutes); + alarmMinutes = 0; } - break; + displayTime(alarmHours, alarmMinutes); + } + break; } } - -void displayTime (byte hours, byte minutes) +void displayTime(byte hours, byte minutes) { char time[5]; - + sprintf(time, "%03d", (hours * 100) + minutes); MFS.write(time, 1); } //-------------------------------------------------------------------------------------------------- -void clockISR () +void clockISR() { // Perform ripple count for all time components. if (clockEnabled) { clockMilliSeconds++; + if (clockMilliSeconds >= 1000) { clockMilliSeconds = 0; - + clockSeconds++; + if (clockSeconds >= 60) { clockSeconds = 0; - + clockMinutes++; + if (clockMinutes >= 60) { clockMinutes = 0; - + clockHours++; + if (clockHours >= 24) { clockHours = 0; } } - + // If current time coincides with alarm time, and alarm is enabled, engage the alarm. if (alarmEnabled && (clockMinutes == alarmMinutes) && (clockHours == alarmHours)) { MFS.beep( - 10, // on period - 5, // off period - 4, // number of cycles - 100, // number of loop cycles - 50 // delay between loop cycles - ); + 10, // on period + 5, // off period + 4, // number of cycles + 100, // number of loop cycles + 50 // delay between loop cycles + ); } } } } -} - +} \ No newline at end of file diff --git a/src/MultiFuncShield.cpp b/src/MultiFuncShield.cpp index 9514773..6ebb3b8 100644 --- a/src/MultiFuncShield.cpp +++ b/src/MultiFuncShield.cpp @@ -1,5 +1,25 @@ #include "MultiFuncShield.h" +/* + DISPLAY COMPATIBILITY OPTION + ------------------------------------------------------------ + Some Multi Function Shield clones use the same 74HC595 display + pins as the classic board, but their 4-digit display uses + active-LOW digit selection. + + Set to 0 for the classic/original shield behavior. + Set to 1 for displays that show malformed characters and need + inverted/active-LOW digit select values. + + Tested pins: + DATA = D8 + CLOCK = D7 + LATCH = D4 +*/ +#ifndef MFS_INVERT_DIGIT_SELECT +#define MFS_INVERT_DIGIT_SELECT 0 +#endif + #define BUTTON_SAMPLE_INTERVAL_SCALE 20 #define BUTTON_SAMPLE_INTERVAL (1000 / BUTTON_SAMPLE_INTERVAL_SCALE) @@ -17,6 +37,40 @@ const byte SEGMENT_MAP_ALPHA[] = {136, 131, 167, 161, 134, 142, 144, 139 ,207, 2 /* Byte maps to select digit 1 to 4 */ const byte SEGMENT_SELECT[] = {0xF1,0xF2,0xF4,0xF8}; + +/* + Display output normalization helpers. + + The original library segment maps are active LOW. On displays that use + inverted/active-LOW digit selection, the segment byte must be normalized + and the digit-select byte must be generated as: + + digit 0 = 0xFE + digit 1 = 0xFD + digit 2 = 0xFB + digit 3 = 0xF7 + + Keeping this logic in helper functions makes the hardware variation clear + and avoids unexplained bit inversions inside the low-level write routine. +*/ +static inline byte normalizeSegmentValue(byte value) +{ +#if MFS_INVERT_DIGIT_SELECT + return ~value; +#else + return value; +#endif +} + +static inline byte normalizeDigitSelect(byte segment) +{ +#if MFS_INVERT_DIGIT_SELECT + return (byte)(0xF0 | ((~(1 << segment)) & 0x0F)); +#else + return SEGMENT_SELECT[segment]; +#endif +} + const char DISPLAY_OVERFLOW_ERROR = 'E'; const byte BLINK_ON_COUNT = 65; @@ -1204,16 +1258,19 @@ int MedianOf9(int s0, int s1, int s2, int s3, int s4, int s5, int s6, int s7, in /* Write a value to one of the 4 digits of the display */ void WriteValueToSegment(byte Segment, byte Value) { + byte valueOut = normalizeSegmentValue(Value); + byte digitOut = normalizeDigitSelect(Segment); + bitClear(PORTD, 4); for (uint8_t i = 0; i < 8; i++) { - bitWrite(PORTB, 0, !!(Value & (1 << (7 - i)))); + bitWrite(PORTB, 0, !!(valueOut & (1 << (7 - i)))); bitSet(PORTD, 7); bitClear(PORTD, 7); } for (uint8_t i = 0; i < 8; i++) { - bitWrite(PORTB, 0, !!(SEGMENT_SELECT[Segment] & (1 << (7 - i)))); + bitWrite(PORTB, 0, !!(digitOut & (1 << (7 - i)))); bitSet(PORTD, 7); bitClear(PORTD, 7); } @@ -1265,16 +1322,19 @@ int MedianOf9(int s0, int s1, int s2, int s3, int s4, int s5, int s6, int s7, in /* Write a value to one of the 4 digits of the display */ void WriteValueToSegment(byte Segment, byte Value) { + byte valueOut = normalizeSegmentValue(Value); + byte digitOut = normalizeDigitSelect(Segment); + bitClear(PORTD, 4); for (uint8_t i = 0; i < 8; i++) { - bitWrite(PORTB, 4, !!(Value & (1 << (7 - i)))); + bitWrite(PORTB, 4, !!(valueOut & (1 << (7 - i)))); bitSet(PORTE, 6); bitClear(PORTE, 6); } for (uint8_t i = 0; i < 8; i++) { - bitWrite(PORTB, 4, !!(SEGMENT_SELECT[Segment] & (1 << (7 - i)))); + bitWrite(PORTB, 4, !!(digitOut & (1 << (7 - i)))); bitSet(PORTE, 6); bitClear(PORTE, 6); } @@ -1336,16 +1396,19 @@ void WriteValueToSegment(byte Segment, byte Value) /* Write a value to one of the 4 digits of the display */ void WriteValueToSegment(byte Segment, byte Value) { + byte valueOut = normalizeSegmentValue(Value); + byte digitOut = normalizeDigitSelect(Segment); + bitClear(PORTG, 5); for (uint8_t i = 0; i < 8; i++) { - bitWrite(PORTH, 5, !!(Value & (1 << (7 - i)))); + bitWrite(PORTH, 5, !!(valueOut & (1 << (7 - i)))); bitSet(PORTH, 4); bitClear(PORTH, 4); } for (uint8_t i = 0; i < 8; i++) { - bitWrite(PORTH, 5, !!(SEGMENT_SELECT[Segment] & (1 << (7 - i)))); + bitWrite(PORTH, 5, !!(digitOut & (1 << (7 - i)))); bitSet(PORTH, 4); bitClear(PORTH, 4); }