Hello,
I am writing a simple timer program and for testing it should turn an led on when an alert occurs.
The code works without problem on my ESP32S2. (LED 5 sec on and then 5 sec off)
On the Attiny202 it does not work for some reason.
The initial test lighting did work (LED is for 2 sec on) on both controllers. Can there be an overflow or different sizes of variables? Or is the memory not enought?
I do not know what I could test next or try to fix.
This is the code:
Main.cpp
#include <Arduino.h>
#include "SimpleTimer.h"
// #define DEBUGGING
SimpleTimer timer;
// Pin to switch the device on and off
int8_t outputPin = 2;
int8_t currenState = LOW;
int8_t getNextState()
{
currenState = currenState == HIGH ? LOW : HIGH;
return currenState;
}
void testAddAlerts()
{
// timer.addAlert(timer.convertTimeToMilliSec(0, 0, 5), B01111111);
timer.addAlert(00, 00, 05, B01111111);
timer.setAllAlertsActive(true);
}
void setup()
{
#ifdef DEBUGGING
Serial.begin(115200);
#endif
pinMode(outputPin, OUTPUT);
testAddAlerts();
timer.setTimer(0, 0, 0);
digitalWrite(outputPin, getNextState());
unsigned long future = millis() + 2000;
while (future > millis())
{
delay(100);
}
digitalWrite(outputPin, getNextState());
}
void loop()
{
if (timer.update() == 1)
{
// Serial.println("Alert");
digitalWrite(outputPin, getNextState());
// Resets the timer so there is an output every alert
timer.setTimer(0,0,0);
timer.setAllAlertsActive(true);
}
}
SimpleTimer.h
#include <Arduino.h>
#pragma once
#define CHECKONLYEVERYSECOND
// #define DEBUGGING
struct Alert
{
Alert(uint32_t time, uint8_t executionDays)
{
executionTime = time;
setExecutionDays(executionDays);
activate(true);
}
/**
* @brief Set the execution time
*
* @param time
*/
void setExecutionTime(uint32_t time)
{
executionTime = time;
}
uint8_t getExecutionDays()
{
return data >= 128 ? data - 128 : data;
}
void setExecutionDays(uint8_t bitmask)
{
boolean active = isActive();
data = bitmask;
activate(active);
}
/**
* @brief Activates or deactivates the alert
*
* @param activate
*/
void activate(bool activate)
{
if (isActive())
{
if (!activate)
{
data -= 128;
}
}
else
{
if (activate)
{
data += 128;
}
}
}
/**
* @brief Returns if the alert is currently active or not
*
* @return true The alert is active
* @return false The alert is deactivated
*/
bool isActive()
{
if (data >= 128)
{
return true;
}
else
{
return false;
}
}
Alert *nextAlert = nullptr;
/**
* @brief data saves multiple differnt data in an 8 bit integer
* The first bit indcates if the alert is active
*
*
*/
uint8_t data;
uint32_t executionTime = 0;
};
/**
* @brief Keeps track of time and triggers when an alert occures
* (Use the update function for that)
*
*/
class SimpleTimer
{
public:
SimpleTimer();
~SimpleTimer();
/**
* @brief Updates the time with the elapsed time and checks if an alert is triggered. Also it resets the time and the alerts when "a day" is passed.
*
* @return returns 1 if an alert was triggered and 0 if noting happend
*/
int update();
/**
* @brief Converts the time given as normal time like 18:30:30 in milliseconds
*
* @param hours A value between 0-23
* @param minutes A value between 0-59
* @param seconds A value between 0-59
* @return The time in milliseconds
*/
uint32_t convertTimeToMilliSec( uint8_t hours, uint8_t minutes, uint8_t seconds);
/**
* @brief Adds an alert to the timer
*
* @param time The time when the alert should trigger
*/
void addAlert(uint32_t time, uint8_t weekdays);
/**
* @brief Adds an alert to the timer
*
* @param hours A value between 0-23
* @param minutes A value between 0-59
* @param seconds A value between 0-59
*/
void addAlert( uint8_t hours, uint8_t minutes, uint8_t seconds, uint8_t weekdays);
/**
* @brief Remove the alert on the given index
*
* @param index the position of the alert
* @return boolean which indicates if the removing was succesfull
*/
boolean removeAlert(int index);
/**
* @brief Remove the alert with the time
*
* @param time the time which should get removed
* @return boolean which indicates if the removing was succesfull
*/
boolean removeAlert(uint32_t time);
/**
* @brief Get the alert with the given index
*
* @param index An positive integer which is the desired index of the alert
* @return Returns an Alert if it exists. If there is no Alert on this index it returns nullptr.
*/
Alert *getAlert( uint8_t index);
/**
* @brief Sets all alerts inactive or active ´
*
* @param active Value which defines if all alerts should be active or inactive
*/
void setAllAlertsActive(bool active);
/**
* @brief Sets the current time
*
* @param hours A value between 0-23
* @param minutes A value between 0-59
* @param seconds A value between 0-59
*/
void setTimer( uint8_t hours, uint8_t minutes, uint8_t seconds);
// Used for debugging
void printTime(uint32_t time)
{
#ifdef DEBUGGING
// Uses too mutch resources so it will only used to debug
int hours = time / (1000 * 60 * 60);
time = time - hours * (1000 * 60 * 60);
int minutes = time / (1000 * 60);
time = time - minutes * (1000 * 60);
int seconds = time / 1000;
time = time - seconds * 1000;
Serial.print(hours);
Serial.print(":");
Serial.print(minutes);
Serial.print(":");
Serial.print(seconds);
Serial.print(":");
Serial.println(time);
#endif
}
protected:
uint32_t lastTimeUpdate = 0;
/**
* @brief Represents the current daytime in milliseconds if it synced before, else it is just a virtual day with 24h
*
*/
uint32_t time = 0;
/**
* @brief Saves all alerts
*
*/
Alert *rootAlert = nullptr;
// Saves the current time just here so the microncontroller does not need to reserve always new storage
uint32_t currentTime;
#ifdef CHECKONLYEVERYSECOND
/**
* @brief Stores the milliseconds elapesed since the last full second was reached
* Only use when CHECKONLYEVERYSECOND is defined
*
*/
int16_t lastSecUpdate;
#endif
};
SimpleTimer.cpp
#include "SimpleTimer.h"
SimpleTimer::SimpleTimer()
{
time = 0;
}
SimpleTimer::~SimpleTimer()
{
}
uint32_t SimpleTimer::convertTimeToMilliSec(uint8_t hours, uint8_t minutes, uint8_t seconds)
{
return ((((hours * 60) + minutes) * 60UL) + seconds) * 1000UL;
}
void SimpleTimer::setTimer(uint8_t hours, uint8_t minutes, uint8_t seconds)
{
// TODO check if params are valid not negativ or to high
// Calculates the time in milli seconds
time = convertTimeToMilliSec(hours, minutes, seconds);
}
void SimpleTimer::setAllAlertsActive(bool activ)
{
Alert *currentAlert = rootAlert;
while (currentAlert != nullptr)
{
currentAlert->activate(activ);
currentAlert = currentAlert->nextAlert;
}
}
void SimpleTimer::addAlert(uint8_t hours, uint8_t minutes, uint8_t seconds, uint8_t weekdays)
{
addAlert(convertTimeToMilliSec(hours, minutes, seconds), weekdays);
}
void SimpleTimer::addAlert(uint32_t time, uint8_t weekdays)
{
if (rootAlert != nullptr)
{
Alert *currentAlert = rootAlert;
while (currentAlert->nextAlert != nullptr)
{
currentAlert = currentAlert->nextAlert;
}
currentAlert->nextAlert = new Alert(time, weekdays);
currentAlert->nextAlert->activate(true);
}
else
{
rootAlert = new Alert(time, weekdays);
}
}
int SimpleTimer::update()
{
uint8_t returnValue = 0;
currentTime = millis();
time += currentTime - lastTimeUpdate;
#ifdef CHECKONLYEVERYSECOND
lastSecUpdate += currentTime - lastTimeUpdate;
if (lastSecUpdate >= 1000)
{
printTime(time);
lastSecUpdate = lastSecUpdate - 1000;
#endif
if (rootAlert != nullptr)
{
Alert *currentAlert = rootAlert;
while (currentAlert != nullptr)
{
if (currentAlert->isActive() && currentAlert->executionTime <= time)
{
currentAlert->activate(false);
returnValue = 1;
}
else
{
currentAlert = currentAlert->nextAlert;
}
}
}
// Test if "a day" has passed
if (time >= 86400000L)
{
time = time - 86400000L;
setAllAlertsActive(true);
}
#ifdef CHECKONLYEVERYSECOND
}
#endif
lastTimeUpdate = currentTime;
return returnValue;
}
Alert *SimpleTimer::getAlert(uint8_t index)
{
if (index < 0)
{
return nullptr;
}
Alert *askedAlert = rootAlert;
for (int8_t i = 0; i <= index; i++)
{
if (index == i)
{
return askedAlert;
}
if (askedAlert->nextAlert != nullptr)
{
askedAlert = askedAlert->nextAlert;
}
else
{
return nullptr;
}
}
return askedAlert;
}