Fetching the whole GPRMC data - c++

Hey guys here is my current code
#include <SoftwareSerial.h>
#include <SPI.h>
#include <SD.h>
SoftwareSerial GPS(4,5); /* Software serial - RX, TX pins */
File Cordinates;
/*........................................ Variables declaration ............................................. */
char Rec_data;
char RMC_flag=0,comma=0,i=0,j=0;
char latitude[12],longitude[12];
int smsflag=0,stable=0,finish=0,snd=0;
/*............................................... Setup ....................................................... */
void setup()
{
Serial.begin(9600); /* Initialize serial communication at 9600 bits per second */
GPS.begin(9600); /* Initialize software serial at 9600 bps for GPS */
while (!SD.begin(9))
{
Serial.println("SD Card Initialization failed!");
return;
}
Serial.println("SD Card Initialized");
Serial.print("AT\r\n"); /* Initialization command */
delay(1000);
Serial.print("ATE0\r\n"); /* Turn echo off */
delay(1000);
Serial.print("AT+CMGF=1\r\n"); /* Text mode */
delay(1000);
Serial.print("AT+CNMI=2,1,0,0,0\r\n"); /* Set message format */
delay(1000);
}
/*...................................................Loop...................................................... */
void loop()
{
if(smsflag==0 && finish==1 && snd==0) /* Send message after storing GPS cordinates */
{
Serial.print("AT+CMGS=\"+91xxxxxxxxxx\"\r\n"); /* Replace xxxxxxxxxx with a valid 10-digit mobile no: */
delay(1000);
}
if(smsflag==1 && finish==1 && snd==0) /* Send the message */
{
Serial.print("Latitude:");
Serial.print(latitude); /* Send latitude */
Serial.print("\r\n");
Serial.print("Longitude:");
Serial.print(longitude); /* Send longitude */
Serial.print('\x1A'); /* Send Ctrl+Z after the message */
Cordinates = SD.open("GPS.txt", FILE_WRITE); /* Open the file GPS.txt to write cordinates */
if(Cordinates) /* If the file opened okay, write to it */
{
Serial.print("Writing to GPS.txt...");
Cordinates.print("Latitude:");
Cordinates.println(latitude); /* Write latitude to the file */
Cordinates.print("Longitude:");
Cordinates.println(longitude); /* Write longitude to the file */
Cordinates.close(); /* Close the file */
Serial.println("done.");
}
else
{
Serial.println("Error opening GPS.txt"); /* If the file didn't open, print an error */
}
Cordinates = SD.open("GPS.txt"); /* Re-open the file for reading */
if(Cordinates)
{
Serial.println("GPS.txt");
while (Cordinates.available()) /* Read from the file until there's nothing else in it */
{
Serial.write(Cordinates.read());
}
Cordinates.close(); /* Close the file */
/*----------- Uncomment these lines if you want to delete the file ---------------------------------------------
Serial.println("Removing GPS.txt...");
SD.remove("GPS.txt");
Serial.println("Removed GPS.txt...");
----------------------------------------------------------------------------------------------------------------*/
}
else
{
Serial.println("Error opening GPS.txt"); /* If the file didn't open, print an error */
}
i = 0;
j = 0;
RMC_flag = 0;
comma = 0; /* Clear the variables */
snd = 1;
smsflag = 0;
finish = 0;
stable = 0;
}
while(GPS.available()) /* Check if any data has arrived in software UART */
{
Rec_data = GPS.read(); /* Copy the received charactr to a variable */
if(Rec_data == 'G') /* Check for GPRMC header */
{
RMC_flag = 1;
}
if(Rec_data == 'P' && RMC_flag==1) /* Check for GPRMC header */
{
RMC_flag = 2;
}
if(Rec_data == 'R' && RMC_flag==2) /* Check for GPRMC header
*/
{
RMC_flag = 3;
}
else if(Rec_data=='M' && RMC_flag==3)
{
RMC_flag = 4;
}
else if(Rec_data=='C' && RMC_flag==4)
{
RMC_flag = 5;
}
if(RMC_flag == 5)
{
if(Rec_data==',')
comma++; /* If GPRMC header is received, count the no: of commas */
if(comma==2 && Rec_data=='A') /* Check if GPS is stable */
{
stable=1;
}
else if(comma==2 && Rec_data=='V')
{
stable=0;
comma=0;
RMC_flag=0;
}
else if(comma>=3 && comma<5 && Rec_data!=',' && stable==1)
{
latitude[i++]=Rec_data; /* Store latitude in an array */
}
else if(comma>=5 && comma<7 && Rec_data!=',' && stable==1)
{
longitude[j++]=Rec_data; /* Store longitude in an array */
}
if(Rec_data=='*' && stable==1)
{
comma=0; finish=1;
}
}
}
while (Serial.available()) /* Check if any data has arrived in hardware UART */
{
Rec_data = Serial.read(); /* Copy the received character to a variable */
if(Rec_data=='>') /* Set flag for response to "AT+CMGS=\"+91xxxxxxxxxx\"" */
{
smsflag = 1;
}
}
}
what i want to do is fetch all GPS/Transit data
http://aprs.gids.nl/nmea/
for eg
$GPRMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,ddmmyy,x.x,a*hh
1 = UTC of position fix
2 = Data status (V=navigation receiver warning)
3 = Latitude of fix
4 = N or S
5 = Longitude of fix
6 = E or W
7 = Speed over ground in knots
8 = Track made good in degrees True
9 = UT date
10 = Magnetic variation degrees (Easterly var. subtracts from true course)
11 = E or W
12 = Checksum
i want to get the whole gprmc data
current output is
Latitude:1000.7898N
Longitude:0761
Latitude:1000.7898N
Longitude:0761
Latitude:1000.7898N
Longitude:0761
Latitude:1000.7898N
Longitude:0761
Latitude:1000.7652N
Longitude:07619.8605E
Latitude:1000.7617N
Longitude:07619.8636E
Latitude:1000.7662N
Longitude:07619.8566E

