Timing duration between two events - c++

I want to compute the time between when I transmit and when I receive. My timer will start counting once I start transmitting then the timer will stop once I receive a response. I'm using C++ on my arduino uno. Base on my code I'm just measuring the delay, Which is not good. what I'm trying to measure is the elapsed time between i transmit and received. I hope you can help me.
output image
My code
#include <VirtualWire.h>
const int transmit_pin = 12;
const int receive_pin = 11;
char *controller;
unsigned long start, finished, elapsed;
void setup() {
//receiver settings
Serial.begin(9600); // Debugging only
vw_set_rx_pin(11);
vw_rx_start();
//transmitter settings
pinMode(13, OUTPUT);
vw_set_ptt_inverted(true);
vw_set_tx_pin(12);
vw_setup(1000); // speed of data transfer Kbps
}
void displayResult()
{
float h,m,s,ms;
unsigned long over;
elapsed=finished-start;
h=int(elapsed/3600000);
over=elapsed%3600000;
m=int(over/60000);
over=over%60000;
s=int(over/1000);
ms=over%1000;
Serial.print("Raw elapsed time: ");
Serial.println(elapsed);
Serial.print("Elapsed time: ");
Serial.print(h,0);
Serial.print("h ");
Serial.print(m,0);
Serial.print("m ");
Serial.print(s,0);
Serial.print("s ");
Serial.print(ms,0);
Serial.println("ms");
Serial.println();
}
void loop() {
//Transmitter
digitalWrite(13, 1);
controller = "1";
vw_send((uint8_t *)controller, strlen(controller));
vw_wait_tx(); //Wait until the whole message is go
start=millis();
delay(1000); // for debounce
Serial.println("Started...");
//Receiver
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
if (vw_get_message(buf, &buflen)) { // Non-blocking
digitalWrite(13, 0); //Flash a light to show received good
for(int i = 0;i < buflen;i++) {
if (buf[i] == '2')
{
finished=millis();
delay(1000); // for debounce
displayResult();
elapsed=finished-start;
Serial.print(start);
Serial.println(" milliseconds start");
Serial.print(finished);
Serial.println(" milliseconds finished");
Serial.print(elapsed);
Serial.println(" milliseconds elapsed");
Serial.println();
}
}
}
}

You say "Base on my code I'm just measuring the delay, Which is not good."
Ok, well:
start=millis();
delay(1000); // for debounce
Well, if you don't want to include the delay in your elapsed time, then take the start time after the delay(), not before.
This seems to be too obvious, so I suspect that you're really asking about something else. You need to show the output you're getting, why you think it's wrong, and what output you expect to get, instead.

Every thing happens during your delay period (the 1000ms delay). The message is received and stored in the buffer waiting for you to read it while you're in the delay. You're now measuring the execution time of a couple of lines of code and that takes less than a millisecond that is why you are getting the 0ms time.

Related

Arduino loop does not stop - only with smaller counters. Arduino Nano Every

I cannot explain to myself why this code works properly in some cases and in some not. Here is the situation:
I am trying to switch a relay with the Arduino Nano. Therefore I took the "Blink" example as a guide. It should switch on for like 5 minutes and switch off for like 25 minutes. Here is the code:
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
pinMode(2, OUTPUT); // sets PIN 2 as switcher for the relay
}
// the loop function runs over and over again forever
void loop() {
int count = 0;
int run_pump = 300; // 5 Min run
int stop_pump = 1500; // 25 Min stop
digitalWrite(LED_BUILTIN, LOW); // turn the LED off (HIGH is the voltage level)
digitalWrite(2, HIGH); // turn the pump on
while(count < run_pump) {
count++;
delay(1000); // wait for a second
}
count = 0;
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on by making the voltage LOW
digitalWrite(2, LOW); // turn the pump off
while(count < stop_pump) {
count++;
delay(1000); // wait for a second
}
}
if I run this code on the Arduino it will just switch on the relay forever. BUT: If I set run_pump and stop_pump for like 10 sec. it will work properly! Is there an explanation why this does not work with the bigger counters? It's so confusing....
so this code here works absolutely fine, but why does the code above not?
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
pinMode(2, OUTPUT); // sets PIN 2 as switcher for the relay
}
// the loop function runs over and over again forever
void loop() {
int count = 0;
int run_pump = 5; // 5 sec run
int stop_pump = 10; // 10 sec stop
digitalWrite(LED_BUILTIN, LOW); // turn the LED off (HIGH is the voltage level)
digitalWrite(2, HIGH); // turn the pump on
while(count < run_pump) {
count++;
delay(1000); // wait for a second
}
count = 0;
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on by making the voltage LOW
digitalWrite(2, LOW); // turn the pump off
while(count < stop_pump) {
count++;
delay(1000); // wait for a second
}
}
Hope someone has a clue.... Thanks!
Tom
OK guys, I solved it. The problem was a cheap relay that was trying to communicate with the Arduino... Replacing it with a better one solved the whole problem. Thanks for the idea with the LED, this brought some stones to roll... :)

