Arduino serial read and check - c++

I am trying to learn some things about arduino serial reading from a bluetooth device. This is the code I found everywhere:
int incomingByte = 0; // for incoming serial data
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got:
Serial.print("I received: ");
Serial.println(incomingByte);
}
}
When I send the word "word" from my mobile bluetooth I get 4 lines:
I received: w
I received: o
I received: r
I received: d
which is fine... But here 's my question:
I want to check the received characters as soon as they come into the serial input, so if one of them is the character "r", I would like an extra line to be printed in the Serial Monitor, something like: "wow, that was an r!"
So I add an if statement after the println(incomingByte) and my code is now like that:
Serial.print("I received: ");
Serial.println(incomingByte);
if (incomingByte == "r") {
Serial.println("wow, that was an r!");
}
That code never works, it 's like not having an "r" at all.
Could someone explain to me?
Thanks

I think it is due to the usage of "r" instead of 'r'. The difference is that in first case you have string, which is char[], and in the second you have single char.

Related

How to use RTCM data to achieve RTK?

I'm using this example from the Sparkfun Arduino Library
/*
Use ESP32 WiFi to get RTCM data from RTK2Go (caster) as a Client
By: SparkFun Electronics / Nathan Seidle
Date: November 18th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to obtain RTCM data from a NTRIP Caster over WiFi
and push it over I2C to a ZED-F9x.
It's confusing, but the Arduino is acting as a 'client' to a 'caster'. In this case we will
use RTK2Go.com as our caster because it is free. See the NTRIPServer example to see how
to push RTCM data to the caster.
You will need to have a valid mountpoint available. To see available mountpoints go here: http://rtk2go.com:2101/
This is a proof of concept to show how to connect to a caster via HTTP. Using WiFi for a rover
is generally a bad idea because of limited WiFi range in the field.
For more information about NTRIP Clients and the differences between Rev1 and Rev2 of the protocol
please see: https://www.use-snip.com/kb/knowledge-base/ntrip-rev1-versus-rev2-formats/
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
RTK Surveyor: https://www.sparkfun.com/products/18443
RTK Express: https://www.sparkfun.com/products/18442
Hardware Connections:
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
Open the serial monitor at 115200 baud to see the output
*/
#include <WiFi.h>
#include "secrets.h"
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//The ESP32 core has a built in base64 library but not every platform does
//We'll use an external lib if necessary.
#if defined(ARDUINO_ARCH_ESP32)
#include "base64.h" //Built-in ESP32 library
#else
#include <Base64.h> //nfriendly library from https://github.com/adamvr/arduino-base64, will work with any platform
#endif
//Global variables
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long lastReceivedRTCM_ms = 0; //5 RTCM messages take approximately ~300ms to arrive at 115200bps
int maxTimeBeforeHangup_ms = 10000; //If we fail to get a complete RTCM frame after 10s, then disconnect from caster
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
Serial.begin(115200);
Serial.println(F("NTRIP testing"));
Wire.begin(); //Start I2C
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
{
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
myGNSS.setPortInput(COM_PORT_I2C, COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3); //Be sure RTCM3 input is enabled. UBX + RTCM3 is not a valid state.
myGNSS.setNavigationFrequency(1); //Set output in Hz.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.print(F("WiFi connected with IP: "));
Serial.println(WiFi.localIP());
while (Serial.available()) Serial.read();
}
void loop()
{
if (Serial.available())
{
beginClient();
while (Serial.available()) Serial.read(); //Empty buffer of any newline chars
}
Serial.println(F("Press any key to start NTRIP Client."));
delay(1000);
}
//Connect to NTRIP Caster, receive RTCM, and push to ZED module over I2C
void beginClient()
{
WiFiClient ntripClient;
long rtcmCount = 0;
Serial.println(F("Subscribing to Caster. Press key to stop"));
delay(10); //Wait for any serial to arrive
while (Serial.available()) Serial.read(); //Flush
while (Serial.available() == 0)
{
//Connect if we are not already. Limit to 5s between attempts.
if (ntripClient.connected() == false)
{
Serial.print(F("Opening socket to "));
Serial.println(casterHost);
if (ntripClient.connect(casterHost, casterPort) == false) //Attempt connection
{
Serial.println(F("Connection to caster failed"));
return;
}
else
{
Serial.print(F("Connected to "));
Serial.print(casterHost);
Serial.print(F(": "));
Serial.println(casterPort);
Serial.print(F("Requesting NTRIP Data from mount point "));
Serial.println(mountPoint);
const int SERVER_BUFFER_SIZE = 512;
char serverRequest[SERVER_BUFFER_SIZE];
snprintf(serverRequest, SERVER_BUFFER_SIZE, "GET /%s HTTP/1.0\r\nUser-Agent: NTRIP SparkFun u-blox Client v1.0\r\n",
mountPoint);
char credentials[512];
if (strlen(casterUser) == 0)
{
strncpy(credentials, "Accept: */*\r\nConnection: close\r\n", sizeof(credentials));
}
else
{
//Pass base64 encoded user:pw
char userCredentials[sizeof(casterUser) + sizeof(casterUserPW) + 1]; //The ':' takes up a spot
snprintf(userCredentials, sizeof(userCredentials), "%s:%s", casterUser, casterUserPW);
Serial.print(F("Sending credentials: "));
Serial.println(userCredentials);
#if defined(ARDUINO_ARCH_ESP32)
//Encode with ESP32 built-in library
base64 b;
String strEncodedCredentials = b.encode(userCredentials);
char encodedCredentials[strEncodedCredentials.length() + 1];
strEncodedCredentials.toCharArray(encodedCredentials, sizeof(encodedCredentials)); //Convert String to char array
snprintf(credentials, sizeof(credentials), "Authorization: Basic %s\r\n", encodedCredentials);
#else
//Encode with nfriendly library
int encodedLen = base64_enc_len(strlen(userCredentials));
char encodedCredentials[encodedLen]; //Create array large enough to house encoded data
base64_encode(encodedCredentials, userCredentials, strlen(userCredentials)); //Note: Input array is consumed
#endif
}
strncat(serverRequest, credentials, SERVER_BUFFER_SIZE);
strncat(serverRequest, "\r\n", SERVER_BUFFER_SIZE);
Serial.print(F("serverRequest size: "));
Serial.print(strlen(serverRequest));
Serial.print(F(" of "));
Serial.print(sizeof(serverRequest));
Serial.println(F(" bytes available"));
Serial.println(F("Sending server request:"));
Serial.println(serverRequest);
ntripClient.write(serverRequest, strlen(serverRequest));
//Wait for response
unsigned long timeout = millis();
while (ntripClient.available() == 0)
{
if (millis() - timeout > 5000)
{
Serial.println(F("Caster timed out!"));
ntripClient.stop();
return;
}
delay(10);
}
//Check reply
bool connectionSuccess = false;
char response[512];
int responseSpot = 0;
while (ntripClient.available())
{
if (responseSpot == sizeof(response) - 1) break;
response[responseSpot++] = ntripClient.read();
if (strstr(response, "200") > 0) //Look for 'ICY 200 OK'
connectionSuccess = true;
if (strstr(response, "401") > 0) //Look for '401 Unauthorized'
{
Serial.println(F("Hey - your credentials look bad! Check you caster username and password."));
connectionSuccess = false;
}
}
response[responseSpot] = '\0';
Serial.print(F("Caster responded with: "));
Serial.println(response);
if (connectionSuccess == false)
{
Serial.print(F("Failed to connect to "));
Serial.print(casterHost);
Serial.print(F(": "));
Serial.println(response);
return;
}
else
{
Serial.print(F("Connected to "));
Serial.println(casterHost);
lastReceivedRTCM_ms = millis(); //Reset timeout
}
} //End attempt to connect
} //End connected == false
if (ntripClient.connected() == true)
{
uint8_t rtcmData[512 * 4]; //Most incoming data is around 500 bytes but may be larger
rtcmCount = 0;
//Print any available RTCM data
while (ntripClient.available())
{
//Serial.write(ntripClient.read()); //Pipe to serial port is fine but beware, it's a lot of binary data
rtcmData[rtcmCount++] = ntripClient.read();
if (rtcmCount == sizeof(rtcmData)) break;
}
if (rtcmCount > 0)
{
lastReceivedRTCM_ms = millis();
//Push RTCM to GNSS module over I2C
myGNSS.pushRawData(rtcmData, rtcmCount, false);
Serial.print(F("RTCM pushed to ZED: "));
Serial.println(rtcmCount);
}
}
//Close socket if we don't have new data for 10s
if (millis() - lastReceivedRTCM_ms > maxTimeBeforeHangup_ms)
{
Serial.println(F("RTCM timeout. Disconnecting..."));
if (ntripClient.connected() == true)
ntripClient.stop();
return;
}
delay(10);
}
Serial.println(F("User pressed a key"));
Serial.println(F("Disconnecting..."));
ntripClient.stop();
}
on an ESP32 Thing Plus C with a ZED-F9P and it's working fine, but it only outputs RTCM data. How do I apply the RTCM data to the GPS data and achieve RTK? My goal is to have the ESP32 Thing Plus C output RTK Latitude and Longitude to the serial monitor.
Example output:
RTCM pushed to ZED: 163
RTCM pushed to ZED: 311
RTCM pushed to ZED: 1694
RTCM pushed to ZED: 1332
Any ideas would be appeciated! Thanks
Answered by PaulZC on Sparkfun Forum
Hi Jacob,
It sounds like everything is working OK. But, correct, there is
nothing in that example to actually print out the position.
Please try Example17. It is better-structured and uses callbacks to:
display your position; and push NMEA GGA data to the server. Some
NTRIP servers require the GGA data, others don't. If the GGA data
causes problems, you can comment this line to disable the push:
https://github.com/sparkfun/SparkFun_u- ... ck.ino#L81
Have fun! Paul

