Timer in program is too slow - c

Hello i am creating a speedcube timer i just got the time centered but then i noticed that the time on it was too slow, I tried changing the usleep function from 1000 but it was either to fast or to slow, any ideas?
#include <ncurses.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int minutes = 0, milliseconds = 0, seconds = 0, x = 0, y = 0, text = 6, textminutes = 0, textseconds = 0, textmilliseconds = 0;
initscr();
while(1)
{
/*This block of code centers the text on the screen by incrementing each variable by one
for each number starting at ten, Then prints the time.*/
getmaxyx(stdscr,y,x);
if (seconds == 60 && minutes == 10){
textminutes += 1;
}
if (milliseconds == 1000 && seconds == 10){
textseconds += 0;
}
if (milliseconds == 10){
textmilliseconds += 1;
}
else if (milliseconds == 100)
{
textmilliseconds += 1;
}
else if(milliseconds == 1000)
{
textmilliseconds += 1;
}
int left_row = (x / 2) - (3 + textminutes + textseconds + textmilliseconds / 2);
mvprintw(y/2, left_row,"%d : %d : %d", minutes, seconds, milliseconds);
/*Sleep for 1 millisecond the increment the milliseconds
var i don't think that the timing is right though.
Then it refreshes and clears the screen to fetch the new contents.*/
usleep(1000);
milliseconds++;
if(milliseconds == 1000)
{
milliseconds = 0;
textmilliseconds -= 2;
seconds++;
if(seconds == 60)
{
seconds = 0;
textseconds -= 1;
minutes++;
}
}
refresh();
clear();
}
endwin();
return(0);
}

Your code seems to be written with the assumption that your process can run reliably once every millisecond, but you're probably running it on an operating system that has to perform other tasks, so you won't get to run every millisecond. Also, usleep might not be as accurate as you are hoping for it to be, and you're not accounting for the time it takes to do your calculations and output data to the terminal.
It's OK to use usleep to conserve CPU time. But when you want to figure out what time it is for displaying the time to the user, you should use a function that actually gets the time, like the C clock_gettime function perhaps.

You should never rely on an internal accumulator to accumulate elapsed wall time. Doing so not only captures the time consumed by usleep(), but also the execution time of formatting that string and any other calculations (the string format is likely to the big one).
Instead, get the system time at the start. Then, whenever you need to sample a new amount of time, get the system time again and subtract the start time from the now time. That'll give you the elapsed time and then you can adjust from there.

Related

Ardunio alarm clock without rtc projects error