Setting delay for capacitive touch sensor to prevent "double press"

I am building a number numpad using 3 different capacitive touch sensor. So my function will be to label each the 3 touch sensors with a different number to create a password system.
However i realised that whenever i try to press the button to key in the number, for example the button tagged with number "3", multple values of 3 came out even though i only pressed once. Is there any function on arduino that i can use so that it only generate 1 results with 1 press instead of multiple results in a press.
Is there anyway to change my code such that i can create some sort of debounce for each button so that when i press the button once only 1 result will be shown.
Would appreciate an edit on my code, thanks!
#include <LiquidCrystal.h>
#include <CapacitiveSensor.h>
CapacitiveSensor cs_2_3= CapacitiveSensor(2,3);
CapacitiveSensor cs_2_4= CapacitiveSensor(2,4);
CapacitiveSensor cs_2_5= CapacitiveSensor(2,5);
int pos=0;
LiquidCrystal lcd(A0,A1,A2,A3,A4,A5);
char pass[]= "321";
int currentposition=0;
char code=0;
void setup() {
cs_2_3.set_CS_AutocaL_Millis(0xFFFFFFFF);
lcd.setCursor(0,0);
lcd.println("Enter Password: ");
Serial.begin(9600);
lcd.begin(16,2);
}
void loop() {
long total1= cs_2_3.capacitiveSensor(100);
long total2=cs_2_4.capacitiveSensor(100);
long total3= cs_2_5. capacitiveSensor(100);
if(total1>=1000)
{
code= '1';
}
if(total2>=1000)
{
code= '2';
}
if(total3>=1000)
{
code='3';
}
delay(100);
if(currentposition==0)
{
lcd.setCursor(0,0);
lcd.println("Enter Password: ");
}
int lu ;
if(code!=0)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("PASSWORD:");
lcd.setCursor(7,1);
lcd.print(" ");
lcd.setCursor(7,1);
for(lu=0;lu<=currentposition;++lu)
{
lcd.print(code);
delay(25);
}
if (code==pass[currentposition])
{
++currentposition;
if(currentposition==3)
{
delay(900);
lcd.setCursor(0,0);
lcd.println(" ");
lcd.setCursor(1,0);
lcd.print("Correct Password");
lcd.setCursor(4,1);
lcd.println("HELLO!!");
lcd.setCursor(15,1);
lcd.println(" ");
lcd.setCursor(16,1);
lcd.println(" ");
lcd.setCursor(14,1);
lcd.println(" ");
lcd.setCursor(13,1);
lcd.println(" ");
delay (5000);
lcd.clear();
lcd.setCursor(0,0);
lcd.println("Enter Password: ");
}
}
else
{
delay(500);
lcd.clear();
lcd.setCursor(1,0);
lcd.print("PASSWORD");
lcd.setCursor(6,0);
lcd.print("INCORRECT");
lcd.setCursor(15,1);
lcd.println(" ");
lcd.setCursor(4,1);
lcd.println("GET AWAY!!!");
code=0;
lcd.setCursor(13,1);
lcd.println(" ");
delay(3000);
currentposition=0;
lcd.clear();
lcd.setCursor(0,0);
lcd.println("Enter Password: ");
}
}
}
Just debounce it like any other button. Only accept signal changes longer then a certain time.
From https://www.arduino.cc/en/tutorial/debounce
/*
Debounce
Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
press), the output pin is toggled from LOW to HIGH or HIGH to LOW. There's a
minimum delay between toggles to debounce the circuit (i.e. to ignore noise).
The circuit:
- LED attached from pin 13 to ground
- pushbutton attached from pin 2 to +5V
- 10 kilohm resistor attached from pin 2 to ground
- Note: On most Arduino boards, there is already an LED on the board connected
to pin 13, so you don't need any extra components for this example.
created 21 Nov 2006
by David A. Mellis
modified 30 Aug 2011
by Limor Fried
modified 28 Dec 2012
by Mike Walters
modified 30 Aug 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Debounce
*/
// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin
// Variables will change:
int ledState = HIGH; // the current state of the output pin
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin
// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
void setup() {
pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
// set initial LED state
digitalWrite(ledPin, ledState);
}
void loop() {
// read the state of the switch into a local variable:
int reading = digitalRead(buttonPin);
// check to see if you just pressed the button
// (i.e. the input went from LOW to HIGH), and you've waited long enough
// since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;
// only toggle the LED if the new button state is HIGH
if (buttonState == HIGH) {
ledState = !ledState;
}
}
}
// set the LED:
digitalWrite(ledPin, ledState);
// save the reading. Next time through the loop, it'll be the lastButtonState:
lastButtonState = reading;
}
You could use INPUT_PULLUP like this:
void setup() {
pinMode(pin, INPUT_PULLUP)
}
But since your using i library this may be an issue.
You could simply use the delay() function, as stated here: https://www.brainy-bits.com/arduino-switch-debounce/
This might be the fastest and simplest way to do it.
Debouncing the button will help - Adafruit got something especially on this topic: https://learn.adafruit.com/make-it-switch/debouncing
But for a quick and dirty solution delay() will do.

