I'm trying to take an input from the Arduino serial connection and write that to a file on the IoT2020. The code I'm using testing with is bellow.
The issue I'm having is that the code does not appear to recognize that there is an input and nothing imputed from the serial appears in the file. I even added an LED "notification" to turn on when a new line is detected in the interrupt but it never turns on. This would mean there is something intrinsically flawed in my code. Any help would be great.
//File handle creation
FILE *testFile;
String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
char buff[400];
void setup()
{
// sleep(3);
Serial.begin(115200);
pinMode(6, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
// reserve 200 bytes for the inputString:
inputString.reserve(400);
// Create files
system("touch /media/test.txt");
}
void loop()
{
digitalWrite(6, LOW);
delay(1000);
testFile = fopen("/media/test.txt", "a+");
fprintf(testFile,"This is a great test that has just started \n\r");
fclose(testFile);
while(1)
{
digitalWrite(6, HIGH);
// digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(6, LOW);
// digitalWrite(LED_BUILTIN, LOW);
delay(5000);
if (stringComplete) {
// clear the string:
inputString = "";
stringComplete = false;
testFile = fopen("/media/test.txt", "a+");
//if the file opened okay, write to it:
if (testFile)
{
fprintf(testFile,"This is a great test");
Serial.println(inputString);
inputString.toCharArray(buff, inputString.length());
fprintf(testFile,buff);
// digitalWrite(6, LOW);
// close the file
fclose(testFile);
}
else
{
// if the file didn't open, print an error
Serial.println("error opening test.txt");
}
}
}
}
/*
SerialEvent occurs whenever a new data comes in the
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
*/
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
digitalWrite(6, HIGH);
stringComplete = true;
}
}
}
Related
I want my Arduino to light up the LED if he reads "on" in the Serial Port.
At Serial.print(serialData); it prints out what he reads but at if (serialData == "on") it wont work.
int led1 = 9;
int led2 = 6;
String serialData;
void setup() {
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
Serial.begin(9600);
Serial.setTimeout(10);
}
void loop() {
if (Serial.available() > 0){
serialData = Serial.readString();
Serial.print(serialData);
if (serialData == "on"){
analogWrite(led1, 255);
}
if (serialData == "off"){
analogWrite(led1, 0);
}
}
}
Anybody know, what I'm doing wrong?
There are two issues in your code:
The timeout is set to 10ms. In 10ms, you can at best enter a single character. readString() will return after a single character and the read string will likely be "o", "n", "f".
When you hit the RETURN key, a carriage return and a line feed character are also transmitted ("\r\n").
The solution is to increase the timeout considerably and to use readStringUntil() to read until the newline character is discovered. This is the indication that a full word (or command) has been entered.
Additionally, the carriage return and line feed need to be trimmed off.
#include <Arduino.h>
int led1 = 9;
int led2 = 6;
String serialData;
void setup() {
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
Serial.begin(9600);
Serial.setTimeout(2000);
}
void loop() {
if (Serial.available() > 0){
serialData = Serial.readStringUntil('\n');
serialData.trim();
Serial.println(serialData);
if (serialData == "on"){
analogWrite(led1, 255);
}
if (serialData == "off"){
analogWrite(led1, 0);
}
}
}
I am new to this shift register. So i created a online simulation of the shift register that hook up to 8 LEDs, the ol' 8bit translate to 8 LED experiment. My design is that when i entered a character like "a" into the serial monitor, it will show in the result in code like 100000, and it should shown in the LEDs too(the sixth LED should light up).
char character;
byte input = 0b01;
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
byte input = 0b01;
if (Serial.available() > 0) {
character = Serial.read();
if (character == 'a') {
Serial.print("character received: ");
Serial.println(character);
for (int i = 0; i < 5; i++) {
updateShiftRegister(input);
input = input << 1;
delay(100);
}
Serial.print("Input: ");
Serial.print(input, BIN);
Serial.println();
} else {
Serial.print("Please retry.\n");
}
}
}
void updateShiftRegister(byte input) {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, input);
digitalWrite(latchPin, HIGH);
}
Problem is when i run the thing, the result is alright but the shift register in the simulation is wack. Every LEDs turn on,
I found the shiftout function is main cause of this, any idea why it is causing every LED to light up?
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!
#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.
#include <stdio.h>
#define LED 13
void setup() {
pinMode(LED, OUTPUT);
Serial.begin(9600);
}
void loop() {
if (Serial.available() == 4) {
char command[5];
for (int i = 0; i < 4; i++) command[i] = Serial.read();
command[4] = '\0';
Serial.println(command);
if (strcmp(command, "AAAA") == 0) {
digitalWrite(LED, HIGH);
Serial.println("LED13 is ON");
} else if (strcmp(command, "BBBB") == 0) {
digitalWrite(LED, LOW);
Serial.println("LED13 is OFF");
}
}
}
I have that code, that reads 4 characters long strings. However, I need it to ignore any string that is not 4 characters long.
So, imagine this input:
AAAA
BBBB
BBB
AAAA
Right now, it reads {"AAAA", "BBBB", "BBBA"}.
I need it to read {"AAAA", "BBBB", "AAAA"}.
Any idea? Thank you.
You can check the duration time of inter-character delay. Set a timeout, such as 100ms. When there is no more data received after the specified timeout, that means the whole string is transferred completely. Then you can check the length of the string and execute your application logic.