Strange characters after JSON

I have an application that gets the Arduino Nano information and sends it to ESP-01 via UART. The ESP-01 send this to MQTT.
NANO CODE:
#include "DHTesp.h"
#include <ArduinoJson.h>
#include <SoftwareSerial.h>
#define gasSensor A1
#define dhtPin 5
#define rain A2
#define soil A3
#define ldr A4
DHTesp dht;
void setup() {
Serial.begin(115200);
pinMode(gasSensor, INPUT);
pinMode(rain, INPUT);
pinMode(soil, INPUT);
pinMode(ldr, INPUT);
digitalWrite(dhtPin, LOW);
dht.setup(dhtPin, DHTesp::DHT11);
}
void loop() {
delay(dht.getMinimumSamplingPeriod());
float humidity = dht.getHumidity();
float temperature = dht.getTemperature();
DynamicJsonBuffer jBuffer;
JsonObject& measure = jBuffer.createObject();
JsonObject& data = jBuffer.createObject();
measure["gas"] = analogRead(gasSensor);
measure["humidity"] = humidity;
measure["temperature"] = temperature;
measure["heatindex"] = dht.computeHeatIndex(temperature, humidity, false);
measure["rain"] = analogRead(rain);
measure["soil"] = analogRead(soil);
measure["ldr"] = analogRead(ldr);
data["measure"] = measure;
data.printTo(Serial);
}
ESP-01 CODE:
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
const char* mqtt_server = "0.0.0.0";
WiFiClient espClient;
PubSubClient client(espClient);
char mystr[100];
void setup() {
Serial.begin(115200);
WiFi.begin("", "");
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println();
Serial.print("Connected to IP: ");
Serial.println(WiFi.localIP());
client.setServer(mqtt_server, 1883);
}
void loop() {
if (client.connect("ESP")) {
Serial.println("STATUS MQTT-ESP: OK");
while (true) {
Serial.readBytes(mystr, 108);
client.publish("esp", mystr);
delay(1000);
}
} else {
Serial.println("STATUS MQTT-ESP: OFF");
}
}
But, I'm getting strange characters into MQTT:
And, at the connection between NANO <-uart-> Computer, the JSON is normal:
Someone could help me?
Thanks.
I am basing this answer on a bit of assumptions as I don't have an Arduino at hand.
You send your data like this:
data.printTo(Serial);
This sends the string holding the formatted JSON data. This does not include the terminating 0 byte.
Then you receive it like this:
char mystr[100];
...
while(true){
Serial.readBytes(mystr, 108);
client.publish("esp", mystr);
delay(1000);
}
This has multiple errors:
You do not care if you got any bytes at all. The method returns the number of bytes but you do not handle the return value at all. If you got 0 bytes within the timeout value, you will just send the previous message again instead of waiting for valid data.
You cannot put 108 bytes into memory location of 100 bytes.
You put an array of char into the publish method that does not contain any termination. How should that method know how many characters are really part of the string?
Try this:
while(true){
size_t num = Serial.readBytes(mystr, sizeof(mystr)-1);
mystr[num] = 0;
client.publish("esp", mystr);
delay(1000);
}
You do not have any protocol that allows you to detect when a message starts or ends. UART communiation is a byte stream without any boundaries for datagrams. You must ensure that you know what belongs to a message and what does not. This also means that you can never know if you have a complete message in your receive bufffer or an incomplete or even more than one message. It's up to you to detect and split messages. Fixing this is a bit more complex. I can only give some hints what you need to do.
a) Detect message boundaries:
You might send some terminator like \n, 0 or similar after each JSON string and scan for this extra byte on receiver side.
Or you can send the length of the string before you send the string.
You could also just check on receiver side when you have a matching pair of {}. This would not require any change on sender side.
b) Collect messages:
Call your read function as long as it takes until you detect the end of a string.
You might need to use intermediate buffer to collect multiple read buffers.
c) Forward messages:
As soon as you detected the end of a message, forward it via publish function.
Then move the remaining content of your collection buffer to the start of that buffer.
If you immediately find the end of another message, repeat that step.
If you don't find any complete message, continue to collect more data until the next message is complete.

