Idle time function on an Arduino - arduino

I want to add a timer to this function so that every time a uid is read it restarts and I can set another function to do a serial.write once a certain time is reached. Let's call this an idle time function. I cannot tie this to the ID read as I have 28 IDs potentially being read. I want to reset my audio player with an ASCII command via serial.write if no iud has been read for say longer than 180 seconds... Suggestions?
if(uid[0] == 0x64 && uid[1] == 0xBF && uid[2] == 0xD8 && uid[3] == 0x51)
{
//pause at beginning
delay (500);
//Serial.write("for Bässgen MM3210")
Serial.write("listplay 1 1");
Serial.write(13);
//pause at end
delay (3000);
}

You could assign each uid a value from the millis() call.
It basically counts the milliseconds since the chip turns on. It is stored in a long so it will reset to zero every 80 days or so I think (I never left it that long)
I did this to time a random array that was writing faster or slower based on how many pieces of data were in it. Instead of using delay() and counted loops, using millis() allowed me to jump in at a certain time.

Related

Comparing datetimes in delphi

I am developing a quizing game in Delphi and I would like to have a timer so that players don´t have unlimited time to answer the questions. I am using the function "Time" to get the current time but I don´t know how to convert it to something like an integer so that when let´s say 10 seconds have passed the player loses it´s chance. It would look like something like this:
Var
CurrentTime,Aux:TDateTime;
Begin
CurrentTime:=Time; //Current Time is assigned to a global variable.
Aux:=CurrentTime;
While (Aux-10000<=CurrentTime) do
Begin
if (Answer:=True) then //If the answer is already given by the player we break the while loop
Break;
Aux:=Time; //We refresh the auxilary variable
if (Aux-10000>=CurrentTime) then //We check if 10 seconds have passed
Begin
showmessage('You have taken too much time, your turn is lost');
exit; //We leave the script
end;
end;
end;
The problem is I can´t do arithmetic operations in DateTimes, as far as I know, So I need a different method for comparing the 2 different time instances. Any help would be appreciated, thanks!
TDate, TTime, and TDateTime are implemented using floating-point numbers, so you can perform arithmetic operations on them.
But you really shouldn't, in this case. The DateUtils unit has many functions for working with date/time values, eg:
uses
..., DateUtils;
var
StartTime, Aux: TDateTime;
begin
StartTime := Time();
Aux := StartTime;
...
while (not Answer) and (MillisecondsBetween(Aux, StartTime) < 10000) do
begin
Sleep(0);
Aux := Time();
end;
if (not Answer) then
begin
ShowMessage('You have taken too much time, your turn is lost');
Exit; //We leave the script
end;
...
end;
Note that this is not really a good use for TDateTime. Your calculations are relying on the system clock in local time being accurate and unchanging, but it can be changed dynamically while your code is running (user updates, network updates, daylight saving time change, etc), throwing off the results.
Consider using TStopWatch instead. It is intended for exactly this kind of use-case (determining elapsed time between actions), eg:
uses
..., System.Diagnostics;
var
SW: TStopWatch;
begin
SW := TStopWatch.StartNew;
...
while (not Answer) and (SW.ElapsedMilliseconds < 10000) do
Sleep(0);
if (not Answer) then
begin
ShowMessage('You have taken too much time, your turn is lost');
Exit; //We leave the script
end;
...
end;
Or, you could use TEvent instead, and have the answer signal the event when ready, eg:
uses
..., SyncObjs;
var
AnsweredEvent: TEvent;
...
// when the answer is submitted:
AnsweredEvent.SetEvent;
...
begin
AnsweredEvent.ResetEvent;
...
if AnsweredEvent.WaitFor(10000) <> wrSignaled then
begin
ShowMessage('You have taken too much time, your turn is lost');
Exit; //We leave the script
end;
end;
initialization
AnsweredEvent := TEvent.Create;
finalization
AnsweredEvent.Free;
I have written a few applications like this, using a TTimer. The timer's interval is set to 1000, which is equivalent to 1 second (you can use a different value); every time the timer's OnTimer event executes, a global variable is incremented which is then checked against the time limit (10 seconds?); if the variable equals this limit then first the timer is stopped, then the code performs whatever is necessary to transfer to the next person, or next question.
There should be similar code that executes when the person enters an answer as this code too needs to first save the answer then transfers to the next person. This portion should also stop the timer.
The 'show next question' part should restart the timer and reset the global variable only after the next question has been displayed, as it might take some time for it to be fetched.