If you want all the data fields, try using my GPS library, NeoGPS. It really simplifies the parsing of all the data fields. Here's your sketch, modified to use NeoGPS:
#include <SPI.h>
#include <SD.h>
#include <NeoSWSerial.h>
#include "NMEAGPS.h"
NeoSWSerial gps_port( 4, 5 );
NMEAGPS gps;
File Cordinates;
bool smsflag = false;
bool snd = false;
//--------------------------
void setup()
{
Serial.begin(9600);
while (!Serial)
;
gps_port.begin(9600);
while (!SD.begin(9)) {
Serial.println( F("SD Card Initialization failed!") );
return;
}
Serial.println( F("SD Card Initialized") );
Serial.print( F("AT\r\n") ); // Initialization command
delay(1000);
Serial.print( F("ATE0\r\n") ); // Turn echo off
delay(1000);
Serial.print( F("AT+CMGF=1\r\n") ); // Text mode
delay(1000);
Serial.print( F("AT+CNMI=2,1,0,0,0\r\n") ); // Set message format
delay(1000);
}
//--------------------------
void loop()
{
while (gps.available( gps_port )) {
gps_fix fix = gps.read();
if (fix.valid.location && !snd) {
if (!smsflag) {
Serial.print( F("AT+CMGS=\"+91xxxxxxxxxx\"\r\n") );
} else {
Serial.print( F("Latitude:") );
Serial.print( fix.latitude(), 6 ); // floating-point format
Serial.print( F("\r\n") );
Serial.print( F("Longitude:") );
Serial.print( fix.longitude(), 6 ); // floating-point format
Serial.print( '\x1A' ); /* Send Ctrl+Z after the message */
snd = true;
Cordinates = SD.open("GPS.txt", FILE_WRITE); // (O_APPEND | O_WRITE | O_CREAT) ?
if (Cordinates) {
Serial.print( F("Writing to GPS.txt...") );
Cordinates.print( F("Latitude:") );
Cordinates.print( fix.latitude(), 6 ); // floating-point format
Cordinates.print( F"Longitude:") );
Cordinates.print( fix.longitude(), 6 ); // floating-point format
Cordinates.close();
Serial.println( F("done.") );
} else {
Serial.println( F("Error opening GPS.txt") );
}
smsflag = false;
}
}
}
while (Serial.available()) {
char c = Serial.read();
if (c == '>') { /* Set flag for response to "AT+CMGS=\"+91xxxxxxxxxx\"" */
smsflag = true;
}
}
}
The NeoGPS Data Model page shows how to get the other fields.
Other notes:
The lat/lon is displayed in floating-point degrees, not the funky DDMM.MMMM of the original NMEA sentences (two digits of degrees, and 6 or more digits of floating-point minutes :P ).
If snd and smsflag can only have the values 0 and 1, use the bool type instead. They can only have values true and false.
Are you sure you only want to send 1 report? snd never gets cleared.
Are you sure you want to send the AT+CMGS command every second? Maybe it should be sent once before the coords are sent?
Using delay in loop() is generally bad, so the AT+CMGS is sent after the coords. The next GPS data won't be available for about 1 second, providing a similar delay.
The NeoSWSerial library is much more reliable than the built-in SoftwareSerial library. AltSoftSerial is even better, if you could use pins 8 & 9.
What Arduino and GPS device are you using? There may be other NeoGPS or serial settings to consider. For example, the F macro is used on 8-bit AVRs to save lots of RAM.

Related

ESP32 Bluetooth connection status