Serial.read() skips over serial input

Trying to send serial messages using Arduino Uno and standard IDE. Ran into issue parsing the serial message sent to the device.
See that if I include this line Serial.println("Serial.available() = " + String(Serial.available())); I will be able to read the rest of the message. If this is commented out I will only see the first letter of the message and skip over the rest. Attached image of output that I'm seeing with and without the added line of code.
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
while (!Serial) {} // wait for serial to be initialized
Serial.println("Setup called. Serial port ready.");
Serial.println("Waiting for time sync message...");
while (!Serial.available()) {}
processSyncMessage();
}
void processSyncMessage() {
// parse first letter of message
char messageHeader = (char) Serial.read();
switch (messageHeader) {
case TIME_HEADER:
// do processing
break;
default:
Serial.println("Unknown message sent with header: " + String(messageHeader));
// must include this line in order to see the entire message sent
// just calling a println or a Serial.available() doesn't work ????
Serial.println("Serial.available() = " + String(Serial.available()));
Serial.println("---start of message");
for (int r = 0; r != -1; r = Serial.read()) {
Serial.print((char) r);
}
Serial.println();
Serial.println("---end of message");
break;
}
}
Missing Buffer
With printout
Is this somehow related to a buffer? Can I flush it somehow with fflush(SOME_SECRET_BUFFER)?
have you tried Serial.readString() to parse the entire missing characters?
Serial data is transmitted and received one character at a time. At 9600 baud, the transmission rate is approximately one character per millisecond.
The code assumes that once the first character has arrived, all of them have. This is not the case. The addition of the println consumes CPU time, and therefore has the effect of adding a delay. This delay allows the rest of the original message to be received.
A receive function with an appropriate timeout for your application is needed here.