HC-SR04P reading errors

In my project I need to measure distances up to 3-4m, so I am using a HC-SR04P sensor hooked up to an ESP32 dev board.
The code is written without any third-party library (was inspired by a very simple HC-SR04 arduino library, though), in plain C, within a project created from the ESP32 eclipse IDF plugin; no extra libraries or arduino code; just the RTOS.
Everything works fine when the device boots and measurements are pretty accurate, but after a while (can't say exactly what triggers this), the sensor/devboard circuit (can't say which) starts behaving strangely : after the TRIG pulse, the ECHO pin does not go HIGH within a reasonable 1s timeout, and no measurement is performed.
Once this happens, no new measurement is performed again unless reboot/power on; it looks like something happens and somehow there is a faulty state either for the sensor or within the communication code.
A couple of observations :
sensor is the right version to be powered at 3.3V.
HC-SR04P uses GPIO2 and GPIO4 for TRIG and ECHO.
measurements are not required to be frequent, hence the 30s timer for the measurement task.
at power on, everything works fine.
after reset by dev board micro-switch, everything works correctly again.
when timeout occurs, re-init the sensor (settings up GPIOs, etc.), but nothing happens; still timeouts.
For reference, the timing function is below (the HCSR04_Info struct holds only pin and measurement data); it is called from a timed task every 30s.
uint32_t hcsr04_timing(HCSR04_Info* pDevice)
{
// TRIG pulse for 10ms
gpio_set_level(pDevice->trig, 1);
ets_delay_us(10);
gpio_set_level(pDevice->trig, 0);
pDevice->startMicros = esp_timer_get_time();
// wait for the echo pin HIGH or timeout
while ((!gpio_get_level(pDevice->echo)) && (esp_timer_get_time() - pDevice->startMicros) <= pDevice->timeout);
if (!gpio_get_level(pDevice->echo)) {
pDevice->status = STATUS_OFFLINE;
ESP_LOGE(TAG, "hcsr04_timing timeout (1)");
return 0;
}
pDevice->startMicros = esp_timer_get_time();
// wait for the echo pin LOW or timeout
while ((gpio_get_level(pDevice->echo)) && (esp_timer_get_time() - pDevice->startMicros) <= pDevice->timeout);
if (gpio_get_level(pDevice->echo)) {
pDevice->status = STATUS_OFFLINE;
ESP_LOGE(TAG, "hcsr04_timing timeout (2)");
return 0;
}
pDevice->status = STATUS_ONLINE;
pDevice->endMicros = esp_timer_get_time();
return pDevice->endMicros - pDevice->startMicros;
}
Any help is appreciated. Thank you.
This does not generate a pulse of 10 ms; it's 10 us. Probably takes your device into an undetermined state eventually.
// TRIG pulse for 10ms
gpio_set_level(pDevice->trig, 1);
ets_delay_us(10);
gpio_set_level(pDevice->trig, 0);
The comment in the header file where ets_delay_us() is defined says: In FreeRTOS task, please call FreeRTOS apis.
Anyway, use delay(10) if in Arduino-land; or vTaskDelay(pdMS_TO_TICKS(10)) if in FreeRTOS-land.
Following up on campescassiano suggestions on overflow, the solution finally presented itself. Not really an overflow in the exact sense of the problem, but closely related.
It's finally a stupid bug in the code, so please close or delete the question if appropriate.
The problem was that pDevice->startMicros was defined as an uint32_t (probably because of a copy/paste or bad habit error), while esp_timer_get_time() returns microseconds as an uint64_t.
So it 'overflows' at about 1h 11m 34s (which is about 232 microseconds) after boot, and timeout calculations become off since (esp_timer_get_time() - pDevice->startMicros) will obviously be an uint64_t.
Because of that (esp_timer_get_time() - pDevice->startMicros) <= pDevice->timeout will always be false after 1h 11m 34s, so the loop breaks before getting an ECHO input.

Sim800L lag/delay before incoming calls are visible to arduino

