Closed JunctionRunner closed 3 years ago
Hi @XOIIO - I think I understand what you are trying to do. You might be over-complicating it. The key thing to remember is that millis() is your accurate clock in milliseconds. You basically want to measure time as a delta from that (elapsed time) and use that to produce the countdown display (subtraction).
Here is my take on what I think you are trying to do:
#include <TM1637TinyDisplay6.h>
/* Digital Pins to TM1637 */
#define CLK 10
#define DIO 11
/* Useful Constants */
#define SECS_PER_MIN (60UL)
#define SECS_PER_HOUR (3600UL)
#define SECS_PER_DAY (SECS_PER_HOUR * 24L)
/* Useful Macros for time (s) */
#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN)
#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN)
#define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR)
#define elapsedDays(_time_) ( _time_ / SECS_PER_DAY)
#define hmsToMillis(_h_, _m_, _s_) ((_h_ * SECS_PER_HOUR) + (_m_ * SECS_PER_MIN) + _s_ ) * 1000ul;
/* Set up Display */
TM1637TinyDisplay6 display(CLK, DIO);
/* Global Variables in milliseconds */
unsigned long startTime;
unsigned long lastLoopTime;
unsigned long startCount;
unsigned long dispout;
void setup()
{
display.setBrightness(BRIGHT_HIGH);
display.clear();
display.showString("boot");
delay(500);
// Record Epoch - Same as Timer Reset
startTime = millis();
// Time to countdown from in h, m, s
startCount = hmsToMillis(1, 0, 10);
}
void loop()
{
unsigned long timeNow = millis();
unsigned long timeElapsed = timeNow - startTime; // true amount of time since start
unsigned long counter = startCount - timeElapsed; // current state of countdown
// Update Display - every 10ms
if (timeNow - lastLoopTime >= 10) {
lastLoopTime = timeNow; // remember last time we displayed
// Compute the values
unsigned long HOURS = numberOfHours(counter / 1000);
unsigned long MINUTES = numberOfMinutes(counter / 1000);
unsigned long SECONDS = numberOfSeconds(counter / 1000);
unsigned long MILLISECONDS = (counter % 1000lu) / 10;
// Convert time values to integer to display
if (HOURS <= 0) {
//This one if timer is below one hour
dispout = ((MINUTES * 10000) + (SECONDS * 100) + MILLISECONDS);
} else {
//This one if timer is above one hour
dispout = ((HOURS * 10000) + (MINUTES * 100) + SECONDS);
}
uint8_t dots = 0b01010000;
display.showNumberDec(dispout, dots);
}
}
Hi, that runs great, the timer code was contributed by someone else as this is my first go at counting down in such a manner, so I wasn't sure where the issue was, I wasn't sure if there was some sort of possible delay or time needed by the display to process whatever information it gets, but this, and my testing before shows that it's not the case.
This code looks to be a much more elegant way of counting down as well, I'm guessing that I'll be able to replace the numerical entries in "startCount = hmsToMillis(1, 0, 10);" with variables to tie in the entry using the keypad, I'll test that out and report back.
Not quite sure if I'll get to it tonight, starting to feel a bit tired, but I'm feeling very optimistic!
That's great! I think many people expect instructions to take zero time. That is not the case. Each function call or math operation will take cycles. When you call showNumberDec() it has a sequence of instructions and signal timing delays it must execute to send the data to the TM1637 module. The amount of time to make those calls will vary based on the number you are sending as well. You can only reliable measure time by using the built in clock via the millis() function.
You are correct. With my sketch above, you just need to adjust the parameters or you can use something like this if it helps:
// Set countdown timer in h, m, s
int Hour = 1;
int Min = 0;
int Sec = 10;
startCount = hmsToMillis(Hour, Min, Sec);
Oh, who am I kidding, there's no way I'd be able to sleep.
Merged your timer code with what I have for setting the variables from the keypad and it works beautifully. Now I just need to set it up to display the numbers as you enter them, maybe a menu and monitor some inputs and it's golden. Thanks a million!
`#include
// Module connection pins (Digital Pins)
const byte ROWS = 4; //setting up keypad const byte COLS = 3;
char hexaKeys[ROWS][COLS] = { {'1', '2', '3'}, {'4', '5', '6'}, {'7', '8', '9'}, {'*', '0', '#'} };
byte rowPins[ROWS] = {2, 3, 4, 5}; byte colPins[COLS] = {6, 7, 8};
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); char customKey; TM1637TinyDisplay6 display(CLK, DIO);
// gubbins to set timer variables
int sethours1; int sethours2; int setminutes1; int setminutes2; int setseconds1; int setseconds2; int timeup = 0;
// actual timer parts start here
/ Useful Constants /
/ Useful Macros for time (s) /
/ Global Variables in milliseconds / unsigned long startTime; unsigned long lastLoopTime; unsigned long startCount; unsigned long dispout;
int hours = 0; int minutes = 0; int seconds = 0;
void setup(){ Serial.begin(115200); char timerdisp[7]; timerdisp[0] = '-'; // 6 character string for display output of timer timerdisp[1] = '-'; timerdisp[2] = '-'; timerdisp[3] = '-'; timerdisp[4] = '-'; timerdisp[5] = '-'; timerdisp[6] = 0; // 7th array element is a null terminator Serial.begin(115200); display.setBrightness(BRIGHT_LOW); display.clear(); display.showString(timerdisp); delay(1000);
settimer(); }
void loop(){ unsigned long timeNow = millis(); unsigned long timeElapsed = timeNow - startTime; // true amount of time since start long int counter = startCount - timeElapsed; // current state of countdown
// Update Display - every 10ms if (timeNow - lastLoopTime >= 10) { lastLoopTime = timeNow; // remember last time we displayed
// Compute the values
unsigned long HOURS = numberOfHours(counter / 1000);
unsigned long MINUTES = numberOfMinutes(counter / 1000);
unsigned long SECONDS = numberOfSeconds(counter / 1000);
unsigned long MILLISECONDS = (counter % 1000lu) / 10;
// Convert time values to integer to display
if (HOURS <= 0) {
//This one if timer is below one hour
dispout = ((MINUTES * 10000) + (SECONDS * 100) + MILLISECONDS);
} else {
//This one if timer is above one hour
dispout = ((HOURS * 10000) + (MINUTES * 100) + SECONDS);
}
uint8_t dots = 0b01010000;
display.showNumberDec(dispout, dots, true);
} Serial.println(counter); if (counter <= 0){ timerstopped(); } }
void settimer(){
//set first hour section
Serial.println("set hours"); //setting hours
sethours1 = (customKeypad.waitForKey() - 48); //subtract 48 to convert hex to decimal Serial.println(sethours1); hours = (sethours1 * 10); Serial.println(hours);
sethours2 = (customKeypad.waitForKey() - 48); //subtract 48 to convert hex to decimal Serial.println(sethours2); hours = (hours + sethours2); Serial.println(hours);
Serial.println("set Minutes"); //setting minutes
setminutes1 = (customKeypad.waitForKey() - 48); //subtract 48 to convert hex to decimal Serial.println(setminutes1); minutes = (setminutes1 * 10); Serial.println(minutes);
setminutes2 = (customKeypad.waitForKey() - 48); //subtract 48 to convert hex to decimal Serial.println(setminutes2); minutes = (minutes + setminutes2); Serial.println(minutes);
Serial.println("set Seconds"); //setting seconds
setseconds1 = (customKeypad.waitForKey() - 48); //subtract 48 to convert hex to decimal Serial.println(setseconds1); seconds = (setseconds1 * 10); Serial.println(seconds);
setseconds2 = (customKeypad.waitForKey() - 48); //subtract 48 to convert hex to decimal Serial.println(setseconds2); seconds = (seconds + setseconds2); Serial.println(seconds);
Serial.println("end of set timer");
// Record Epoch - Same as Timer Reset startTime = millis(); startCount = hmsToMillis(hours, minutes, seconds); loop(); }
void timerstopped(){ timeup = 1; Serial.println("Timer Stopped"); while (timeup == 1) { display.showString("000000"); delay(500); display.clear(); delay(500); } }`
Hmm, might pick your brain for one other thing since I've been trying a few things and haven't had any luck, possibly due to lack of sleep.
Basically, it will instruct you to set the time with a string in HH MM SS format, and then switch to all zeroes. After that, as you type in the numbers I'm hoping them to pop up on the screen in the appropriate positions.
I did try using something similar to " dispout = ((HOURS 10000) + (MINUTES 100) + SECONDS);" with the "setx1 or setx2" variables, however it glitched out if the hour number was too high when multiplied.
I figured updating a char array would be the way to do it but can't figure out how to format the char array to basically input the button presses.
I figure calling this section after each button press and updating the char array is cleanest, but yeah, can't quite get it to work, I'm sure it's simple but I haven't really used char arrays either.
`
void showinput(){ char showinputdisp[7]; showinputdisp[0] = '(sethours1)'; showinputdisp[1] = '(sethours2)'; showinputdisp[2] = setminutes1; showinputdisp[3] = setminutes2; showinputdisp[4] = setseconds1; showinputdisp[5] = setseconds2; showinputdisp[6] = 0; // 7th array element is a null terminator display.showString(showinputdisp); } `
I think I need something along the lines of this, though it's not quite there., it actually freezes the sketch it seems. Oh well, time to sleep.
edit: Actually, having the decimal points lit up for this too would be good, so doing it numerically might be best, when I tried to use decimals with a string it didn't work iirc.
`void settimer(){
char showinputdisp[7]; showinputdisp[0] = '0'; showinputdisp[1] = '0'; showinputdisp[2] = '0'; showinputdisp[3] = '0'; showinputdisp[4] = '0'; showinputdisp[5] = '0'; showinputdisp[6] = 0; // 7th array element is a null terminator
display.showString("Set time - Hours Minutes Seconds"); display.showString(showinputdisp);
//set first hour section
Serial.println("set hours"); //setting hours
sethours1 = (customKeypad.waitForKey() - 48); //subtract 48 to convert hex to decimal Serial.println(sethours1); hours = (sethours1 * 10); Serial.println(hours); strcpy(showinputdisp[0],sethours1); display.showString(showinputdisp);
sethours2 = (customKeypad.waitForKey() - 48); //subtract 48 to convert hex to decimal Serial.println(sethours2); hours = (hours + sethours2); Serial.println(hours); strcpy(showinputdisp[1],sethours2); display.showString(showinputdisp);
Serial.println("set Minutes"); //setting minutes
setminutes1 = (customKeypad.waitForKey() - 48); //subtract 48 to convert hex to decimal Serial.println(setminutes1); minutes = (setminutes1 * 10); Serial.println(minutes); strcpy(showinputdisp[2],setminutes1); display.showString(showinputdisp);
setminutes2 = (customKeypad.waitForKey() - 48); //subtract 48 to convert hex to decimal Serial.println(setminutes2); minutes = (minutes + setminutes2); Serial.println(minutes); strcpy(showinputdisp[3],setminutes2); display.showString(showinputdisp);
Serial.println("set Seconds"); //setting seconds
setseconds1 = (customKeypad.waitForKey() - 48); //subtract 48 to convert hex to decimal Serial.println(setseconds1); seconds = (setseconds1 * 10); Serial.println(seconds); strcpy(showinputdisp[4],setseconds1); display.showString(showinputdisp);
setseconds2 = (customKeypad.waitForKey() - 48); //subtract 48 to convert hex to decimal Serial.println(setseconds2); seconds = (seconds + setseconds2); Serial.println(seconds); strcpy(showinputdisp[5],setseconds2); display.showString(showinputdisp);
Serial.println("end of set timer");
// Record Epoch - Same as Timer Reset startTime = millis(); startCount = hmsToMillis(hours, minutes, seconds); loop();
} `
Hi @XOIIO nice job on getting it to work!
You can use showNumberDec() to display Hours, Minutes and Seconds separately using the position and length parameters.
showNumberDec(int num, uint8_t dots = 0, bool leading_zero = false, uint8_t length = MAXDIGITS, uint8_t pos = 0);
See this: https://github.com/jasonacox/TM1637TinyDisplay/blob/master/TM1637TinyDisplay.h for more details. Here is how it would fit in your code:
uint8_t dots = 0b01010000;
if (HOURS <= 0) {
// Display M:S.ms if timer is below one hour
display.showNumberDec(MINUTES, dots, true, 2, 0);
display.showNumberDec(SECONDS, dots, true, 2, 2);
display.showNumberDec(MILLISECONDS, 0, true, 2, 4);
} else {
// Display H:M:S if timer is above one hour
display.showNumberDec(HOURS, dots, true, 2, 0);
display.showNumberDec(MINUTES, dots, true, 2, 2);
display.showNumberDec(SECONDS, 0, true, 2, 4);
}
By the way, here is a pro tip for Github, you can paste syntax highlighted and formatted python code by prefixing your code snip with this:
```python
loop();
of course end with ``` and it will look like
loop();
Hi, so I have a thread on the arduino forum where I'm working on a countdown timer where you enter the time with a matrix keypad, and the desired behavior is that if the time is one hour or greater, the display shows it as such
02.25.30
as in two hours, 25 minutes, 30 seconds.
Then, when it drops to one hour and below, I want to have milliseconds update on the display, so it all shifts over like so
59.30.12
59 minutes, 30 seconds, 12ms
However, when I try to update the display at speed in my sketch it slows the whole thing down, basically making one second take three seconds. If I displayed the time in only milliseconds, without turning it into a two digit value, 700ms would take an entire three seconds to change to 600ms, however, the last two digits update extremely fast without any issue.
Its really peculiar, and the sketch being slowed down is fixed by commenting out the display.showNumberDec line, so it's somehow related to the output.
I figure you might be able to help or have a clue as to why this is, the display is clearly able to update extremely fast, but for some reason in this sketch, it bogs down.
Heres my forum thread, with the later few posts being the one cracking down on identifying the issue. https://forum.arduino.cc/t/need-help-setting-up-a-countdown-timer-which-you-set-using-a-keypad/864081/43
`#include
//
//// Module connection pins (Digital Pins)
define CLK 10
define DIO 11
TM1637TinyDisplay6 display(CLK, DIO); unsigned long dispout;
byte hours = 0; byte minutes = 12; byte seconds = 10;
//number of milliseconds; unsigned long counter = ((hours 3600ul) + (minutes 60ul) + seconds ) * 1000ul;
unsigned long timeMICROS; unsigned long secondMICROS; unsigned long timeMillis;
unsigned long num; unsigned long leftDecimal; unsigned long rightDecimal;
unsigned long HOURS; unsigned long temp; unsigned long MINUTES; unsigned long SECONDS; unsigned long MILLISECONDS;
void setup() { display.setBrightness(BRIGHT_LOW); display.clear(); display.showString("boot");
Serial.begin(115200); // <---------------------<<<<<<<<<<<<<<<<<
Serial.println("Start the count down");
} //END of setup()
void loop() { unsigned long timeNow = micros();
//***** //every 1ms do this if (timeNow - timeMICROS >= 1000) { //restart the TIMER timeMICROS = timeMICROS + 1000;
}
//***** // RAW 10X milliseconds //every 10ms // if (timeNow - secondMICROS >= 10000) //10000 = 10ms // { //restart the TIMER //secondMICROS = timeNow;
//restart the TIMER // secondMICROS = secondMICROS + 10000;
// num = counter; // leftDecimal = num / 1000; // rightDecimal = (counter - leftDecimal * 1000) / 10; // Serial.print("Milliseconds = "); // Serial.print(leftDecimal); // Serial.print("."); // Serial.println(rightDecimal); // }
//***** //every 10ms do this //if (millis() - timeMillis >= 10)
//every 100ms do this if (millis() - timeMillis >= 100) { //restart the TIMER every 10ms timeMillis = timeMillis + 10;
// dispout = ((HOURS 10000) + (MINUTES 100) + SECONDS); //This one if timer is above one hour dispout = ((MINUTES 10000) + (SECONDS 100) + MILLISECONDS); //This one if timer is below one hour
} `