I am running into some problems finding a solution when it comes to performing some form of Bluetooth connection check for my project that will allow me to have a connection status light.
My project consists of creating a Bluetooth speaker that has Led Strips controlled over Bluetooth serial (an app will be made to handle this) and audio stream over Bluetooth from a single ESP32.
I have found plenty of examples and had success with performing an spp callback event, however, of course this only works if I connect to the Bluetooth serial side of things through my 'Serial Bluetooth Terminal' app on my phone. If I just go into my phone Bluetooth list and connect to the audio side of things, nothing is registered, which isn't very useful for a Bluetooth speaker!
Basically I really need some help finding a way of registering that a device has connected to the Bluetooth audio so that I can have some form of indication light to tell the user that they are successfully connected to the speaker to play music.
Below is my code:
#include <btAudio.h> //<-------this is the library that I am using to handle Bluetooth audio to an external I2s DAC
#include "BluetoothSerial.h"
#include <FastLED.h>
TaskHandle_t Task1;
//POWER/BT-LIGHT-SETUP----------------------------------------
int powerPinR = 4;
int powerPinG = 16;
int powerPinB = 17;
bool BTisConnected;
//FAST-LED-STUFF----------------------------------------------
CRGB leds[NUM_STRIPS][NUM_LEDS];
CRGB leds_temp[NUM_STRIPS][NUM_LEDS/2];
//BLUETOOTH-SETUP---------------------------------------------
btAudio audio = btAudio("");
BluetoothSerial SerialBT;
//CONNECTION-CHECK--------------------------------------------
void callback(esp_spp_cb_event_t event, esp_spp_cb_param_t*param){
if(event == ESP_SPP_SRV_OPEN_EVT){
Serial.println("Client Connected");
BTisConnected = true;
}
else {
BTisConnected = false;
}
}
//------------------------------------------------------------
void setup() {
//CORE-1-INITIALISE
xTaskCreatePinnedToCore(
codeForTask1, /* Task function. */
"Task_1", /* name of task. */
1000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* Core */
//POWER/BLUETOOTH-CONNECTION-LIGHT-SETUP
pinMode(powerPinR, OUTPUT);
pinMode(powerPinG, OUTPUT);
pinMode(powerPinB, OUTPUT);
digitalWrite (powerPinR, HIGH);
digitalWrite (powerPinG, HIGH);
digitalWrite (powerPinB, HIGH);
//COOLDOWN-DELAY
delay(3000);
//AUDIO-INITIALISE
audio.begin();
int bck = 26;
int ws = 27;
int dout = 25;
audio.I2S(bck, dout, ws);
//LED-STRIP-SETUP-&-CLEAR-ALL
FastLED.addLeds<WS2812B,STRIP1PIN,GRB>(leds[0], NUM_LEDS);
FastLED.addLeds<WS2812B,STRIP2PIN,GRB>(leds[1], NUM_LEDS);
FastLED.clear();
FastLED.show();
//SERIAL-INITIALISE-&-CLIENT-CONNECTION-CHECK
Serial.begin(115200);
SerialBT.begin("Pilot"); //<-----BLUETOOTH NAME
SerialBT.register_callback(callback); //<-- SerialBT connection check works perfectly, but nothing for audio connection! :(
}
//CORE-0-VOID-LOOP--------------------------------------------
void codeForTask1( void * parameter )
{
for (;;) {
manageData();
delay(10);
}
}
//CORE-1-VOID-LOOP--------------------------------------------
void loop() {
BTconnectionCheck();
playScene();
}
//MANAGE-INCOMING-BLUETOOTH-SERIAL-DATA-----------------------------------------------
void manageData() {
//READ FROM SERIAL AND PARSE OUT ** READ FROM SERIAL AND PARSE OUT ** READ FROM SERIAL AND PARSE OUT **
char rawData[100] = "";
char keyword[] = "Mydata=";
if (SerialBT.available() > 0) {//new data in
size_t byteCount = SerialBT.readBytesUntil('\n', rawData, sizeof(rawData) - 1); //read in data to buffer
rawData[byteCount] = NULL;//put an end character on the data
const char delimiter[] = ",";
char parsedStrings[5][8]; //first number = how many bits of data - 2nd number = max size of eeach data
int dataCount = 0;
int dataPosition = 0;
char *token = strtok(&rawData[dataPosition], delimiter);//look for first piece of data after keyword until comma
if (token != NULL && strlen(token) < sizeof(parsedStrings[0])) {
strncpy(parsedStrings[0], token, sizeof(parsedStrings[0]));
dataCount++;
} else {
Serial.println("token to big");
strcpy(parsedStrings[0], NULL);
}
for (int i = 1; i < 5; i++) {
token = strtok(NULL, delimiter);
if (token != NULL && strlen(token) < sizeof(parsedStrings[i])) {
strncpy(parsedStrings[i], token, sizeof(parsedStrings[i]));
dataCount++;
} else {
Serial.println("token to big");
strcpy(parsedStrings[i], NULL);
}
}
if (dataCount == 5) {
scene = atoi (parsedStrings[0]);
hue = atoi(parsedStrings[1]);
saturation = atoi(parsedStrings[2]);
brightness = atoi(parsedStrings[3]);
eventInterval = atol (parsedStrings[4]);
}
}
}
//BLUETOOTH-CONNECTION-CHECK---------------------------------------------------------
void BTconnectionCheck(){
SerialBT.register_callback(callback);
if (BTisConnected == true){
bluetoothConnected();
}
else {
bluetoothSearch();
}
}
void bluetoothSearch(){
digitalWrite (powerPinR, LOW);
digitalWrite (powerPinG, LOW);
digitalWrite (powerPinB, HIGH);
}
void bluetoothConnected(){
digitalWrite (powerPinR, HIGH);
digitalWrite (powerPinG, LOW);
digitalWrite (powerPinB, HIGH);
}
I have cut lots of the code to do with the LEDs out but its still quite long, If it would help to have a more condensed version then I will chop it down further. Or if it helps to have the full code then I can also post it.
Any help would be greatly appreciated as I am well and truly stuck with this one and its a pretty important part of the project.
Thanks in advance!

Lidar Sensors not working properly - How to work with two lidar Sensors over I2C on arduino

I'm currently working on a project with some friends about lidar measuraments based on ARDUINO and GARMIN Lidar v3HP and we are getting some reading that are questionable from the sensors. They seem to work but the measurements are not correct.
We have issues with the data and also with the address, we setup the sensors with two different addresses 0x42 and 0x43, but one of the sensors keeps on the default address.
#include <Arduino.h>
#include <Wire.h>
#include <stdint.h>
#include <LIDARLite_v3HP.h>
#include <I2CFunctions.h>
#define POWER_ENABLE_S1 12
#define POWER_ENABLE_S2 11
#define DEFAULT_ADDRESS 98
#define FAST_I2C
#define NUMERO_LIDARS 2
LIDARLite_v3HP Sensor1;
LIDARLite_v3HP Sensor2;
int detectedAddreses[NUMERO_LIDARS];
int currentAdd;
int deviceCount = 0;
int i = 0;
void scanI2C()
{
int nDevices = 0;
while (i < NUMERO_LIDARS)
{
for (byte addr = 1; addr < 127; ++addr)
{
Wire.beginTransmission(addr);
byte error = Wire.endTransmission();
if (error == 0)
{
Serial.print("Se encontro un dispositivo en ");
Serial.print(addr);
Serial.println(" !");
++nDevices;
detectedAddreses[i] = addr;
if (addr == DEFAULT_ADDRESS)
{
configSensors(i, 66 + deviceCount, addr);
detectedAddreses[i] = addr;
i++;
}else{
detectedAddreses[i] = addr;
i++;
}
}
else if (error == 4)
{
Serial.print("Error desconocido en ");
Serial.println(addr);
}
}
if (nDevices == 0)
{
Serial.println("No se encontraron dispositivos\n");
}
else
{
Serial.println("Terminado\n");
}
}
}
void configSensors(int sensor, uint8_t new_address, uint8_t old_address)
{
switch (sensor)
{
case 0:
Sensor1.setI2Caddr(new_address, 0, old_address);
digitalWrite(POWER_ENABLE_S1, LOW);
//detectedAddreses[sensor] = new_address;
deviceCount++;
Sensor1.configure(0,new_address);
break;
case 1:
Sensor2.setI2Caddr(new_address, 0, old_address);
digitalWrite(POWER_ENABLE_S2, LOW);
//detectedAddreses[sensor] = new_address;
deviceCount++;
Sensor2.configure(0,new_address);
i = 999;
break;
case 2:
break;
}
}
void setup()
{
Serial.begin(115200);
#ifdef FAST_I2C
#if ARDUINO >= 157
Wire.setClock(400000UL); // Set I2C frequency to 400kHz (for Arduino Due)
#else
TWBR = ((F_CPU / 400000UL) - 16) / 2; // Set I2C frequency to 400kHz
#endif
#endif
pinMode(POWER_ENABLE_S1, OUTPUT);
pinMode(POWER_ENABLE_S2, OUTPUT);
digitalWrite(POWER_ENABLE_S1, HIGH);
digitalWrite(POWER_ENABLE_S2, HIGH);
Wire.begin();
scanI2C();
digitalWrite(POWER_ENABLE_S1,HIGH);
digitalWrite(POWER_ENABLE_S2,HIGH);
Sensor1.configure(3,detectedAddreses[0]);
Sensor2.configure(3,detectedAddreses[1]);
}
void measure(){
float s1;
float s2;
Sensor1.waitForBusy();
Sensor1.takeRange();
Sensor1.waitForBusy();
s1 = Sensor1.readDistance(detectedAddreses[0]);
Sensor2.waitForBusy();
Sensor2.takeRange();
Sensor2.waitForBusy();
s2 = Sensor2.readDistance(detectedAddreses[1]);
Serial.println("Sensor 1: " + String(s1) + "; Sensor 2: " + String(s2));
}
void loop()
{
/*Serial.println(detectedAddreses[0]);
Serial.println(detectedAddreses[1]);*/
measure();
}
Based on your top comment, there may be an issue with configuring both lidars at the same time.
From factory default, they will both respond to the default I2C address 0x62. So, when you try to reconfigure one at a time, they will both respond [and there may be a race condition] and will both get programmed to the new I2C address.
If [and this is a big if] the lidar can save the configuration to non-volatile storage on the unit, you can connect one at a time [physically/manually] and give them different addresses. The unit saves the address. And, next time, will only respond to the "new" address.
Then, after both units have been reconfigured, you can then connect both simultaneously and they will respond individually [as desired].
I looked at the .pdf and the wiring diagram. You may be able to connect the lidar's power pin [or enable pin] to an Arduino GPIO port pin (instead of +5V). Then, you can control the power up of each unit individually. Then, you can reconfigure both as above. That is, assert power to one, reconfigure it, power it down [with the saved config]. Do this for the other unit. Then, you can power up both units [at this point, they are responding to different I2C addresses].
Don't know if Garmin starts up the lasers immediately or whether you have to give it a "start" command. Being able to control power individually may be a good thing if there is no separate start command.
I'm not familiar with Garmin's lidars, but I've written S/W to control Velodyne lidars and we had to apply power in a staggered manner because the power surge when they both started up would "brown out" the system. With Garmin, YMMV.
If all else fails, you may have to put each unit on a separate/different physical I2C bus [because you can't reconfigure them separately].
Here's the working code,
The sensors are hocked up in the same I2C bus, power enable pins to each sensor and ground conected to arduino. Power to the sensors is supplied by a 11.1V battery with a power regulator to 5V
#include <Arduino.h>
#include <Wire.h>
#include <stdint.h>
#include <LIDARLite_v3HP.h>
#include <I2CFunctions.h>
#define POWER_ENABLE_S1 12
#define POWER_ENABLE_S2 11
#define DEFAULT_ADDRESS 98
#define FAST_I2C
#define NUMERO_LIDARS 2
LIDARLite_v3HP Sensor1;
LIDARLite_v3HP Sensor2;
int detectedAddreses[NUMERO_LIDARS];
int currentAdd;
int deviceCount = 0;
int i = 0;
void scanI2C()
{
int nDevices = 0;
while (i < NUMERO_LIDARS)
{
for (byte addr = 1; addr < 127; ++addr)
{
Wire.beginTransmission(addr);
byte error = Wire.endTransmission();
if (error == 0)
{
Serial.print("Se encontro un dispositivo en ");
Serial.print(addr);
Serial.println(" !");
++nDevices;
detectedAddreses[i] = addr;
if (addr == DEFAULT_ADDRESS)
{
configSensors(i, 66 + deviceCount, addr);
detectedAddreses[i] = addr;
i++;
}else{
detectedAddreses[i] = addr;
i++;
}
}
else if (error == 4)
{
Serial.print("Error desconocido en ");
Serial.println(addr);
}
}
if (nDevices == 0)
{
Serial.println("No se encontraron dispositivos\n");
}
else
{
Serial.println("Terminado\n");
}
}
}
void configSensors(int sensor, uint8_t new_address, uint8_t old_address)
{
switch (sensor)
{
case 0:
Sensor1.setI2Caddr(new_address, 0, old_address);
digitalWrite(POWER_ENABLE_S1, LOW);
//detectedAddreses[sensor] = new_address;
deviceCount++;
Sensor1.configure(0,new_address);
break;
case 1:
Sensor2.setI2Caddr(new_address, 0, old_address);
digitalWrite(POWER_ENABLE_S2, LOW);
//detectedAddreses[sensor] = new_address;
deviceCount++;
Sensor2.configure(0,new_address);
i = 999;
break;
case 2:
break;
}
}
void setup()
{
Serial.begin(115200);
#ifdef FAST_I2C
#if ARDUINO >= 157
Wire.setClock(400000UL); // Set I2C frequency to 400kHz (for Arduino Due)
#else
TWBR = ((F_CPU / 400000UL) - 16) / 2; // Set I2C frequency to 400kHz
#endif
#endif
pinMode(POWER_ENABLE_S1, OUTPUT);
pinMode(POWER_ENABLE_S2, OUTPUT);
digitalWrite(POWER_ENABLE_S1, HIGH);
digitalWrite(POWER_ENABLE_S2, HIGH);
Wire.begin();
scanI2C();
digitalWrite(POWER_ENABLE_S1,HIGH);
digitalWrite(POWER_ENABLE_S2,HIGH);
Sensor1.configure(3,detectedAddreses[0]);
Sensor2.configure(3,detectedAddreses[1]);
}
void measure(){
float s1;
float s2;
digitalWrite(POWER_ENABLE_S1,HIGH);
digitalWrite(POWER_ENABLE_S2,LOW);
delay(25);
Sensor1.waitForBusy();
Sensor1.takeRange();
Sensor1.waitForBusy();
s1 = Sensor1.readDistance(detectedAddreses[0]);
digitalWrite(POWER_ENABLE_S1,LOW);
digitalWrite(POWER_ENABLE_S2,HIGH);
delay(25);
Sensor2.waitForBusy();
Sensor2.takeRange();
Sensor2.waitForBusy();
s2 = Sensor2.readDistance(detectedAddreses[1]);
Serial.println("Sensor 1: " + String(s1) + "; Sensor 2: " + String(s2));
}
void loop()
{
/*Serial.println(detectedAddreses[0]);
Serial.println(detectedAddreses[1]);*/
measure();
}

Alt, Course, and Speed not displaying on the LCD display

I wrote this code for my bike computer; however, the Alt, Course, and Speed are not displaying on the LCD display although it is on the Serial monitor. The GPS module isn't returning values either.
/* BaldwinOS by John Seong
An Open-Source Project
Version 1.0
*/
#include <SPI.h>
#include <SD.h>
#include <TinyGPS++.h> // Include the TinyGPS++ library
#include <Wire.h>
TinyGPSPlus tinyGPS; // Create a TinyGPSPlus object
#define ARDUINO_USD_CS 10 // uSD card CS pin (pin 10 on SparkFun GPS Logger Shield)
/////////////////////////
// Log File Defintions //
/////////////////////////
// Keep in mind, the SD library has max file name lengths of 8.3 - 8 char prefix,
// and a 3 char suffix.
// Our log files are called "gpslogXX.csv, so "gpslog99.csv" is our max file.
#define LOG_FILE_PREFIX "gpslog" // Name of the log file.
#define MAX_LOG_FILES 100 // Number of log files that can be made
#define LOG_FILE_SUFFIX "csv" // Suffix of the log file
char logFileName[13]; // Char string to store the log file name
// Data to be logged:
#define LOG_COLUMN_COUNT 8
char * log_col_names[LOG_COLUMN_COUNT] = {
"longitude", "latitude", "altitude", "speed", "course", "date", "time", "satellites"
}; // log_col_names is printed at the top of the file.
//////////////////////
// Log Rate Control //
//////////////////////
#define LOG_RATE 5000 // Log every 5 seconds
unsigned long lastLog = 0; // Global var to keep of last time we logged
#define GPS_BAUD 9600 // GPS module baud rate. GP3906 defaults to 9600.
#define SerLCD_Address 0x72
#include <SoftwareSerial.h>
#define ARDUINO_GPS_RX 9 // GPS TX, Arduino RX pin
#define ARDUINO_GPS_TX 8 // GPS RX, Arduino TX pin
SoftwareSerial ssGPS(ARDUINO_GPS_TX, ARDUINO_GPS_RX); // Create a SoftwareSerial
#define gpsPort ssGPS
#define SerialMonitor Serial
const int statusLED = 9;
const int blueLeftLED = 8;
const int redLeftLED = 7;
const int blueRightLED = 0;
const int redRightLED = 3;
const int leftButton = A3;
const int rightButton = 11;
const int modeButton = 12;
const int buzzer = 13;
void setup() {
SerialMonitor.begin(9600);
gpsPort.begin(GPS_BAUD);
SerialMonitor.println("Setting up SD card.");
// see if the card is present and can be initialized:
if (!SD.begin(ARDUINO_USD_CS))
{
SerialMonitor.println("Error initializing SD card.");
}
updateFileName(); // Each time we start, create a new file, increment the number
printHeader(); // Print a header at the top of the new file
Wire.begin();
Wire.setClock(400000);
Wire.beginTransmission(SerLCD_Address);
Wire.write('|'); // Put LCD into setting mode
Wire.write('-'); // Send clear display command
Wire.write('|'); // Put LCD into setting mode
Wire.write('+'); // Send the Set RGB command
Wire.write(0xFF); // Send the red value
Wire.write(0x00); // Send the green value
Wire.write(0x00); // Send the blue value
Wire.println("Welcome to");
Wire.print("BaldwinOS!");
Wire.endTransmission();
delay(2000);
}
void loop() {
Wire.beginTransmission(SerLCD_Address);
Wire.write('|'); // Put LCD into setting mode
Wire.write('-'); // Send clear display command
Wire.println("Pathfinder");
Wire.print("Bike Computer");
if ((lastLog + LOG_RATE) <= millis())
{ // If it's been LOG_RATE milliseconds since the last log:
if (tinyGPS.location.isUpdated()) // If the GPS data is vaild
{
if (logGPSData()) // Log the GPS data
{
SerialMonitor.println("GPS logged."); // Print a debug message
lastLog = millis(); // Update the lastLog variable
}
else // If we failed to log GPS
{ // Print an error, don't update lastLog
SerialMonitor.println("Failed to log new GPS data.");
}
}
else // If GPS data isn't valid
{
// Print a debug message. Maybe we don't have enough satellites yet.
SerialMonitor.print("No GPS data. Sats: ");
SerialMonitor.println(tinyGPS.satellites.value());
}
}
printStats1();
smartDelay(1000);
}
byte logGPSData()
{
File logFile = SD.open(logFileName, FILE_WRITE); // Open the log file
if (logFile)
{ // Print longitude, latitude, altitude (in feet), speed (in mph), course
// in (degrees), date, time, and number of satellites.
logFile.print(tinyGPS.location.lng(), 6);
logFile.print(',');
logFile.print(tinyGPS.location.lat(), 6);
logFile.print(',');
logFile.print(tinyGPS.altitude.feet(), 1);
logFile.print(',');
logFile.print(tinyGPS.speed.mph(), 1);
logFile.print(',');
logFile.print(tinyGPS.course.deg(), 1);
logFile.print(',');
logFile.print(tinyGPS.date.value());
logFile.print(',');
logFile.print(tinyGPS.time.value());
logFile.print(',');
logFile.print(tinyGPS.satellites.value());
logFile.println();
logFile.close();
return 1; // Return success
}
return 0; // If we failed to open the file, return fail
}
void printHeader()
{
File logFile = SD.open(logFileName, FILE_WRITE); // Open the log file
if (logFile) // If the log file opened, print our column names to the file
{
int i = 0;
for (; i < LOG_COLUMN_COUNT; i++)
{
logFile.print(log_col_names[i]);
if (i < LOG_COLUMN_COUNT - 1) // If it's anything but the last column
logFile.print(','); // print a comma
else // If it's the last column
logFile.println(); // print a new line
}
logFile.close(); // close the file
}
}
// updateFileName() - Looks through the log files already present on a card,
// and creates a new file with an incremented file index.
void updateFileName()
{
int i = 0;
for (; i < MAX_LOG_FILES; i++)
{
memset(logFileName, 0, strlen(logFileName)); // Clear logFileName string
// Set logFileName to "gpslogXX.csv":
sprintf(logFileName, "%s%d.%s", LOG_FILE_PREFIX, i, LOG_FILE_SUFFIX);
if (!SD.exists(logFileName)) // If a file doesn't exist
{
break; // Break out of this loop. We found our index
}
else // Otherwise:
{
SerialMonitor.print(logFileName);
SerialMonitor.println(" exists"); // Print a debug statement
}
}
SerialMonitor.print("File name: ");
SerialMonitor.println(logFileName); // Debug print the file name
}
void printStats1() {
Wire.beginTransmission(SerLCD_Address);
Wire.write('|'); // Put LCD into setting mode
Wire.write('-'); // Send clear display command
Wire.print("Alt: "); Wire.print(tinyGPS.altitude.feet());
Wire.print(" Course: "); Wire.println(tinyGPS.course.deg());
Wire.print("Speed: "); Wire.println(tinyGPS.speed.mph());
Serial.print("Alt: "); SerialMonitor.println(tinyGPS.altitude.feet());
Serial.print("Course: "); SerialMonitor.println(tinyGPS.course.deg());
Serial.print("Speed: "); SerialMonitor.println(tinyGPS.speed.mph());
}
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
// If data has come in from the GPS module
while (gpsPort.available())
tinyGPS.encode(gpsPort.read()); // Send it to the encode function
// tinyGPS.encode(char) continues to "load" the tinGPS object with new
// data coming in from the GPS module. As full NMEA strings begin to come in
// the tinyGPS library will be able to start parsing them for pertinent info
} while (millis() - start < ms);
}
If you are using a passive GPS antenna, you should test it outside (or in an open window pointing the antenna to the sky) to get the satellite fix. TinyGPS lib won't give you back any data if you don't have the fix value