i am currently working in a ardunio alarm clock project without and rtc for school. I have a problem with my hour variable not increasing and my conditionals that checks it.
This code mostly works i can set time in hr and minutes but when the timer reaches 59 minutes the hour doesnt increase by 1. The second code that has been posted is the bit where the problem lies. Any tips/help would be appreciated.
#include <Time.h>
#include <TimeLib.h>
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
#include <EEPROM.h>
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
const int numofMenus = 4;
int currentMenu = 0;
String menu[4][2] = {{"Set hour", "hr"}, {"Set minutes", "min"}, {"Set alarm", "o"}, {"Current Time", "ha"}};
int parameters[24];
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
lcd.noBlink();
}
void loop() {
inputAction();
if (currentMenu == 0)
{
printScreen();
}
if (currentMenu == 1)
{
printScreen();
}
if (currentMenu == 2)
{
printScreen();
}
if (currentMenu == 3)
{
int hr = parameters[0];
int mn = minute(parameters[1]);
int sec = second();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time: ");
if (parameters[1] >= 0 && parameters[1] <= 59 && sec < 59) {
parameters[0];
printtime(parameters[0]);
}
else if (parameters[1] == 59 && second() == 59) {
if (parameters[0]>=0 && parameters[0]<24){
parameters[0];
printtime(parameters[0]++);
//delay(1000);}
/*else if (parameters[0] == 24){
parameters[0]= 0;
printtime(parameters[0]);
}*/
}
}
lcd.print(":");
if (sec >= 0 && sec < 59) {
printtime(parameters[1]);
}
else if (sec == 59) {
parameters[1];
printtime(parameters[1]++);
delay(1000);
}
lcd.print(":");
printtime(sec);
/* if (sec == 60) {
mn+1;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time: ");
printtime(hr);
lcd.print(":");
printtime(mn);
lcd.print(":");
printtime(sec);
}
if (mn == 60) {
hr+1;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time: ");
printtime(hr);
lcd.print(":");
printtime(mn);
lcd.print(":");
printtime(sec);
}*/
delay (100);
}
}
void inputAction() {
uint8_t buttons = lcd.readButtons();
if (buttons & BUTTON_UP) {
if (currentMenu == 0) {
currentMenu = numofMenus - 1;
} else {
currentMenu--;
}
} else if (buttons & BUTTON_DOWN) {
if (currentMenu == numofMenus - 1) {
currentMenu = 0;
} else {
currentMenu++;
}
} else if (buttons & BUTTON_RIGHT) {
parameters[currentMenu]++;
} else if (buttons & BUTTON_LEFT) {
parameters[currentMenu]--;
}
}
void printScreen() {
lcd.clear();
lcd.print(menu[currentMenu][0]);
lcd.setCursor(0, 1);
lcd.print(parameters[currentMenu]);
lcd.print(" ");
lcd.print(menu[currentMenu][1]);
delay(100);
}
void printtime(int data) {
if (data >= 0 && data < 10) {
lcd.print('0');
}
lcd.print(data);
}
I don't think it is a good strategy to throw all those delays in the code. If you want to work with an RTC, you need to be mindful of those delays as they will affect the functionality of your program. If you don't account for delay properly, they will accumulate as errors. An error of 100 msecs will be seen as error in seconds easily within days.
I did not go through your code because it is hard to understand. I propose you have a look at this code which should be placed in your loop() function:
delay(100);
parameters = parameters + 100;
long rtcSeconds = parameters / 1000;
int seconds = (int) (rtcSeconds % 60); // Range 0 . 59 units: Secs
int minutes = (int)(((rtcSeconds - seconds) / 60) % 60); // Range 0 . 59 units: Mins
int hours = (int) (((rtcSeconds - minutes*60 - seconds) / (3600)) % 24); // Range 0 . 23 units: Hrs
I am using your parameters[0] field to keep track of the time in your syste, in milliseconds units. The field increases every 100 msecs as you see. You can recover the different time values using a combination of the modulus (%) and division operations. Now, I know you need to increase the time in your program. To do so, it is easy:
If you want to increase one second, do this: parameters[0] += 1000;
If you want to increase one minute, do this: parameters[0] += 1000 * 60;
If you want to increase one hour, do this: parameters[0] += 1000 * 3600;
Now, you might need to work with long variables as int have a limited range. You also need to watch for the time roll over when you change your time. If you are decreasing the time, you need to watch pramaters[0] doesn't become negative. In case it does, you need to add 3600 * 24 * 1000 msecs to force it jump one day ahead (3600 * 24 is one day in seconds). I hope you understand this is not a solution to your problem but an alternative approach using a little bit of a simpler code structure.

Condition for cycling between a value each X milliseconds within a full second

