The title doesn’t help explain my problem so I’ll explain and give my code here.(This is my first project that I’m doing on my own)
I made a clock + Session timer by using an RTC module (DS3231) and I’ve done the basic time and session programs(and they work fine). Then I wanted to make it more “lively” by adding some simple animations. What I wanted was to put a little animation between time change ( Basically I just add two time modes where in one there’s seconds and without seconds (sometimes seeing seconds feel like a stress so ye)), and this animation runs across the whole screen whether the session is running or not(I’m not having any worries abt the way it’s going)
void animation() {
if (doAnimation == true) {
switch (Animation) {
case Animation::Start:
lcdClearAnimation();
if (currentMillis - animationStartMillis >= animationState[0]) {
Animation = Mid1;
}
break;
case Animation::Mid1:
lcd.setCursor(0, 1);
lcd.print("Mid1 Doing");
if (currentMillis - animationStartMillis >= animationState[1]) {
Animation = Mid2;
}
break;
case Animation::Mid2:
lcd.setCursor(0, 1);
lcd.print("Mid2 Doing");
if (currentMillis - animationStartMillis >= animationState[2]) {
Animation = End;
}
break;
case Animation::End:
lcd.setCursor(0, 1);
lcd.print("END. Doing");
if (currentMillis - animationStartMillis >= animationState[3]) {
doAnimation = false;
}
break;
}
}
}
So this is the one that handles the animation. This runs when I change the toggle switch. I’ve already done the “lcdAnimationClear();” one. Now I’ll explain what animation I want. What I have in mind is this,
In the “Mid1” part(I’ll probs remove Mid2 but let’s keep it here for now), The program picks an order from 1-16(I have a 16x2 lcd) and let’s say it picks the number each 50ms (For every time the animation runs the number order should be different), and when the first number is taken, it will go on a sequence of changing symbols on that picked column (kind of like a weird glitch and symbol changing transition but this continues until the time I want it to stop) and while that column is going through the different symbols, the program picks the next column and again puts that column in the symbol changing loop thing. Like this the program will pick all columns in both rows and filling (or doing the animation) .
@@ Then I want to end the columns that stays clear in the LCD in a blank(I think I’ll be able to manage this by getting which states I’m in(switch modes and session running or not)), and the columns that have displaying time and session(if on) will just go to that.
For now I want to ignore the part after “@@” bc I’m still stuck on the main animation thing (Mid1 part). I don’t want any code but I do need some suggestions on how to do this and or I can even get to this type of animation from arduino. I’m thinking like this bc I’ve always saw arduino as a way to tell something to do something like this and stop (not like -> start this, keep doing that and also start this after a few milliseconds, and keep doing all of that until the last part is done)
I also have a few things I’ve been avoiding. I’m not using blocking code in this program, I never used delay on this program(it’s kind of like a learning challenge) I saw from an AI about fisher yates algorithm which need a “for loop” (it kinda goes against my challenge so I’m thinking about looking into some libraries or something that somehow get my randomize problem(I saw on google(AI again) that there is some libraries there))
Thank you for reading all of this and hope someone can give me an idea
I think you are at a similar place where I got stuck before. One, do not hesitate to toss all of your code and redo it from scratch a few times. I do this in CAD naturally all the time, but struggle to do the same in code, and it leaves me with unfinished projects, many, very many, just like this one. So my advice is to first get a minimum functional version where you are at now, and archive it. At least you can finish the project that way.
Second, learn about schedulers. There are many types of schedulers, for example in the Linux kernel. The CPU scheduler is probably the best place to get started learning. This is a thing you need to have in mind from the very start of the project. You write the CPU scheduler to be your main loop. Then you use interrupts and processes with priorities. You may never need to halt one process/function to run another, like saving the registers states to RAM and loading some other process thread. This allows you to break stuff up into more manageable chunks so you might load some characters into the LCD’s custom character buffer, then service the RTC fetch routine, then display those characters in the next time slot.
The scheduler is a periodic interrupt loop that check what wants to run in the next time slot, picks the most important priority code, and runs it. If your code completes before the scheduler time slot ends, it may call the scheduler to run or you might keep it simple and and just wait until the next scheduler interrupt triggers the proceeding time slot. the scheduler has a high priority interrupt so that it preempts whatever code you may be running. The reset and external I/O still have higher level interrupts and short routines. With any external button interrupts, these would enable a high priority function/process that the scheduler then loads code to execute in the next cycle.
At first this seems inefficient or a waste, and it is overhead, but it is a structure that exists everywhere under the surface if you go looking for it. When exploring this, stick to retro microcomputer spaces for info and examples to start out. These ran systems very similar to a microcontroller where all of the code was scheduled and threaded on a single root layer. In more modern hardware, kernel space is separate from user space and the abstraction layers critical to scheduling with this separation will make it unnecessarily complicated to understand from a practical and useful perspective.
Ok, Then I’ll first complete my work like I was thinking about it before the current one(First fill all the columns and then do a simple animation which know how to do as it’s linear typa thing), then I can look into improving the animation. I just saw on the internet that you have something called a “scheduler” which I’ve never heard specially in the Arduino side. I’ll need to look into it too. Thanks for the reply! ☺️
There is a FreeRTOS option for Arduino which is pretty much the next step when you want to do multitasking.
Basically, you create tasks in your setup routine by pointing to various self contained functions - each function becomes a task - and your “loop” becomes the task that runs when everything else is idle.
Your functions have their own loops so they never exit, and then when you kick-start the tasks the task scheduler in FreeRTOS does all the heavy lifting of timeslicing the various functions so that they all appear to be running at once.
If you share resources, like an I2C bus, you can add locking around it so that tasks that need the resource wait until other tasks are finished with it so you don’t get tasks treading on each other’s toes.
FreeRTOS is in the Arduino libraries so you can just add it to a blank project and then have a play running two tasks at once.
I’ pretty sure I can get this to work like this(using RTOS) thanks
Arduino is based on the ‘giant loop’ model, where you initialize settings in the setup() function, then wait for events (inputs, timers, handlers, etc) in the loop() function.
Each time, the loop() function has to finish before it can be called again. So if there are timing related actions, there’s a chance they may fall out of sync or stutter. If you want to advance an animation frame, you’ll need to maintain all the state, and hope the loop gets called often enough so the frame can advance. If you want to sync up the animation to an RTC, then you’ll want to track whether the current loop syncs up with a time code before deciding whether to advance the animation (or not). Pretty soon your giant loop will likely get complicated and messy.
Another option is to look at something like SoftPWM for controlling LEDs and see how they set up animation timing. Or to use the millis() function instead of delay() to manage timing. Adafruit has a nice tutorial on that: https://learn.adafruit.com/multi-tasking-the-arduino-part-1/using-millis-for-timing
To get more asynchronous activity going, the next option is to move to a more task-based system like FreeRTOS. Here you set up ‘tasks’ which can yield to each other, so you can have more asynchronous events. But the mental model is very different than the Arduino loop. The toolchain is also completely different. Here’s a decent primer: https://controllerstech.com/freertos-on-arduino-tutorial-part-1/
If your target device is an ESP32, the underlying OS is actually FreeRTOS. Arduino is a compatibility layer on top. So you can use the Arduino IDE and toolchain to write FreeRTOS tasks. Many peripheral device drivers can also be shared between the two. However, the minute you switch to tasks, the Arduino loop doesn’t work any more. Examples here: https://randomnerdtutorials.com/esp32-freertos-arduino-tasks/
From your description, it sounds like you may want to switch to FreeRTOS tasks.
Thanks, I’ll look into FreeRTOS next.



