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.
main.cpp
/**************************************************
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);
}
Arduino file
//
// SuiteLock v.2.1a
// By: Chris Bero (bigbero#gmail.com)
// 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.
Related
I'm super new to programming so apologies if this is a badly phrased question or just confusing code! I have some Arduino code that automates things inside my campervan. The arduino reads data from temperature and battery sensors, and also controls the heating system. I had everything working, but the code was really inefficient and buggy, and I'd frequently get gibberish back when reading from the sensors. The internet suggested I use start and end markers to identify the useful information and discard the rest. Some copy and pasting and editing, I've ended up with the code below. However while the start and end markers are filtering out the information, I can't seem to make it call functions which actually do the controlling of things (e.g., move a servo, switch the heater on etc.).
// Van control system.
// Heater and sensor control code
// 20.03.2021
// This code controls the heater and reads from temp and power sensors.
#include <Servo.h> //Controls the heater air flow
#include <DHT.h> //temp sensor
#define DHT_SENSOR_TYPE DHT_TYPE_11
#include <Adafruit_INA260.h> //this breakout board monitors battery level and power consumption
Adafruit_INA260 ina260 = Adafruit_INA260();
Servo myservo; // servo to turn on heater
int pos = 90;// variable to store the servo position
#define DHTPIN 3 // temp sensor pin
#define DHTTYPE DHT11 // DHT 11
DHT dht(DHTPIN, DHTTYPE);
// Set up pins, the controller uses a common ground, so only one
// ground connection is needed. Pin A and B are used as pairs to
// generate a quadrature signal that mimics a rotary encoder (which controllers the heater)
int pinA = 9; //Pin A of encoder output
int pinB = 10; // Pin B of encoder output
int offPin = 11; // Acts as momentary on button
int onPin = 12; // Act as momentary off button
const byte numChars = 32; //serial input buffer
char receivedChars[numChars];
boolean newData = false;
void setup() {
Serial.begin(9600);
dht.begin(); //initalise temp sensor
myservo.attach(5); //attaches servo to pin.
pinMode(pinA, OUTPUT);
pinMode(pinB, OUTPUT);
pinMode(onPin, OUTPUT);
pinMode(offPin, OUTPUT);
digitalWrite(pinA, LOW);
digitalWrite(pinB, LOW);
digitalWrite(onPin, LOW);
digitalWrite(offPin, LOW);
ina260.begin(); //initalise power sensor
Serial.println("<ATMega is ready>"); //confirms that microcontroller is ready
}
//End of set up process.
void loop() {
recvWithStartEndMarkers(); //for maximum efficiency, loop should be as short as possible.
showNewData();
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; //terminate string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
void showNewData() {
if (newData == true) {
Serial.println(receivedChars); //this works and I get the character back in the serial monitor.
if (receivedChars == "H") {
upHeat(); //this doesn't work, if the character is H I want to call this function
}
else if (receivedChars == "C") {
downHeat();
}
else if (receivedChars == "O") {
heatOn();
}
else if (receivedChars == "F") {
heatOff();
}
else if (receivedChars == "a") {
servoPosOne();
}
else if (receivedChars == "s") {
servoPosTwo();
}
else if (receivedChars == "d") {
servoPosThree();
}
newData = false;
}
}
void upHeat() { //this generates a quadrature to simulate a rotary encoder.
digitalWrite(pinB, HIGH);
delay(200);
digitalWrite(pinA, HIGH);
delay(200);
digitalWrite(pinB, LOW);
delay(200);
digitalWrite(pinA, LOW);
delay(200);
digitalWrite(pinB, HIGH);
delay(200);
digitalWrite(pinA, HIGH);
delay(200);
digitalWrite(pinB, LOW);
delay(200);
digitalWrite(pinA, LOW);
}
//I haven't included the rest of the functions because, if one works, the rest will.
Any help would be amazing. I feel like it could be something really simple that I'm missing. Equally it could all be completely terrible!
Hello I wanted to change some voids to bools and I am a little lost. I understand if you write a void or a bool and want to add the values to the next void you just insert the code to add the previous function
I don't know how to explain it I am just gonna tell you what I want to do:
created a new bool getValues and added all the value getting code from the sensors then I wanted to send the data to void loop that will send the data through mqqt to raspberry.
I understand that bool is for true and false. but I don't really understand the etiquette of using it
so the problem I am getting 'temp' was not declared in this scope at the void loop function
I highlighted the function with // where I get the error it's almost at the bottom
#include "DHT.h"
#include <WiFi.h>
#define DHTPIN 25 // Digital pin connected to the DHT sensor
#define DHTTYPE DHT11 // DHT 11
//MQTT Setup Start
#include <PubSubClient.h>
#define mqtt_server "192.168.1.210"
WiFiClient espClient;
PubSubClient client(espClient);
#define mqttlightReadingpercent "greenHouse/light"
#define mqttsoilmoisturepercent "greenHouse/soil"
#define mqtttemp "greenHouse/temp"
#define mqtthum "greenHouse/hum"
//MQTT Setup End
const char* ssid = "Cgates_E031F1"; // ESP32 and ESP8266 uses 2.4GHZ wifi only
const char* password = "60E541C32F";
DHT dht(DHTPIN, DHTTYPE);
const byte lightPin = 33;
int lightReading;
int lightReadingpercent=0;
//const int RELAY_PIN = 15; // the Arduino pin, which connects to the IN pin of relay
// soil moisture
const int AirValue = 4095; //you need to replace this value with Value_1
const int WaterValue = 2200; //you need to replace this value with Value_2
const int SensorPin = 32;
int soilMoistureValue = 0;
int soilmoisturepercent=0;
const int Lightvalue = 0;
const int Darkvalue = 4095;
unsigned long millisNow = 0; //for delay purposes
unsigned int sendDelay = 20000; //delay before sending sensor info via MQTT
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println();
// begin Wifi connect
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(2000);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
//end Wifi connect
client.setServer(mqtt_server, 1883);
// pinMode(RELAY_PIN, OUTPUT);//relay
pinMode(lightPin, INPUT);
pinMode(SensorPin, INPUT);
Serial.println(F("DHTxx test!")); //dht
;
dht.begin();
}
void reconnect() {
// Loop until we're reconnected
int counter = 0;
while (!client.connected()) {
if (counter == 5) {
ESP.restart();
}
counter+=1;
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("greenHouseController")) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
bool getValues() {
lightReading = analogRead(lightPin); //0-4095 12bit -- esp8266 10bit 0-1023 -- arduino 8bit 0-254
Serial.print("Light reading = ");
lightReadingpercent = map(lightReading, Darkvalue, Lightvalue, 0, 100 );
Serial.print(lightReadingpercent);
Serial.println(" %");
Serial.println();
soilMoistureValue = analogRead(SensorPin); //put Sensor insert into soil
soilmoisturepercent = map(soilMoistureValue, AirValue, WaterValue, 0, 100);
if (soilmoisturepercent > 100) {
Serial.println("Soil moisture ");
Serial.println("100 %");
delay(500);
}
else if(soilmoisturepercent <0) {
Serial.println("Soil moisture ");
Serial.println("0 %");
delay(500);
}
else if (soilmoisturepercent >=0 && soilmoisturepercent <= 100) {
Serial.println("Soil moisture "); //go to next line
Serial.print(soilmoisturepercent);
Serial.println("%");
delay(500); // soil end
}
delay(500);
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float hum = dht.readHumidity();
// Read temperature as Celsius (the default)
float temp = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
float f = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(hum) || isnan(temp) || isnan(f)) {
Serial.println(F("Failed to read from DHT sensor!"));
return 1;
}
// Compute heat index in Fahrenheit (the default)
float hif = dht.computeHeatIndex(f, hum);
// Compute heat index in Celsius (isFahreheit = false)
float hic = dht.computeHeatIndex(temp, hum, false);
Serial.print(F(" Humidity: "));
Serial.print(hum);
Serial.print(F("% Temperature: "));
Serial.print(temp);
Serial.print(F("C "));
Serial.print(f);
Serial.print(F("F Heat index: "));
Serial.print(hic);
Serial.print(F("C "));
Serial.print(hif);
Serial.println(F("F"));
delay(500); //wait 0.5seconds
}
void loop() {
if (!client.connected()) {
reconnect();
}
if (millis() > millisNow + sendDelay) {
if (getValues()) {
client.publish(mqttlightReadingpercent, String(lightReadingpercent).c_str(),true);
client.publish(mqttsoilmoisturepercent, String(soilmoisturepercent).c_str(),true);
client.publish(mqtttemp, String(temp).c_str(),true); // the problem is here
client.publish(mqtthum, String(hum).c_str(),true);
millisNow = millis();
}
}
client.loop();
/*if (moisture_level < 10) {
digitalWrite(RELAY_PIN, HIGH); // turn on pump 5 seconds
delay(5000);
}
else {
digitalWrite(RELAY_PIN, LOW); // turn off pump 5 seconds
delay(5000);
}*/
}
By moving your code to getValues, you also changed the scope in which your temp variable exists in. Variables are not automatically globally available. If you declare a variable inside a function (which getValues is), it's only available in this function.
When you try to access the temp variable in your loop function, the compiler rightly tells you, that there is no such variable available.
You could solve the problem by declaring temp as a global variable, which you would do by adding float temp = 0 up on top where you also declare variables like soilMoistureValue. Make sure not to redeclare the variable in getValues then, so instead of declaring like so float temp = dht.readTemperature(); you just assign a new value like so temp = dht.readTemperature();
A quick note on your first paragraph: The voids and bools how you call it, define the return type of a function. If your function does not return anything, you define it as void. If it returns a boolean value (so true or false), you define so bool. In the case of your getValues function, since it does not return anything, it should be void getValues.
I'm writing an Arduino program to control a minigun for a friend's cosplay. I need to write a program that when the button is pressed the motor ramps up from 0 to a given value (for now lets say "analogWrite(output_pin,200);") then loop at that RPM until the button is released, at which point it needs to ramp down back to zero.
When I try to put ramping into a loop it doesn't finish the code. I
I need something like this in c++ code for the Arduino button. (I've tried similar things using the "delay" function to no avail)
motorspeed = 0
if buttonpress == True:
buttonheld = True
for i in range (0,10):
delay(1)
motorspeed =+ 20
if buttonpress == False:
motorspeed = 0
if buttonheld == True:
motorspeed = 200
if buttonpress == False:
for i in range(0,10):
delay(1)
motorspeed =- 20
else:
#shut off motor
#Play error sound
Here is the current code that only runs the motor at one speed when the button is held down.
const int button1 =4;
int BUTTONstate1 = 0;
void setup()
{
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(9, OUTPUT);
pinMode(button1, INPUT);
}
void loop()
{
//set button to read
BUTTONstate1 = digitalRead(button1);
//if button is pressed
if (BUTTONstate1 == HIGH)
{
//run current through motor
digitalWrite(2, LOW);
digitalWrite(3, HIGH);
//set speed
//Rampup
analogWrite(9,200);
}
else
{
digitalWrite(2, LOW);
digitalWrite(3, LOW);
}
}
Here is a virtual environment for the circuit
https://www.tinkercad.com/things/cLOBc9JJuTz-copy-of-dayloncircuitrefinecode/editel?sharecode=b6cqTLlNqUCCN09-mQ_zykp5sMnXx6KLt_KNqlXJmcs
I would recommend using interrupts, it's pretty well documented in Arduino reference:
Arduino reference - Interrupts
Most helpful is "Parameters" and "Example code" section. I think you should prepare two methods and attach interrupt to your input (button) pin on RISING and FALLING trigger.
Make sure that the button pin can be used for interrupt (on Arduino UNO / NANO only pin 2 and 3).
I think it should look similar to this (I haven't tested that):
#define buttonPin 2; // pin usable for interrupt
#define outputPin 9;
#define powerPinA 3;
#define powerPinB 4;
bool running = false;
int currentSpeed = 0;
void buttonUp()
{
digitalWrite(powerPinA, LOW);
digitalWrite(powerPinB, LOW);
running = false;
}
void buttonDown()
{
digitalWrite(powerPinA, LOW);
digitalWrite(powerPinB, HIGH);
running = true;
}
void setup()
{
pinMode(outputPin, OUTPUT);
pinMode(powerPinA, OUTPUT);
pinMode(powerPinB, OUTPUT);
pinMode(buttonPin, INPUT);
attachInterrupt(digitalPinToInterrupt(interruptPin), buttonUp, RAISING);
attachInterrupt(digitalPinToInterrupt(interruptPin), buttonDown, FALLING);
}
void loop()
{
delay(1);
if (running && currentSpeed < 200)
currentSpeed += 20;
else if (!running && currentSpeed > 0)
currentSpeed -= 20;
analogWrite(outputPin, currentSpeed);
}
Here's an example that doesn't rely on any interrupts. Just reading the button and remembering the state in a variable and remembering the time of the last step in a variable to check against millis() (Compiled but Untested)
int buttonPin = 5;
int lastButtonState = HIGH;
unsigned long lastRampStep;
unsigned int stepTime = 10; // 10ms steps. Set to whatever you want.
int analogPin = 3;
int analogLevel = 0;
int maxLevel = 200;
int analogStepSize = 10;
void setup() {
pinMode(buttonPin, INPUT_PULLUP); // will read LOW when pressed
}
void loop() {
int buttonState = digitalRead(buttonPin);
if (buttonState != lastButtonState) {
// The button just changed!
if (buttonState == LOW) {
// was just now pressed
analogLevel = 0; // start ramp up
lastRampStep = millis(); // note the time that we took this step
} else {
// Button just released.
// not sure what you want to happen here
}
}
else if (buttonState == LOW) {
// While button is held ramp until we reach the max level
if(analogLevel < maxLevel){
if(millis() - lastRampStep >= stepTime){
analogLevel += analogStepSize;
lastRampStep = millis();
}
}
} else {
// While button is released (HIGH) ramp back down:
if(analogLevel > 0){
if(millis() - lastRampStep >= stepTime){
analogLevel -= analogStepSize;
lastRampStep = millis();
}
}
}
analogWrite(analogPin, analogLevel);
lastButtonState = buttonState;
}
You could use interrupts to handle pressed/release, set a value, and handle the ramp up/down in the loop.
Keep in mind that you should also debounce the button.
Below is some pseudocode:
const byte maxLevel = 200; // some example values (max 255)
const int rampDelay = 5;
volatile byte targetLevel = 0;
byte currentLevel = 0;
// ...
ISR for Button { // Could be in one ore two ISR's
if pressed
targetLevel = maxLevel;
// possible other calls
if released
targetLevel = 0;
// possible other calls
}
void loop()
{
if (currentLevel < targetLevel) {
SetLevel(++currentLevel);
}
else if (currentLevel > targetLevel) {
SetLevel(--currentLevel);
}
// if currentLevel == targetLevel nothing changes
// if your device is battery powered you could even put the mcu
// to sleep when both levels are zero (and wake up from the ISR)
// no need for constantly polling the button when using ISR
delay(rampDelay);
}
This will also start ramping down immediately if the button is released before the motor is at full speed.
I'm working on a timer for the end of a game in Arduino. Basically, the program gets a command from serial, flips a pin, waits for 5 seconds, then triggers a reset command. It works, but it doesn't do it the very first time '43' comes through the serial. It will do it the second time and work fine after that. Why is that? What am I missing?
#include <elapsedMillis.h>
elapsedMillis timeElapsed;
int pin = 13;
unsigned int wait = 5000;
//// SERIAL //////////////////////////////////////////////
byte incomingByte; // from python
int command = 0; // command (1 = open, 2 = close)
int servoCom = 0; // the incoming command shit
void setup()
{
Serial.begin(9600);
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
Serial.println("setup done");
// wait 20 ms
delay(20);
}
void loop()
{
if (Serial.available() > 0)
{
incomingByte = Serial.read();
command = incomingByte;
servoCom = ServoGo(command);
}
if (servoCom == 43){
digitalWrite(pin, HIGH);
// run for 5 seconds
if (timeElapsed >= wait)
{
// trigger reset
servoCom = 70;
}
}
if(servoCom == 70){
// reset
digitalWrite(pin, LOW);
timeElapsed = 0;
}
}
int ServoGo(int com)
{
Serial.println("!inServoGo");
Serial.println(com);
return com;
}
timeElapsed is not initialized to zero at setup; it got reinitialized after the first command 70, then only command 23 works properly.
#include <SoftwareSerial.h>
SoftwareSerial SIM900(7, 8);
String outMessage1 = "Hello Arduino";
String outMessage2 = "Arduino2";
volatile int NbTopsFan; //measuring the rising edges of the signal
int Calc;
int hallsensor = 2; //The pin location of the sensor
int condition_1 = LOW;
int condition_2 = LOW;
int gsm_condition_1 = HIGH;
int gsm_condition_2 = HIGH;
String destinationNumber = "+6014681xxxx";
void rpm () //This is the function that the interupt calls
{
NbTopsFan++; //This function measures the rising and falling edge of the hall effect sensors signal
}
// The setup() method runs once, when the sketch starts
void setup() //
{
Serial.begin(9600); //This is the setup function where the serial port is initialised,
SIM900.begin(19200);
SIM900power();
delay(20000);
pinMode(hallsensor, INPUT); //initializes digital pin 2 as an input
pinMode(13, OUTPUT);
attachInterrupt(0, rpm, RISING); //and the interrupt is attached
}
// the loop() method runs over and over again,
// as long as the Arduino has power
void SIM900power()
{
digitalWrite(9,HIGH);
delay(1000);
digitalWrite(9,LOW);
delay(5000);
}
void sendSMS1()
{
gsm_condition_2 = HIGH;
SIM900.print("AT+CMGF=1\r"); //AT command to send SMS message
delay(100);
SIM900.println("AT + CMGS = \"" + destinationNumber +"\""); //recipient's mobile number, in international format
delay(100);
SIM900.println(outMessage1); //message to send
delay(100);
SIM900.println((char)26); //End AT command with a^Z, ASCII code 26 or ctrl+z
delay(100);
}
void sendSMS2()
{
gsm_condition_1 = HIGH;
SIM900.print("AT+CMGF=1\r"); //AT command to send SMS message
delay(100);
SIM900.println("AT + CMGS = \"" + destinationNumber +"\""); //recipient's mobile number, in international format
delay(100);
SIM900.println(outMessage2); //message to send
delay(100);
SIM900.println((char)26); //End AT command with a^Z, ASCII code 26 or ctrl+z
delay(100);
}
void gsm_check()
{
if (condition_1 == HIGH && gsm_condition_1 == HIGH) {
condition_1 = LOW;
gsm_condition_1 = LOW;
sendSMS1();
}
else if ( condition_2 == HIGH && gsm_condition_2 == HIGH) {
condition_2 = LOW;
gsm_condition_2 = LOW;
sendSMS2();
}
}
void water_rate()
{
NbTopsFan = 0; //Set NbTops to 0 ready for calculations
sei(); //Enables interrupts
delay (1000); //Wait 1 second
cli(); //Disable interrupts
Calc = (NbTopsFan * 60 / 7.5); //(Pulse frequency x 60) / 7.5Q, = flow rate in L/hour
Serial.print (Calc, DEC); //Prints the number calculated above
Serial.print (" L/hour\r\n"); //Prints "L/hour" and returns a new line
}
void loop ()
{
water_rate();
if ( Calc > 100 ) {
digitalWrite(13, HIGH);
condition_1 = HIGH;
}
else {
digitalWrite(13, LOW);
condition_2 = HIGH;
}
gsm_check();
}
I cannot use water flow rate sensor and GSM(SIM900) together. Once I use both then GSM will not work at all. I have tried a lot of methods to solve it but still not succeeded. Hope you guys can give me some help.
I was having the same problem. The solution is to stop the time 2 interrupt from running to send the message.
The edit of your code:
void sendSMS2()
{
cli();
gsm_condition_1 = HIGH;
SIM900.print("AT+CMGF=1\r"); //AT command to send SMS message
delay(100);
SIM900.println("AT + CMGS = \"" + destinationNumber +"\"");
delay(100);
SIM900.println(outMessage2); //message to send
delay(100);
SIM900.println((char)26); //End AT command with a^Z, ASCII code 26 or ctrl+z
delay(100);
sei();
}
The problem is that the sensor can only read using the interrupt, but your sim900 will not function when the interrupt is active. So you'll have to temporarily disable the interrupt and then carry on. Also, SIM900.print("AT+CMGF=1\r"); should be in void loop.
The last problem is that your sim 900 will not send integer. So you'll have to send it as a string. Please follow this example for that: http://microembarcado.blogspot.com.au/p/wr-bridge-send-sms-with-temperature.html
I sat for about 4 hours to figure it out.
Hope this makes things a little simplier for you.