I am working with a micro-controller that has an interrupt that counts every 1ms since start.
I have a variable which can be between 0 and 999 and I want to toggle another value if the time elapsed is less than x milliseconds (in following example it is 500ms). So between time 0 and 500 I want shouldActivate to be TRUE, and between 500 and 1000 it should be false, then between 1000 and 1500 it should be true and so on.
int activeTime = 500; // 500ms active
int shouldActivate = 0;
int elapsed = 0; //how many ticks we had so far
// This function gets automatically called every 1ms
void tick() {
if(elapsed < activeTime) {
elapsed++;
shouldActivate = 1;
} else {
shouldActivate = 0;
elapsed--;
}
}
The above code works when I just start, while elapsed goes over 500, I get problems as it just does the decrement operation only once.
What conditions should I put into my function to achive the desired result?
You have two solutions, make new variable "direction" (for specify if you are decrementing or incrementing) but I think better is something like:
void tick() {
elapsed++;
if(elapsed < activeTime) {
shouldActivate = 1;
} else {
shouldActivate = 0;
}
if(elapsed>999)
elapsed = 0;
}
As per my understanding your application should active for 500 ms and sleep or inactive for 500ms. You can achieve that like below:-
int activeTime = 500; // 500ms active
int shouldActivate = 0;
int elapsed = 0; //how many ticks we had so far
// This function gets automatically called every 1ms
void tick() {
if(elapsed < activeTime) {
elapsed++;
shouldActivate = 1;
} else {
shouldActivate = 0;
elapsed++;//keep increasing elapsed for another 500ms
}
// after sleeping for 500ms assign elapsed to zero so that it should active again
if(elapsed >= (activeTime + 500))
elapsed = 0
//with the above condition you can switch off and on every after 500ms
}
How about:
const int activeTime = 500; // 500ms active
int shouldActivate = 0;
int elapsed = 0; //how many ticks we had so far
// This function gets automatically called every 1ms
void tick() {
elapsed = (elapsed + 1) % 1000;
shouldActivate = (elapsed < activeTime);
// And possibly:
// if (elapsed == activeTime) { /* State change to Inactivate */}
// if (elapsed == 0) { /* State change to activate */}
}
So your code only decrements elapsed once then the next time through, elapsed < active, so it increments again.
Most answers so far reset elapsed when it gets to 500 or 1,000. However, if it is called elapsed I think it should contain the elapsed time since the start. Here's a solution that allows elapsed to go on increasing forever, or at least for just over 2 billion milliseconds for a 32 bit int.
void tick()
{
shouldActivate = elapsed % (2 * activeTime) < activeTime;
elapsed++;
}
What you are basically describing is a cycle, in which elapsed ranges from 0 to 2*activeTime-1 and the next ms it is back to 0. So in order to check in which part of the range you are at every moment, you can simply do
elapsed = (elapsed+1) % (2*activeTime);
Which will make the final code look like this:
int activeTime = ...;
int shouldActivate = 0;
int elapsed = 0; //how many ticks we had so far
// This function gets automatically called every 1ms
void tick() {
elapsed = (elapsed+1) % (2*activeTime);
if(elapsed < activeTime) {
shouldActivate = 1;
} else {
shouldActivate = 0;
}
}
The reason for why your code isn't working is: If the elapsed == activeTime, and else branch triggers, your elapsed-- runs, and after which, the condition of elapsed < activeTime is, once again, true, hence why it keeps going back-and-forth between branches.
Simplest solution, in my opinion, is just resetting elapsed to 0, and inverting shouldActivate, once the value of elapsed reaches activeTime.
void tick() {
if(elapsed < activeTime) {
elapsed++;
} else {
elapsed = 0;
shouldActivate = !shouldActivate;
}
}

Calling a function every 40 second inside a while loop

This code invokes a function for every 40 seconds inside a loop. Since time_t is signed in my linux system, I am doubtful about this condition:
if ((time_left <= 0 || time_left > interval))
Is only checking (time_left <= 0) fine? I referred to some websites and they have also added a check for time_left > interval. Is this check required?
int print_timed_op()
{
time_t time_now;
time_t time_left;
time_t time_next_interval;
int interval = 40, hit_count =10; //40 second interval, 10 times
time_next_interval = time(0) + interval;
//tight loop
while (1) {
sleep(1);
time_now = time(0);
time_left = time_next_interval - time_now;
/* here time_left > interval check required ? */
if ((time_left <= 0 || time_left > interval)) {
call_my_fuc();
time_next_interval = time(0) + interval;
time_left = interval;
hit_count--;
}
if(hit_count <= 0)
break;
}
return 0;
}
Note: I don't want to use a Linux timer system call or any other method to invoke the function periodically.
The check for time_left > interval is to deal with clock changes or synchronization. If your interval is 40 seconds, and someone comes along and updates the system clock to shift it ahead by one hour, you will miss 90 updates if you don't have that check.
You can overcome this in a more precise way by using clock_gettime() with the CLOCK_MONOTONIC option. Then the time will never skip forward or backward, and your function calls will always be evenly spaced.

Simplifying Rounding code C