Serial communication between pc and arduino via RS232 using c++

I am trying to communicate with my arduino duemilanove via an RS232 cord. I simply want to be able to send a byte (or char) to my arduino from a desktop application. The Arduino is plugging into USB COM5 on my computer. I have the RS232 plugged into COM1, and then I have pins 2 3 and 5 on the other end of the RS232 connected to arduino pins TX, RX, and GND, respectively.
I found a serial comm class for c++ at the following link:
http://playground.arduino.cc/Interfacing/CPPWindows
I have added the .h and .cpp files from the above example as Serial.h and Serial.cpp (i think the example uses SerialClass.h and SerialClass.cpp, I just changes the names).
On my arduino, I have the following code running:
// ARDUINO
char incomingByte = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got:
Serial.print("I received: ");
Serial.println(incomingByte, HEX);
}
}
And my c++ program is the following:
// C++
#include <iostream>
#include <Windows.h>
#include "Serial.h"
using namespace std;
int main(void)
{
Serial port("COM1");
char* msg = "Hello Arduino!";
int msgLen = strlen(msg);
bool writeSuccess = port.WriteData(msg, msgLen);
cout << "\n\n";
system("PAUSE");
}
When I use the Arduino's serial port viewer to see what is bring printed, I'm getting very strange values that don't match what I'm sending (as far as I can tell).
When I send "Hello Arduino!", the arduino prints the following:
I received: FFFFFFAB
I received: 3A
I received: 3A
I received: A
I received: FFFFFFFA
I received: FFFFFFEB
I received: 6D
I received: 37
I received: 15
I received: 2D
I received: 23
I received: 21
I received: FFFFFFBD
I received: 0
This does not appear to be the correct hex for "Hello Arduino!", but I have no idea why it's not correct. Does anyone have any clue what I'm doing wrong?
Arduino used TTL logic for Serial connection. It expects values at 0 and 5V. RS232 used a different voltage -V to +V. You may need a converter.
Ehm... No! pull up and pull down are not for this reason..
TTL = low: 0V, high: 5V
RS232 = low: +3:+15V, high: -3:-15V
Consequently.. You need a voltage converter (and inverter), like David Skogan correctly pointed out.
Examples:
Using discrete components (has automatic echo feature, i.e. on the PC you will see the data you send): http://project.irone.org/simple-rs232-to-ttl-level-converter.html or http://circuit-diagram.hqew.net/Simple-TTL$2dRS232-Level-Converter-Using-Transistor_2757.html
Common circuit with a MAX232 (or equivalent) and four capacitors
Instead of using a USB-RS232 converter use a USB-UART one, using for instance a FT232 or something like that. This does not need any interface
Or.. simply use the USB port on the Arduino, which already has a FT232 on it.
Personal comment: i'd avoid solution 1...