Rotary encoder strange behaviour

I have problem with results (on serial monitor) of rotary encoder.
I am using Arduino UNO and RotaryEncoder library.
When I am running example code serial monitor show proper values when rotating with any speed.
I want to use encoder to change volume in Df-player.
Problem starts when I want to use this code together with more complicated one - Mp3 player.
It actually works only when I am rotating encoder very very slowly
#include <SPI.h>
#include <MFRC522.h>
#include <Arduino.h>
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>
#include <RotaryEncoder.h>
#define RST_PIN 9 // Configurable, see typical pin layout above
#define SS_PIN 10 // Configurable, see typical pin layout above
#define PIN_IN1 2
#define PIN_IN2 3
#define ROTARYSTEPS 1
#define ROTARYMIN 0
#define ROTARYMAX 30
const int playPauseButton = 4;
const int shuffleButton = 5;
boolean isPlaying = false;
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
SoftwareSerial mySoftwareSerial(5, 6); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);
// Setup a RotaryEncoder with 2 steps per latch for the 2 signal input pins:
RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);
// Last known rotary position.
int lastPos = -1;
//*****************************************************************************************//
void setup() {
Serial.begin(9600); // Initialize serial communications with the PC, COMMENT OUT IF IT FAILS TO PLAY WHEN DISCONNECTED FROM PC
mySoftwareSerial.begin(9600);
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522 card
while (! Serial);
encoder.setPosition(5 / ROTARYSTEPS); // start with the value of 5.
pinMode(playPauseButton, INPUT_PULLUP);
pinMode(shuffleButton, INPUT_PULLUP);
Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3.
Serial.println(F("Unable to begin:"));
Serial.println(F("1.Please recheck the connection!"));
Serial.println(F("2.Please insert the SD card!"));
}
Serial.println(F("DFPlayer Mini online. Place card on reader to play a spesific song"));
//myDFPlayer.volume(15); //Set volume value. From 0 to 30
//volumeLevel = map(analogRead(volumePot), 0, 1023, 0, 30); //scale the pot value and volume level
myDFPlayer.volume(5);
//prevVolume = volumeLevel;
//----Set different EQ----
myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
// myDFPlayer.EQ(DFPLAYER_EQ_POP);
// myDFPlayer.EQ(DFPLAYER_EQ_ROCK);
// myDFPlayer.EQ(DFPLAYER_EQ_JAZZ);
// myDFPlayer.EQ(DFPLAYER_EQ_CLASSIC);
// myDFPlayer.EQ(DFPLAYER_EQ_BASS);
}
//*****************************************************************************************//
void loop() {
encoder.tick();
// get the current physical position and calc the logical position
int newPos = encoder.getPosition() * ROTARYSTEPS;
if (newPos < ROTARYMIN) {
encoder.setPosition(ROTARYMIN / ROTARYSTEPS);
newPos = ROTARYMIN;
} else if (newPos > ROTARYMAX) {
encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
newPos = ROTARYMAX;
} // if
if (lastPos != newPos) {
Serial.println(newPos);
myDFPlayer.volume(newPos);
lastPos = newPos;
} // if
// Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
MFRC522::MIFARE_Key key;
for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;
//some variables we need
byte block;
byte len;
MFRC522::StatusCode status;
if (digitalRead(playPauseButton) == LOW) {
if (isPlaying) {
myDFPlayer.pause();
isPlaying = false;
Serial.println("Paused..");
}
else {
isPlaying = true;
myDFPlayer.start();
Serial.println("Playing..");
}
delay(500);
}
if (digitalRead(shuffleButton) == LOW) {
myDFPlayer.randomAll();
Serial.println("Shuffle Play");
isPlaying = true;
delay(1000);
}
//-------------------------------------------
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if ( mfrc522.PICC_IsNewCardPresent()) {
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
Serial.println(F("**Card Detected:**"));
//-------------------------------------------
mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); //dump some details about the card
//mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); //uncomment this to see all blocks in hex
//-------------------------------------------
Serial.print(F("Number: "));
//---------------------------------------- GET NUMBER AND PLAY THE SONG
byte buffer2[18];
block = 1;
len = 18;
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 1, &key, &(mfrc522.uid)); //line 834
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Authentication failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
status = mfrc522.MIFARE_Read(block, buffer2, &len);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Reading failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
//PRINT NUMBER
String number = "";
for (uint8_t i = 0; i < 16; i++)
{
number += (char)buffer2[i];
}
number.trim();
Serial.print(number);
//PLAY SONG
myDFPlayer.play(number.toInt());
isPlaying = true;
//----------------------------------------
Serial.println(F("\n**End Reading**\n"));
delay(1000); //change value if you want to read cards faster
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
}
}
Any ideas what is wrong?
You have a delay(1000) in your main loop, and since your RotaryEncoder object seems to need a tick() function, i am assuming that it is not interrupt driven. This means that it will check only once per second if it has moved to the next step.
If a rotary encoder is stepped twice, and the middle step is missed by the MCU, the latter has no way of knowing which way round the encoder has turned.
So in this case you can only turn it one step per second.
What you need is, either:
a free running main loop, which goes round at least 100 times per second. (less nice)
a rotary encoder driver that is interrupt driven. (very nice)
I don't know if such a library exists, because i tend not to use arduino libs, but it is a very good exercise to write your own using GPIO interrupts.