I'm new to coding and trying to figure out how to get code to round up to the next hour. The only method I've been able to think up (i.e. the only method I've been taught) is to just make else if statements for every hour. Clearly this isn't efficient at all and i know there's probably something much simpler. I was given a clue that there's a math equation involved?
Here's what i coded up so far:
#include <stdio.h>
int main()
{
//listens for value of "cost"
float cost;
printf("How much does this go-kart location charge per hour?\n");
scanf("%f", &cost);
//listens for value of "time"
float time;
printf("How many minutes can you spend there?\n");
scanf("%f", &time);
// i have to get it to round time to values of 60 (round up to next hour)
//really overcomplicated lack of knowledge workaround.txt
if (time < 60 && time > 0){
time = 1;
} else if(time > 61 && time < 70){
time = 2;
} else if(time > 71 && time < 80){
time = 3;
} else if(time > 81 && time < 90){
time = 4;
} else if(time > 91 && time < 100){
time = 5;
} else if(time > 101 && time < 160){
time = 6;
}
//etc etc
float total = cost * time;
printf("Your total will be $%f\n", total);
return 0;
}
For non regular intervals, one could do something like
int times[] = { 60; 70; 80; 90; 100; 160; INT_MAX }; // INT_MAX is to avoid segfault for bad input
int facts[] = { 1; 2; 3; 4; 5; 6; -1 }; // -1 is value for bad input
int it = 0;
while(times[it] < time) ++it;
int result = facts[it];
Note that you code doesnt have valid results for time = 60, 70, etc ... you should check the wanted behaviour
int hour = time/60;
if(60*hour < time)
++hour;
This is fairly basic math.
time / 60 would round down to to give you the hour.
Therefore (time / 60) + 1 rounds up.
If the maximum is 6 hours then simply check:
hour = time/60 + 1;
if (hour > 6) hour = 6;
Of course I'm assuming that time is an int. If it's a float then you can use floor or ceil to round up or down:
hour = floor(time/60 +1);
or
hour = ceil(time/60);
I think this is not bad
time = (time % 60) ? time / 60 + 1 : time / 60

Arduino Due C Timer Coding (Interrupt Counting)

I have an Arduino Due that I'm doing a lot of really neat stuff with in one section of code I'm handeling a flowsensor and getting readings from it. the flowsensor is hooked up to an interrupt as it is a hallsensor device. The problem I'm having is that my math is based off of a single seconds worth of collection data, when I turn on the interrupt and sleep for a second do the calculations for flowrate in gp/m it works great. For My purposes however I can't afford to pause and collect data, so instead I calculate a change in time of greater than a thousand milliseconds. then I take the amount of time passed since the last loop, devide it by 1000 milliseconds or 1 second then I have the percentage of 1 second stored in a variable, I multiply the count by the percentage and should arrive at the number of counts per second. This however results in an ever growing number regardless of the fact that I zero the numbers prior to the next loop. Below I've included the way I formatted the expressions and the loop code for the flowsensor, I'd post the whole code but I don't want to waste space on stackoverflow and I know that portion of code already works with the sleep method.
long currentMillis = 0;
long lastMillis = 0;
int checkMillis = 0;
volatile int NbTopsFan; //measuring the rising edges of the signal
int newNbTopsFan;
float realNbTopsFan;
float realMillis;
float Calc;
float Calcd;
int Calcf;
int hallsensor = 7;
void loop()
{
if (lastMillis = 0) {
lastMillis = millis();
}
currentMillis = millis();
checkMillis = (currentMillis - lastMillis);
if (checkMillis >= 1000) {
realMillis = (checkMillis / 1000);
realNbTopsFan = (NbTopsFan * realMillis);
newNbTopsFan = realNbTopsFan;
Calc = (newNbTopsFan * 60 / 7.5); //(Pulse frequency x 60) / 7.5Q, = flow rate
Calc = (Calc / 60);
Calc = (Calc / 3.78541);
Calc = (Calc * 1.47);
Calcd = (Calc * 100);
Calcf = Calcd;
NbTopsFan = 0;
lastMillis = 0;
checkMillis = 0;
realMillis = 0;
realNbTopsFan = 0;
newNbTopsFan = 0;
}
}
Your first line should read:
if ( lastMillis == 0 ) {
lastMillis = millis();
}
You need the double = to evaluate the variable

Resources