I use SIM800L GSM module to detect incoming calls and generally it works fine. The only problem is that sometimes it takes up to 8 RINGS before the GSM module tells arduino that someone is calling (before RING appears on the serial connection). It looks like a GSM Network congestion but I do not have such issues with normal calls (I mean calls between people). It happens to often - so it cannot be network/Provider overload. Does anybody else had such a problem?
ISP/Provider: Plus GSM in Poland
I don't put any code, because the problem is in different layer I think
sorry that I didn't answer earlier. I've tested it and it turned out that in bare minimum code it worked OK! I mean, I can see 'RING' on the serial monitor immediately after dialing the number. So it's not a hardware issue!
//bare minimum code:
void loop() {
if(serialSIM800.available()){
Serial.write(serialSIM800.read());
}
if(Serial.available()){
serialSIM800.write(Serial.read());
}
}
In my real code I need to compare calling number with the trusted list. To do that I saved all trusted numbers in the contact list on the sim card (with the common prefix name 'mytrusted'). So, in the main loop there's if statement:
while(mySerial.available()){
incomingByte = mySerial.read();
inputString += incomingByte;
}
if (inputString.indexOf("mytrusted") > 0){
isTrusted = 1;
Serial.println("A TRUSTED NUMBER IS CALLING");
}
After adding this "if condition" Arduino sometimes recognize trusted number after 1'st call, and sometimes after 4'th or 5'th. I'm not suspecting the if statement itself , but the preceding while loop, where incoming bytes are combined into one string.
Any ideas, what can be improved in this simply code?
It seems, I found workaround for my problem. I just send a simple 'AT' command every 20 seconds to SIM800L (it replies with 'OK' ). I use timer to count this 20 seconds interval (instead of simply delay function)
TimerObject *timer2 = new TimerObject(20000); //AT command interval
....
timer2->setOnTimer(&SendATCMD);
....
void SendATCMD () {
mySerial.println("AT");
timer2->Stop();
timer2->Start();
}
With this simple modification Arduino always sees incoming call immediately (after 1 ring)

Understanding UNIX termios VMIN and VTIME

I am currently working on a simple serial interface on a UNIX based device and cant find a definitive answer to the following:
I am currently trying to determine if a 'pure time read' (VMIN = 0, VTIME >0) will return half way through reading to n_bytes, as the timer is started when read is called, not when the first character is received.
For example, if I send a message to the device on the other end of the serial interface and I want a response I'd attempt the following (pseudo code):
m_tty.c_cc[VMIN] = 0;
m_tty.c_cc[VTIME] = 5; //i.e. > 0
write(myFileHandle, myData, sizeof(myData));
usleep(sizeof(myData) * 100); //assuming 100 us per char to Tx.
read(myFileHandle, myRxData, expectedMinNumBytes);
I am unclear as to whether read() would return if the first byte arrived just as the timer was about to expire, or if it would continue until 'expectedMinNumBytes' once the first is received?
Thanks for the help in advance!
This is a pure timed read. If there is available data, the read is immediately satisfied. If there is no data, the timer is started at the time read is called, and the read returns: either because the timer expires (returns 0) or a single byte is available.

Sending Array to a Single Process

I have an array with size nx*ny. The data in the array is in nrows*ncols processes. I want to send all the various parts of the array to a single array in a single process, say process 0.
I do it this way: I perform two do loops one the on nrows with variable x and another one inside that on the ncols with variable y. In each loop I find the process that has the row and coloumn same as x and y and use mpi_isend to send the data to process 0 and after that, again inside the same loop process 0 recevies the subarray by mpi_irecv.
I actually tried this and the problem is process 0 keeps receiving data that are not still sent! I even tried using mpi_barrier without success. Below is my code. Can anyone help me please? Thanks.
do x=0,grid%nrows
do y=0,grid%ncols
! Finding the relevant process and sending
if ((grid%row==x) .and. (grid%col==y)) then
call MPI_ISEND(tempp,ctot,MPI_DOUBLE_PRECISION,0, &
& grid%proc,MPI_COMM_WORLD,ierr)
end if
! Process 0 receives data
if (grid%proc==0) then
call MPI_IRECV(temp0(2*grid%xl:2*grid%xl+2*grid%mx-1, &
& :,1:size(v%a,4)), &
& ctot,MPI_DOUBLE_PRECISION, &
& x*grid%ncols+y,x*grid%ncols+y,MPI_COMM_WORLD,stat,ierr)
end if
end do
end do
mpi_Irecv and mpi_Isend are non-blocking functions. This means, that these function calls return before the transmission is completed. To solve your problem, you can either
use the blocking versions, mpi_Recv and mpi_Send or
add mpi_Wait calls to your solution to wait for the non-blocking calls to finish.

Resources