Entering multiple SPI interfaces

I am having a problem with my code for arduino m0 (using microchip SAMD21). There are two SPI interfaces, first classic and second with int variable in front of the pin name, int MISO, for instance. Does someone know, how to control this classic SPI interface?
I have also attached my code.
PS: Code stucks in begin function of OZONE2CLICK sensor...
#include "Arduino.h"
#include <MQ131.h>
// include RFM69 library
#include <SPI.h>
// Local
#define PC_BAUDRATE 56700
#define MS_DELAY 0 // Number of milliseconds between data sending and LED signalization
#define LED_DELAY 100
#define Serial SerialUSB
// SD card
#define sd_cs_pin 35 // set SD's chip select pin (according to the circuit)
float PPMO2;
float PPBO2;
float MGM3O2;
float UGM3O2;
const byte pinSS = 2; //cs pin
const byte pinRDY = 12;
const byte pinSCK = 13;
const byte O2Pin = 10;
#define DcPin 8
// SD card file
File file; // SD library variable
// LEDS
#define D13_led_pin 42 // D13 LED
#define M_led_pin 36 // MLED
// Local variables
int idCounter = 1;
bool isBmeOk = true;
bool isSdOk = true;
bool isRadioOk = true;
bool isGpsConnected = true;
void OZONE2CLICKCalibrate ()
{
Serial.println("2");
//MQ131.begin(pinSS, pinRDY, O2Pin, LOW_CONCENTRATION, 10000); //(int _pinCS, int _pinRDY, int _pinPower, MQ131Model _model, int _RL)
Serial.println("99");
Serial.println("Calibration in progress...");
MQ131.calibrate();
Serial.println("Calibration done!");
Serial.print("R0 = ");
Serial.print(MQ131.getR0());
Serial.println(" Ohms");
Serial.print("Time to heat = ");
Serial.print(MQ131.getTimeToRead());
Serial.println(" s");
}
void OZONE2CLICKMeasure ()
{
Serial.println("Sampling...");
MQ131.sample();
Serial.print("Concentration O3 : ");
PPMO2 = MQ131.getO3(PPM);
Serial.print(PPMO2);
Serial.println(" ppm");
Serial.print("Concentration O3 : ");
PPBO2 = MQ131.getO3(PPB);
Serial.print(PPBO2);
Serial.println(" ppb");
Serial.print("Concentration O3 : ");
MGM3O2 = MQ131.getO3(MG_M3);
Serial.print(MGM3O2);
Serial.println(" mg/m3");
Serial.print("Concentration O3 : ");
UGM3O2 = MQ131.getO3(UG_M3);
Serial.print(UGM3O2);
Serial.println(" ug/m3");
}
void setup()
{
Serial.begin(PC_BAUDRATE);
// wait for the Arduino serial (on your PC) to connect
// please, open the Arduino serial console (right top corner)
// note that the port may change after uploading the sketch
// COMMENT OUT FOR USAGE WITHOUT A PC!
// while(!Serial);
Serial.println("openCanSat PRO");
Serial.print("Node ");
Serial.print(MYNODEID,DEC);
Serial.println(" ready");
// begin communication with the BME280 on the previously specified address
// print an error to the serial in case the sensor is not found
if (!bme.begin(BME280_ADDRESS_OPEN_CANSAT))
{
isBmeOk = false;
Serial.println("Could not find a valid BME280 sensor, check wiring!");
return;
}
// begin communication with the INA219
ina219.begin();
// check of Gps is connected
Wire.beginTransmission(0x42); // 42 is addres of GPS
int error = Wire.endTransmission();
if (error != 0)
{
isGpsConnected = false;
}
// begin communication with gps
gps.begin();
// Uncomment when you want to see debug prints from GPS library
// gps.debugPrintOn(57600);
if(!radio.initialize(FREQUENCY, MYNODEID, NETWORKID))
{
isRadioOk = false;
Serial.println("RFM69HW initialization failed!");
}
else
{
radio.setFrequency(FREQUENCYSPECIFIC);
radio.setHighPower(true); // Always use this for RFM69HW
}
pinMode(D13_led_pin, OUTPUT);
}
void loop()
{
pinMode(SS, OUTPUT);
digitalWrite(SS, HIGH);
pinMode(DcPin, OUTPUT);
pinMode(O2Pin, OUTPUT);
digitalWrite(DcPin, HIGH);
digitalWrite(O2Pin, HIGH);
delay(10000);
OZONE2CLICKCalibrate();
OZONE2CLICKMeasure();
}
It looks the code opening the SPI connection is commented out:
MQ131.begin(pinSS, pinRDY, O2Pin, LOW_CONCENTRATION, 10000);
You need to configure the SPI connection to get any data from your device.
Refer to reference code from the manufacturer or library you're using to make sure your programming against it correctly.
Please format your code with predictable spacing. This is pretty hard to read.
Since you're using C++, prefer to use:
constexpr <type> NAME = <value>;
rather than macros:
#define NAME (<value>)
Since this is a bare metal compilation, using return in the setup() or loop() functions does not stop them. You probably want something more like while (true) {}. This will loop the code indefinitely, rather than proceed in a bad state.
i.e.:
void stop_forever() {
Serial.println("fatal error detected, stoping forever.");
while (true) {}
}
// then, use it later:
// ...
if (error) {
stop_forever();
}
// ...