Originally, I used AutoHotkey to communicate with the Arduino, but I found that after a few hours of not sending anything to the Arduino (the Arduino sent a 'heartbeat' every ten seconds), the connection would freeze or fail.
Now I'm trying to control an Arduino via its serial connection from a C++ program with the RS-232 library.
But I'm getting the same problem. The program pings the Arduino every twenty seconds, and the Arduino is then supposed to report with a small string of information. After a few hours, the connection dies, and my C++ program just sits there pinging with no response. The Arduino has a watchdog, and I can verify that it is still working when the connection isn't, so I believe that my problem lies in some sort of inherent timeout with serial... Except that the connection is actively being used..
I'd appreciate any help figuring out what I need to do in order to keep the serial connection alive, the computer has to be able to send data to the Arduino 24/7.
I'm compiling on Code::Blocks, and running the program on Windows 7.
I'm not very familiar with C++ or C, so if you find other stupid stuff I'm doing in the program, please let me know.
/**************************************************
File: main.cpp
Purpose: Simple demo that receives characters from
the serial port and print them on the
screen.
**************************************************/
#include <stdlib.h>
#include <iostream>
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif
#include "rs232.h"
using namespace std;
int main()
{
int debug = 0;
int i = 0, n,
cport_nr = 5, /* /dev/ttyS5 (COM6 on Windows) */
bdrate = 9600; /* 9600 baud */
unsigned char buf[4096];
if(OpenComport(cport_nr, bdrate))
{
cout << "Can not open comport\n";
return(0);
}
while(1)
{
if (debug)
{
printf("Entering While(1) loop. \n");
}
n = PollComport(cport_nr, buf, 4095);
if(n > 0)
{
buf[n] = 0; /* always put a "null" at the end of a string! */
/* for(i=0; i < n; i++)
{
if(buf[i] < 32) // replace unreadable control-codes by dots
{
buf[i] = '.';
}
} */
//printf("\n\n\nreceived %i bytes: %s\n\n", n, (char *)buf);
cout << endl << endl << endl << (char *)buf;
}
if (SendByte(cport_nr, 83))
{
printf("\n\nSending data didn't work. \n\n");
}
else
{
cout << "\nSent [S]\n";
}
i = 0;
#ifdef _WIN32
Sleep(10000); /* It's ugly to use a sleeptimer, in a real program, change
the while-loop into a (interrupt) timerroutine. */
#else
usleep(10000000); /* Sleep for 100 milliSeconds */
#endif
}
return(0);
}
//
// SuiteLock v.2.1a
// By: Chris Bero ([email protected])
// Last Updated: 11.4.2012
//
#include <Servo.h>
#include <avr/wdt.h>
// Pin Constants:
const int servoPin = 9;
const int doorbtn = 3;
// Not sure if I'm still going to use these...
const int ledGND = 4;
const int ledVCC = 5;
const int servDelay = 600; // The delay allowing for the servo to complete an action.
//Variables:
int doorState = 0; // The value returned by the door button (0 or 1).
int servState = 90; // The position of the servo in degrees (0 through 180).
unsigned long prevMillis = 0;
unsigned long progCycles = 0;
int serialByte = 0;
int lastSerial = 0;
int smallBlink = 0;
bool dostatus = false; // Determine whether to send sys status.
Servo serv;
// Set up the environment.
void setup()
{
wdt_enable(WDTO_4S);
pinMode(doorbtn, INPUT);
pinMode(ledGND, OUTPUT);
pinMode(ledVCC, OUTPUT);
pinMode(servoPin, OUTPUT);
digitalWrite(ledGND, LOW);
serv.attach(servoPin);
Serial.begin(9600);
prevMillis = millis();
}
////////////////////////////////////////////////
// Statuser - Sends system status to Serial
/////////////////////////////////////////////
int statuser ()
{
wdt_reset();
Serial.println("[Start]"); //Start Of Transmission
delay(15);
unsigned long currentMillis = millis();
refresh();
Serial.print("\tTime Alive: ");
int hr = ((currentMillis/1000)/3600);
int mn = (((currentMillis/1000)-(hr*3600))/60);
int sc = ((currentMillis/1000)-(hr*3600)-(mn*60));
Serial.print(hr);
Serial.print(":");
Serial.print(mn);
Serial.print(":");
Serial.println(sc);
Serial.print("\tNum of Program Cycles: ");
Serial.println(progCycles);
Serial.print("\tAvg Cycles per Second: ");
int cps = (progCycles/(currentMillis/1000));
Serial.println(cps);
Serial.print("\tDoorState: ");
Serial.println(doorState);
Serial.print("\tServo Position: ");
Serial.println(servState);
Serial.print("\tLast Serial Byte: ");
Serial.println(lastSerial);
delay(15);
Serial.println("[End]"); //End Of Transmission
return(0);
}
////////////////////////
// Lock the door.
/////////////////////
int locker()
{
wdt_reset();
// Check the button states.
refresh();
// Make sure the door is closed.
do
{
wdt_reset();
delay(500);
refresh();
} while(doorState == LOW);
// Turn on the locking LED during the servo movement.
digitalWrite(ledVCC, HIGH);
wdt_reset();
// Tell the servo to turn to 20 degrees.
serv.write(20);
// Give the servo time to complete the turn.
delay(servDelay);
wdt_reset();
// Turn the servo opp direction to reset.
serv.write(90);
// Wait for the servo to reach it's reset point.
delay(servDelay);
// Turn off the cool little LED.
digitalWrite(ledVCC, LOW);
// Call parents for 11pm checkup and tell them everything's A-OK.
return(0);
}
/////////////////////////
// Unlock the door.
//////////////////////
int unlocker ()
{
wdt_reset();
// Check the pin states.
refresh();
// Turn on the status LED.
digitalWrite(ledVCC, HIGH);
wdt_reset();
// Turn servo to 170 degrees to unlock the door.
serv.write(170);
// Wait for servo motion to complete.
delay(servDelay);
wdt_reset();
// Reset the servo to 90 degrees.
serv.write(90);
// Wait for reset motion to complete.
delay(servDelay);
// Turn off LED.
digitalWrite(ledVCC, LOW);
return(0);
}
///////////////////////////////
// Refresh button states.
/////////////////////////////
void refresh ()
{
wdt_reset();
doorState = digitalRead(doorbtn);
servState = serv.read();
}
///////////////////////
// Main function.
////////////////////
void loop()
{
wdt_reset();
// Blink the LED every so many turn overs of the function.
if (smallBlink == 5)
{
smallBlink = 0;
digitalWrite(ledVCC, HIGH);
delay(300);
digitalWrite(ledVCC, LOW);
}
// Status.
if(dostatus == true)
{
unsigned long currentMillis = millis();
if ((currentMillis - prevMillis) > 4000)
{
prevMillis = currentMillis;
statuser();
}
}
// Refresh button states.
refresh();
// Is the door closed and not locked? *Gasp*
if ((doorState == LOW))
{
// Fix it.
while (doorState == LOW)
{
wdt_reset();
delay(500);
refresh();
}
locker();
}
// Check for available communications.
if (Serial.available() > 0)
{
// Reset the serialByte, done for debugging.
serialByte = 0;
wdt_reset();
// Read the serialByte.
serialByte = Serial.read();
lastSerial = serialByte;
}
// Act on the byte data.
if (serialByte == 'U')
{
// Let someone in.
unlocker();
// Wait for the door to change states.
delay(1000);
}
if (serialByte == 'L')
{
locker();
delay(1000);
}
if (serialByte == 'S')
{
statuser();
delay(200);
}
// Clean serialByte for debugging.
serialByte = 0;
// Count through program cycles.
progCycles++;
smallBlink++;
}
I adjusted the C++ program to open the comport, send 'S', then close the comport and wait. Then I had it loop the procedure, so that it would keep opening and closing the port. My hope was that this would keep the connection from reaching the several hour mark and timing out or whatever. Instead, the program looped successfully for an hour, and then suddenly failed to open the COM port... This is totally blowing me away, and I have no idea what to do about it..
If CrazyCasta is right, and it's just my Arduino's connection to the laptop that's buggy, is there a way to reset the connection without having to restart the computer first?
As CrazyCasta said, it was a hardware problem. I was able to fix the issue by removing a 9 ft (2.7 m) USB extension cord between my Arduino and computer.
As of this morning the connection has been alive for ten hours, which is seven hours longer than previous tests. I hope it's safe to say this is fixed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With