I am having an issue with my code.
I am trying to control the speed that a timer is displayed.
Individually the time is working as expected.
Faster time is 2x as fast
Normal is 1x
Slower is half of normal.
It looks like my issue is when I transition from one speed to the next.
The following code will show what I mean.
Any help would be appreciated.
#define secondsElapsed (currentMillis / 1000)
#define minutesRemaining (minutes - (currentMillis / 60000))
#define secondsLeftInMinute (59-(secondsElapsed %60))
#include "LiquidCrystal.h"
// This defines the LCD wiring to the DIGITALpins
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
//TIME INITS
byte time[4];
unsigned long startMillis;
unsigned long timeCalcVar;
uint8_t tempTime;
float timeMultiplier = 1;
float speedupTimer = 2;
float slowdownTimer = 0.5;
uint8_t GAMEMINUTES = 3;
uint8_t ACTIVATESECONDS = 15;
uint8_t refresh = 0;
int longTone = 50;
uint8_t minutes;
unsigned long currentMillis;
unsigned long ledInterval;
unsigned long previousLedMillis;
unsigned long buzzerInterval;
unsigned long previousBuzzerMillis;
void setup() {
Serial.begin(9600);
lcd.begin(16,2);
pinMode(6, OUTPUT);
pinMode(9, OUTPUT);
}
void loop() {
destroy();
}
void destroy() {
minutes = GAMEMINUTES - 1;
startMillis = millis();
int longTone = 50;
previousLedMillis = 0;
previousBuzzerMillis = 0;
ledInterval = 500;
buzzerInterval = 500;
int ledState = LOW; // ledState used to set the LED
int timeState = LOW;
lcd.clear();
while (1) {
currentMillis = ((millis() - startMillis) * timeMultiplier );
//LEDs blinking
if(currentMillis - previousLedMillis >= ledInterval) {
previousLedMillis = currentMillis;
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
digitalWrite(6, ledState);
}
if ((currentMillis - previousBuzzerMillis) > buzzerInterval) {
if (minutesRemaining >= 2) {
buzzerInterval = 10000;
tone(9, 3951, longTone);
timeMultiplier = 1;
}
else {
if (minutesRemaining >= 1) {
buzzerInterval = 5000;
tone(9, 3951, longTone);
timeMultiplier = slowdownTimer;
}
else {
if ((minutesRemaining < 1) && (secondsLeftInMinute > ACTIVATESECONDS)) {
buzzerInterval = 2000;
longTone = 300;
tone(9, 3951, longTone);
timeMultiplier = 1;
}
else {
if (secondsLeftInMinute <= ACTIVATESECONDS) {
buzzerInterval = 500;
longTone = 200;
tone(9, 3951, longTone);
}
}
}
}
}
//Sound End
lcd.setCursor(0, 0);
//print time
printTime(minutes, currentMillis); //CUTWIRE TIME MODIFIER
}
}
void printTime(unsigned long minutes, unsigned long atTime) {
timeCalcVar = (minutes - (atTime / 60000));
//Hours
if (timeCalcVar / 60 < 1 && refresh == 0) {
lcd.clear();
refresh = 1;
delay(100);
}
if (timeCalcVar / 60 >= 1) {
if (timeCalcVar / 60 < 10) {
lcd.print(F("0"));
lcd.print(timeCalcVar / 60);
}
else {
lcd.print(timeCalcVar / 60);
}
lcd.print(F(":"));
}
//minutes
if ((timeCalcVar %60) < 10) {
lcd.print(F("0"));
lcd.print(timeCalcVar %60);
}
else {
lcd.print(timeCalcVar %60);
}
lcd.print(F(":"));
//seconds
timeCalcVar = (atTime / 1000);
if ((59 - (timeCalcVar %60)) < 10) {
lcd.print(F("0"));
lcd.print(59 - (timeCalcVar %60));
}
else {
lcd.print(59 - (timeCalcVar %60));
}
lcd.print(F(":"));
//this does not match with real time and is meant for effect,
//it says 999 otherwise millis%1000 could display 0
lcd.print(999 - (millis() %1000));
}
Hi here is something I had written a while back that could give you a sense how to call a function (performTick()) on a user specific clock. Default clock speed is 1 tick per second, but you can just select the pace by sending a code through the serial monitor (set at 115200 bauds)
// Author: J-M-L for Arduino Forum (https://forum.arduino.cc/index.php?action=profile;u=438300)
// originally posted at https://forum.arduino.cc/index.php?topic=649133.msg4377744#msg4377744
// Software License Agreement = standard BSD License
unsigned long tickPeriod = 1000; // 1s
unsigned long chrono;
void printUsage()
{
Serial.print(F("------- P:"));
Serial.print(tickPeriod);
Serial.println(F(" ------"));
Serial.println(F("Enter Tick options"));
Serial.println(F("0\t1/4x speed"));
Serial.println(F("1\t1/2x speed"));
Serial.println(F("2\t1x speed"));
Serial.println(F("3\t2x speed"));
Serial.println(F("4\t4x speed"));
Serial.println(F("------------------"));
}
void performTick()
{
Serial.print(F("Tick "));
Serial.println(chrono / 100); // integral division
}
void checkUserInput()
{
int b = Serial.read(); // returns -1 if nothing to read. don't bother with available() which is slower since commands are only 1 character long
switch (b) {
case '0': {
tickPeriod = 4000;
printUsage();
break;
}
case '1': {
tickPeriod = 2000;
printUsage();
break;
}
case '2': {
tickPeriod = 1000;
printUsage();
break;
}
case '3': {
tickPeriod = 500;
printUsage();
break;
}
case '4': {
tickPeriod = 250;
printUsage();
break;
}
}
}
void checkTick()
{
if (millis() - chrono >= tickPeriod) {
performTick();
chrono += tickPeriod;
}
}
void setup()
{
Serial.begin(115200);
printUsage();
chrono = millis();
}
void loop()
{
checkUserInput();
checkTick();
// you can do other stuff here if it's not too long
}
The picture you have from Tinkercad shows the circuit perfectly? No?
I am using a standard 16X2 LCD
// This defines the LCD wiring to the DIGITALpins
const int rs = 12,
en = 11,
d4 = 5,
d5 = 4,
d6 = 3,
d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
and I am using standard 5mm LED with 220 Ohm resistor tied to pin 6 of the UNO,
and the buzzer is one that you would find in an old PC (I am not using a resistor though I should probably be using a 1K Ohm resistor) is pied to pin 9 of the UNO.
Essentially the circuit is irrelevant to the problem as I am just working with timings.
References to lcd.print() could simply be replaced by Serial.print() with the same effect.
The link to Tinkercad was made to make simulating the problem easier,
as you can run the program online through the emulator without having to built the circuit yourself.
Alain74Martel:
The picture you have from Tinkercad shows the circuit perfectly? No?
No?
These pictures do not help with any trouble shooting.
Have you built this project in the real world?
If not, then get your hands dirty and BUILD IT.
Run it in the real world, and see if the timing problem REALLY exists.
Simulators are not perfect, especially free ones.
Tom....
Yes Tom,
I have built the circuit in the real world and tested the system.
I was able to reproduce the exact issue by dumbing down both the code and the circuit.
Once again, this is a software issue and not a hardware problem.
I will not be providing any pictures, as I said before the issue is in the code not the circuit.
It can't get any simpler than connecting an LCD directly to the Arduino.
The link to Tinkercad was made to make simulating the problem easier,
as you can run the program online through the emulator without having to built the circuit yourself.
No problem, but at this stage we were lead to believe you had only run it on simulator.
Hi,
Running your simulation without any info about when it is supposed to change speed and what it does when the fault occurs, leave us needing more information.
When is the alarm supposed to sound.
What speed are we seeing when the simulation starts?