WebClient and MotionDetector stops after a while

I've been digging this for around a week and doesn't have any way to solve this one. My Arduino code is working for a while (few times / few days) and then stops all of a sudden. I'm trying to implement a WebClient within the Arduino which sends HTTP GET requests to some other server every time (periodically - every 90 seconds) when a motion had been detected / when motion had stopped.
Below you can find the code. Can anyone assist?
#include <Ethernet2.h>
#include <SPI.h>
byte mac[] = { 0x90, 0xA2, 0xDA, 0x10, 0x73, 0x88 };
IPAddress ip(192,168,20,84);
IPAddress server(192,168,50,93); // Google
IPAddress myDns(8, 8, 8, 8);
EthernetClient client;
//getMovement - sends a GET request when motion is detected
void getMovement() {
client.stop();
if (client.connect(server, 8080)) {
client.println("GET /GetARoomMaven/motion?roomId=1&movement=1");
client.println();
Serial.println("Movement Request Sent");
} else {
Serial.println("connection failed");
}
}
//getNoMovement - sends a GET request when motion had stopped
void getNoMovement() {
client.stop();
if (client.connect(server, 8080)) {
client.println("GET /GetARoomMaven/motion?roomId=1&movement=0");
client.println();
Serial.println("Movement Request Sent");
} else {
Serial.println("connection failed");
}
}
//VARS
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 10;
//the time when the sensor outputs a low impulse
long unsigned int lowIn;
//the amount of milliseconds the sensor has to be low
//before we assume all motion has stopped
long unsigned int pause = 90000;
//
boolean lockLow = true;
boolean takeLowTime;
int pirPin = 2; //the digital pin connected to the PIR sensor's output
int ledPin = 13;
/////////////////////////////
//SETUP
void setup(){
Serial.begin(9600);
pinMode(pirPin, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(pirPin, LOW);
Ethernet.begin(mac);
//give the sensor some time to calibrate
Serial.print("calibrating sensor ");
for(int i = 0; i < calibrationTime; i++){
Serial.print(".");
delay(1000);
}
Serial.println(" done");
Serial.println("SENSOR ACTIVE");
delay(50);
loop();
}
////////////////////////////
//LOOP
void loop(){
if(digitalRead(pirPin) == HIGH){
digitalWrite(ledPin, HIGH); //the led visualizes the sensors output pin state
if(lockLow){
//makes sure we wait for a transition to LOW before any further output is made:
lockLow = false;
Serial.print("motion detected at ");
Serial.print(millis()/1000);
Serial.println(" sec");
getMovement();
}
takeLowTime = true;
}
if(digitalRead(pirPin) == LOW){
digitalWrite(ledPin, LOW); //the led visualizes the sensors output pin state
if(takeLowTime){
lowIn = millis(); //save the time of the transition from high to LOW
takeLowTime = false; //make sure this is only done at the start of a LOW phase
}
//if the sensor is low for more than the given pause,
//we assume that no more motion is going to happen
if(!lockLow && millis() - lowIn > pause){
//makes sure this block of code is only executed again after
//a new motion sequence has been detected
lockLow = true;
Serial.print("motion ended at "); //output
Serial.print((millis() - pause)/1000);
Serial.println(" sec");
getNoMovement();
}
}
}
It's hard to say without a better description of symptoms.
Are the LED still blinking ?
If yes, the socket code seems wrong to me:
void getMovement() {
client.stop();
You must remember that TCP requires connection tracking, so you can't immediately stop a socket, it has to linger a bit for acknowledging packets sent.
If you look at the implementation:
void EthernetClient::stop() {
if (_sock == MAX_SOCK_NUM)
return;
[...]
}
stop() will fail if you have more than MAX_SOCK_NUM (which is 4 on your platform) opened at a time. Can this happen?
In all case, you should avoid as much as possible dynamic allocations, you should have a single function sendMovement(bool detected) that's writing the detected value (getMovement and getNoMovement are the same function, so factorize them). You should re-use the client as much as possible (avoid closing the socket and re-opening it unless you get an error from any socket function). Finally, you might want to set up an interrupt on the digital input pin (with some software debouncing) to avoid polling on it, that would release CPU, and, depending on the configuration, might release more time to process SPI messages.
If the LED are not blinking, try to comment out the SPI related code (EthernetClient's code) and check if it works (in that case, I would check the HW for errors, some of the socket code is busy looping (socket::send does this) that would never finish and stop your loop function from progressing. In that case, if you use JTAG to pause the CPU, it'll be in the client.connect or client.println method.
If it still does not work (LED not blinking with no SPI code), then the issue is likely hardware, check voltage / temperature / JTAG connect to the board to interrupt the CPU to figure out where it's struck.
BTW, if you are doing HTTP, the request is wrong and should be:
GET url HTTP/1.1\r\n
Host: yourserverhost.com\r\n
Connection: Keep-Alive\r\n
\r\n
The part HTTP/1.x after the GET url is absolutely required even for HTTP/1.0. Unless you've written your own server (in that case, there's no need to mimick HTTP), it should not work at all, not even once.

C++ Void Call Timeout

I`ve got a problem with my C++ application on a Raspberry Pi. This script should print a distance in cm one time before terminatig. But it should also check if the ultrasonic sensor is connected and if not the script should break. How could I do that? Is there a way to set a timeout for the getCM() method or has anyone another idea to solve this?
This is the code:
...
void setup() {
wiringPiSetup();
pinMode(TRIG_R, OUTPUT);
pinMode(ECHO_R, INPUT);
digitalWrite(TRIG_F, LOW);
delay(30);
}
int getCM() {
digitalWrite(TRIG_R, HIGH);
delayMicroseconds(20);
digitalWrite(TRIG_R, LOW);
//Wait for echo start
while(digitalRead(ECHO_R) == LOW);
//Wait for echo end
long startTime = micros();
while(digitalRead(ECHO_R) == HIGH);
long travelTime = micros() - startTime;
int distance = travelTime / 58;
return distance;
}
int main(void) {
setup();
printf("Distance: %dcm\n", getCM());
return 0;
}
Thanks in advance!
Tim
Checking in advance for the ultrasonic sensor there's not much anyone can suggest without knowing more about the sensor. If the communication is purely bit-toggling you probably can't tell without more hardware.
For the second part, timing out getCM, add an extra condition to the digitalRead loops to force an exit. For example:
int timeout = <read timeout goes here>;
while((digitalRead(ECHO_R) == LOW)&&(--timeout));
if (!timeout)
{
return -1; // Should never be able to read less than blanking distance
// from an ultrasonic sensor. -1 is certainly out of range.
}
In main you can either print out the -1 or check for -1 and print out a better error message. For more clarity, the second loop could return -2; on failure so you know what failed.

Arduino Loop Error: Waits several seconds to respond to input change

I am trying to write a simple control program for an Arduino Uno for an experiment I'm running at work. Quite simply it just needs to read if an input pin is high, if it is wait 10 milliseconds to turn an output pin high, hold for 10 milliseconds then go low, else the output pin is low.
My problem is that when I run this it ignores the initial delay altogether, and the output pin stays high for several seconds before going low. (using delayMicroseconds)
void setup()
{
pinMode(8, INPUT);
pinMode(13, OUTPUT);
}
void loop()
{
if (digitalRead(8) == HIGH)
{
delayMicroseconds(10000); //wait 10 milliseconds
digitalWrite(13, HIGH); // Pump on
delayMicroseconds(10000); // holds for pulse width of 10 millisecond
digitalWrite(13, LOW); // Pump off
}
else
{
}
}
I've tried setting up something simpler for debugging using the delay function to wait for a second, then turn output pin high, wait for a seconds, then turn output pin low. I did this so I could visually debug using the arduino's built in LED. the result is that it actually continues to run the loop 3 times after the input pin goes low. (using delay)
void setup()
{
pinMode(8, INPUT);
pinMode(13, OUTPUT);
}
void loop()
{
if (digitalRead(8) == HIGH)
{
delay(1000); //wait 1 second
digitalWrite(13, HIGH); // Pump on
delay(1000); // hold for 1 second
digitalWrite(13, LOW); // Pump off
}
else
{
}
}
I can't seem to figure out why it's doing this. I've looked all over and can't seem to find information about why this would happen. I might be missing something really simple, I am not an experienced coder, I just write what I need to run experiments. I've tried reading and writing to the pin register directly using c code, and switching from an if statement to a while loop, none of them fixed the problem. Any insight is greatly appreciated.
You should look at the internal pull-up resistors on the Arduino. You can debounce the signal from your button entirely with software:
void setup() {
pinMode(2, INPUT_PULLUP);
}
void loop() {
if (digitalRead(2) == LOW) // NOTE THAT PULLUPS REVERSE YOUR LOGIC
{
delay(1000); //wait 1 second
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
}
}