Hey there, so for a school project I need to make a tracking device using the ATtiny85. This device also uses the NEO6m GPS module and the SIM900 GSM module. Its works by pressing a button so the tiny knows when to send coördinates recieved by the GPS to the GSM. The GSM should send these coördinates to a phone number I have chosen. Instead it only sends 0.000000. I have also made this project using the UNO and it worked there. I'm using the same software but changed a few things so its compatible with the tiny but then I got no coördinates. here is the code I'm using:
#include <SoftwareSerial.h>
#include <TinyGPS.h>
int state = 0;
const int pin = 4;
float gpslat, gpslon;
TinyGPS gps;
SoftwareSerial sgps(0,1); //Tx = pb0
SoftwareSerial sgsm(2,3); //Rx = pb3
void setup()
{
OSCCAL = 70 ;
sgsm.begin(9600);
sgps.begin(9600);
}
void loop()
{
sgps.listen();
while (sgps.available())
{
int c = sgps.read();
if (gps.encode(c))
{
gps.f_get_position(&gpslat, &gpslon);
}
}
if (digitalRead(pin) == HIGH && state == 0) {
sgsm.listen();
sgsm.print("\r");
delay(1000);
sgsm.print("AT+CMGF=1\r");
delay(1000);
/*Replace XXXXXXXXXX to 10 digit mobile number &
ZZ to 2 digit country code*/
sgsm.print("AT+CMGS=\"+32479317685\"\r");
delay(1000);
//The text of the message to be sent.
sgsm.println("Position of your vehicle.");
sgsm.print("Latitude: ");
sgsm.println(gpslat, 6);
sgsm.print("Longitude: ");
sgsm.println(gpslon, 6);
delay(1000);
sgsm.write(0x1A);
delay(1000);
state = 1;
}
if (digitalRead(pin) == LOW) {
state = 0;
}
}
I have tried switching the hardware pins but this has had no effect. Thanks in advance for taking the time to help!
There is a fundamental flaw in the structure of the program and its commonly seen.
In essense;
You turn on the software serial for the GPS and read one NMEA sentence.
There is no check that this one sentence contains location data, but you assume it does.
You stop reading the GPS and thus the next sentences, which may be the ones with the location data are missed.
You turn on software serial for the GSM, do a pile of stuff that takes a while, including sending a telephone message which may not contain any location data (see above).
You turn on the software serial for the GPS and read one NMEA sentence, which also may not contain any location data, but you assume it does.
Look at the TinyGPS examples to see if there is a way to determine if you have a valid location. Don't send an SMS until that is true. If you have a spare pin you could add an LED to light up when there is a valid fix.
EDIT: I just looked at the TinyGPS library and it looks like the values returned when the fix is invalid are TinyGPS::GPS_INVALID_F_ANGLE.
You could try this to see if your GPS is reporting invalid location:
sgsm.println("Position of your vehicle.");
sgsm.print("Latitude: ");
if (gpslat == TinyGPS::GPS_INVALID_F_ANGLE)
sgsm.println("INVALID");
else
sgsm.println(gpslat, 6);
sgsm.print("Longitude: ");
if (gpslon == TinyGPS::GPS_INVALID_F_ANGLE)
sgsm.println("INVALID");
else
sgsm.println(gpslon, 6);
Thanks for your comment! Is there a way that I could read more than one NMEA sentence or a way so that the coördinates are only sent when there is location data recieved?
Thanks for taking the time to comment! I have implemented this software in my program but this does not really fix the problem because now I only get INVALID as messages.
Well, the situation at startup should easy to pick up, dont send the co-ordinates if the location is 0.00000, 0.00000 (unless your near that location of course).
The ongoing situation is no so easy to deal with when using TinyGPS, but is quite easy when using TinyGPSPlus since that has the gps.location.isUpdated() method. No point in sending the location if it has not changed since last time.
The f_get_position() function can return a variable called fix_age, run the example program and see how this varies when there is no fix at startup or the GPS is disconnected when running (so is not updating the fix). You might be able to use this to work out if the GPS fix is updating.
Then the solution hinted at by @groundFungus could be good in that you would use only one SoftwareSerial instance.
Which Arduino core are you using anyway for the ATtiny85?
Clearly, with the Uno, which you say worked, you had one hardware serial and so required only one software serial instance. SoftwareSerial may have restrictions when you 2 instances simultaneously.
OP needs just one software serial channel on the ATtiny: RX for data from GPS, TX for data to GSM. This is workable.
In essence what seems to be happening is identified by srnet (#4) and by johnwasser (#5 & 12): make sure you have a valid fix before sending anything.
Debug #1: send whatever you received to TX, not to GSM but to serial monitor.
Debug #2: only send data after button push after GPS data is validated (post #5)
Debug #3: remedy program sequence (post #4, 12, ..)
As an experiment: ref post #9 (srnet): TinyGPSPlus?
I will include this in the program, thanks. And yes the GPS module has a clear view of the sky without a cloud to see so satellite connection should not be a problem.
Then you do not need to use SoftwareSerial for the serial port. Though you do need to use certain pins for RX (pin 1) and TX (pin 0). See the ATTinyCore documentation:
On the following chips, no hardware serial is available, however, a built-in software serial named Serial is provided to maximize compatibility. This uses the analog comparator pins (to take advantage of the interrupt, since very few sketches/libraries use it, while lots of sketches/libraries use PCINTs). TX is AIN0, RX is AIN1 - This is a software implementation - as such, you cannot receive and send at the same time. If you try, you'll get gibberish, just like using SoftwareSerial. See also the discussion of baud rates.
ATtiny x5 (25/45/85)
ATtiny x4 (24/44/84)
My point with the questions in reply #8 is that you only need one serial port. Connect tiny85 RX to the TX of the GPS and the tiny85 TX to the GSM RX. Then when you print or write the GSM gets it and when you read it comes from the GPS. It is worth a try so you do not need to switch between ports.
When compiling my code the Software Serial is found in the map ATTinyCore. In the case of my project I don't need to switch between ports so this problem is not really applicable here. The feedback is very usefull tho so thank you for taking the time!