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.
Related
I created a simple game in C in Xcode, but time does not elapse. Does anyone know how to solve this problem?
int main(void)
{
long startTime = 0;
long totalTime = 0;
long prevtime = 0;
int num;
init();
cursor = arrayFish;
startTime = clock();
while (1)
{
printFishes();
printf("\n Which fishing port would you like to water? ");
scanf("%d", &num);
printf("\n");
if (num > 6 || num < 1)
{
printf("Please re-enter.\n");
continue;
}
}
totalTime = (clock() - startTime) / CLOCKS_PER_SEC;
printf("Total Elapsed Time: %ld\n", totalTime);
}
It works except for the time mark. So I just wrote the code needed. Thank you.
You need to know Time Stamp Counter register your clock function is reading. If it is a 32 bit register it will reset very frequently.
For example if your CPU has 2GHz clock then 1 sec = 2 * 1e9 cycles and 32 bit unsigned register can count from 0 to 2^32 - 1 cycles. Which is equal to (2^32)/(2*1e9) = 2.14748365 seconds.
In this case your output will always be limited to 2.14 seconds
everyone, I am using, P10 Dot Matrix Display with Arduino Uno. I am using P10 Library from this link. P10_LED and I need to display the one-hour countdown on the display module. The given library uses TimerOne library. So for countdown i am using MsTimer2 library which usese timer2 of arduino.
When I individually run both of the libraries, my scrolling on the display is perfect and my timer library also generates a pure 1sec interrupt. Now what I did is the added both the library in my project and I am doing the countdown. But now suddenly my MsTimer2 doesn't generate pure 1sec.
Here is the code.
#include <MsTimer2.h>
#include <TimerOne.h>
#include"SPI.h"
#include <ledP10.h>
LedP10 myled;
uint8_t minute = 0, second = 0, hour = 1;
volatile bool xIsCountDone = false;
volatile bool xIsInterruptOcuured = false;
char time_buff[100];
void setup()
{
Serial.begin(9600);
myled.init(3,4,8,9 ,3);
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
Serial.println((char*)time_buff);
myled.showmsg_single_static((char*)time_buff, 0);
xIsInterruptOcuured = false;
//myled.showmsg_single_scroll("this is single led test",2,8,0);
MsTimer2::set(1000, count);
MsTimer2::start();
}
void loop() {
if (xIsInterruptOcuured == true)
{
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
Serial.println((char*)time_buff);
myled.showmsg_single_static((char*)time_buff, 0);
xIsInterruptOcuured = false;
}
}
void count(){
second--;
if (second <= 0 || second > 59)
{
second = 59;
minute--;
if (minute <= 0 || minute > 59)
{
minute = 59;
hour--;
if (hour <= 0 || hour > 12)
{
xIsCountDone =true;
}
}
}
Serial.println(millis());
xIsInterruptOcuured = true;
}
In the interrupt routine, I am printing millis() to see at after how many ms the interrupt occurs. The results are something like this.
15:33:02.684 -> 1199
15:33:04.371 -> 2396
15:33:06.059 -> 3592
15:33:07.746 -> 4783
15:33:09.434 -> 5986
15:33:11.121 -> 7181
15:33:12.855 -> 8379
15:33:14.543 -> 9578
15:33:16.230 -> 10768
15:33:17.918 -> 11974
15:33:19.605 -> 13168
15:33:21.292 -> 14365
15:33:22.980 -> 15562
15:33:24.667 -> 16751
15:33:26.402 -> 17955
When I use only MsTimer2 library the results are something like this.
15:37:21.241 -> 998
15:37:22.226 -> 1998
15:37:23.257 -> 2998
15:37:24.241 -> 3998
15:37:25.226 -> 4998
15:37:26.257 -> 5998
15:37:27.241 -> 6998
15:37:28.225 -> 7998
15:37:29.257 -> 8998
15:37:30.241 -> 9998
15:37:31.225 -> 10998
15:37:32.256 -> 11998
15:37:33.241 -> 12998
15:37:34.225 -> 13998
15:37:35.256 -> 14998
My guess, it's happening because of the TimerOne library but I couldn't find the solution. In ledP10.cpp there is a callback method for timer1 and it contains loops and may line of code. But is timer1 interrupts priority is higher than timer2? But according to the ATmega328p datasheet, the vector no. for Timer2 is less than Timer1. Doesn't that mean Timer2 has a higher priority? My ultimate goal is to do the one-hour countdown. Any help with this problem or any additional information i am missing which will be useful or any other solution other than using timer2 interrupt will be appreciated.
Regards.
EDIT
Here is the code I used with millis() and gave me around 12min difference.
uint8_t new_buff[100];
unsigned long startMillis; //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000; //the value is a number of milliseconds
uint8_t minute = 0, second = 0, hour = 1;
char time_buff[100];
void setup()
{
myled.init(3,4,8,9,3);
Serial.begin(9600);
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
//Serial.println((char*)time_buff);
myled.showmsg_single_static((char*)time_buff, 0);
startMillis = millis();
}
void loop() {
currentMillis = millis(); //get the current "time" (actually the number of milliseconds since the program started)
if (currentMillis - startMillis >= period) //test whether the period has elapsed
{
Serial.println(millis());
second--;
startMillis = currentMillis; //IMPORTANT to save the start time of the current LED state.
if (second <=0 || second > 59) {
second = 59;
minute--;
if (minute <=0 || minute > 59) {
minute = 59;
hour--;
if (hour <= 0 || hour > 12) {
hour = 0;
}
}
}
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
myled.showmsg_single_static((char*)time_buff, 0);
startMillis = currentMillis;
}
}
This answer targets your example using millis(). You can avoid accumulating errors over time, by not setting the next update relative to the current time. Rather just increment it by one second each time. This way, it does not matter if your main loop gets blocked by an interrupt for some milliseconds.
Also note that you don't have to save hours, minutes and seconds separately, you can just calculate them:
unsigned long nextMillis = 1000;
unsigned long targetTime = 1 * 60 * 60 * 1000; // 1 hour in milliseconds
void setup(){
myled.init(3,4,8,9,3);
Serial.begin(9600);
updateMyLed(0);
}
void updateMyLed( unsigned long elapsedTime ){
char buffer[100];
unsigned long timeLeftInSeconds = (targetTime - elapsedTime) / 1000;
uint8_t hour = timeLeftInSeconds / 3600;
timeLeftInSeconds -= hour * 3600;
uint8_t minute = timeLeftInSeconds / 60;
uint8_t second = timeLeftInSeconds - (minute * 60);
sprintf((char*)buffer, " %d%d:%d%d:%d%d", (hour/10), (hour%10), (minute/10), (minute%10), (second/10), (second%10));
myled.showmsg_single_static((char*)buffer, 0);
}
void loop() {
if( millis() >= nextMillis ){
updateMyLed(nextMillis);
nextMillis += 1000;
}
}
In the Arduino world, some libraries are disabling the interrupts.
This happens with all WS2812 LEDS and also yours. Without disabling interrupts, there would be a timing problem with the external devices.
So, you should never use interrupts or library with interrupts, if you use another one who will disable the interrupts.
Do you want use the P10 library? You can, but do not use interrupts in your code. Do not add other libraries like IR_remote, since it will not work correctly.
Back to your problem, just update your timer in the loop. And do not wait until the a second is over to update your time by 1 second! This will always be more than 1second.
You can for example convert the millis to seconds seconds = millis() / 1000;.
Your loop could be so:
void loop() {
currentSeconds = millis() / 1000; //get the current "time" (actually the number of milliseconds since the program started)
if (currentSeconds != savedSeconds) //test whether the period has elapsed
{
savedSeconds = currentSeconds;
Serial.println(millis());
second--;
if (second <=0 || second > 59) {
second = 59;
minute--;
if (minute <=0 || minute > 59) {
minute = 59;
hour--;
if (hour <= 0 || hour > 12) {
hour = 0;
}
}
}
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
myled.showmsg_single_static((char*)time_buff, 0);
}
}
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;
}
}
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.
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