Arduino: AT Commands - Read the last line of the serial output using Serial.read()

I constantly pass AT commands to get GSM Signal Strength
My code copies the entire serial output
Kindly advise how to read the latest serial output (last line)
find the output below, in which i need to assign the output from last line (21,0) to the variable "signal"
My Output:
AT
OK
AT+CREG?
+CREG: 0,1
ok
AT+CSQ
+CSQ: 21,0
My code:
byte gsmDriverPin[3] = {
3,4,5};
char signal[10];
char inChar;
int index;
char inData[200];
void setup()
{
//Init the driver pins for GSM function
for(int i = 0 ; i < 3; i++){
pinMode(gsmDriverPin[i],OUTPUT);
}
digitalWrite(5,HIGH);//Output GSM Timing
delay(1500);
digitalWrite(5,LOW);
digitalWrite(3,LOW);//Enable the GSM mode
digitalWrite(4,HIGH);//Disable the GPS mode
delay(2000);
Serial.begin(9600); //set the baud rate
delay(5000);//call ready
delay(5000);
delay(5000);
start_GSM();
}
void loop()
{
Signal_Strength();
Serial.println("AT+CMGF=1");
delay(1000);
Serial.println("AT+CMGS=\"1234567890\"");//Change the receiver phone number
delay(1000);
Serial.println(signal);
delay(1000);
Serial.write(26);
}
void Signal_Strength(){
Serial.println("AT+CSQ");
delay(2000);
read_String();
strtok(inData, ",");
strcpy(signal,strtok(NULL, ","));
}
void read_String() {
index=0;
while(Serial.available() > 0) // Don't read unless
// there you know there is data
{
if(index < 199) // One less than the size of the array
{
inChar = Serial.read(); // Read a character
inData[index] = inChar; // Store it
index++; // Increment where to write next
inData[index] = '\0'; // Null terminate the string
}
}
}
void start_GSM(){
//Configuracion GPRS Claro Argentina
Serial.println("AT");
delay(2000);
Serial.println("AT+CREG?");
delay(2000);
}
First of all, you must seriously redo your AT command handling to
Read and parse the every single response line given back from the modem until you get a final result code. This applies for every single command line invocation, no exceptions whatsoever. See this answer for more details.
Never ever call delay in any code that handles AT commands. See this answer for more details about the risk of aborting the next command.
Before fixing these fundamental issues you cannot expect any successful behaviour. Parsing AT command responses is not that complicated, have a look at the source code for atinout for an example.