-Dev The 'missing' / at the beginning was in the correct position earlier and somehow some *** were entered in front of it. This has been corrected. I needed to move the sevseg.refresh.Display(); from the 'If' area as the digits were not being displayed, only the individual led bars in sequence. After I did this all worked perfectly without flicker in the car trial until it reached 31 (kmph) then became ----. Does this have anything to do with
Speed = (int) ((uint32_t)fix.spd.whole * 1852UL)/1000UL; ? Is the 32 a co-incidence? Barrie
bazzlance:
all worked perfectly without flicker in the car trial until it reached 31 (kmph) then became ----. Does this have anything to do withSpeed = (int) ((uint32_t)fix.spd.whole * 1852UL)/1000UL; ?Is the 32 a co-incidence?
Yes, good catch. My desk was always going less than 32kph. ![]()
On the Arduino, int has a valid range of -32768 to +32767. So when the GPS reports a speed of 18knots, the above calculation becomes
Speed = (int) (18 * 1852) / 1000
= (int) (33336) / 1000
= -32200 / 1000
= -32
The 3rd step is where the signed overflow occurs, because I used the (int) casting operator. It's not really needed, but I like to put them in so it's obvious that overflow/truncation might occur. Remove it and it works. You could also insert parentheses to make sure the divide-by-1000 happens before the int cast:
Speed = (int) (((uint32_t)fix.spd.whole * 1852UL)/1000UL);
Here's the complete sketch, including the refresh outside the if statement:
/******************************************************************************
*A0 to GPS Module TX: A1 to GPS Module RX: 5v to GPS Module VCC: Gnd to GPS Module Gnd *
*Digital pins 2,3 4.5 go through 330 ohm resistors to sevseg pins 12,9,8 & 6 respectively *
*Digital pins 6, 7, 8, 9, 10, 11, 12, 13 go to sevseg pins 11, 7, 4, 2, 1, 10, 5, 3 respectively *
* *
* 12 11 10 9 8 7 *
* ___ ___ ___ ___ *
* [___][___][___][___] *
* [___]{___][___][___]o *
* 1 2 3 4 5 6 *
******************************************************************************/
#include <NeoSWSerial.h>
#include <NMEAGPS.h>
#include <SevSeg.h>
int Speed=0;
SevSeg sevseg; //Instantiate a seven segment object
//NeoSWSerial gpsPort(A0,A1);
#define gpsPort Serial1
NMEAGPS gps;
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(9600);
// set the data rate for the software serial port
gpsPort.begin(9600);
byte numDigits = 4;
byte digitPins[] = {2, 3, 4, 5};
byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12, 13};
//Note the use of analogue pins A0 & A1 for the Module Tx & Rx respectively
sevseg.begin(COMMON_ANODE, numDigits, digitPins, segmentPins);
sevseg.setBrightness(15);
}
void loop()
{
if (gps.available( gpsPort )) {
gps_fix fix = gps.read();
Speed = ((uint32_t)fix.spd.whole * 1852UL)/1000UL; // avoids floating-point
Serial.print(Speed);Serial.println( F(" kmh") );
sevseg.setNumber(Speed,0);
}
sevseg.refreshDisplay();
}
Thanks again -Dev. As you wrote it, it wouldn't compile as it didn't like #define gpsPort Serial1 When I commented this out and uncommented //NeoSWSerial gpsPort(A0,A1); it compiled and worked brilliantly at all speeds up to 100 kph. I am sure it will be OK above that too but there are no roads nearby where I can test it. I am very pleased that you became involved since the display is easier to read without flicker and I have learnt something about posting on the forum. i have been doing electronics for a long time but only recently became involved with Arduino. i am 83 but still love a challenge. Barrie
One more thing... I noticed it was skipping some kph values. This is because it was not using the fractional part of the speed. This is a more-accurate calculation:
Speed = ((fix.spd.whole * 100UL + fix.spd.frac) * 18520UL) / 1000000UL;
Glad it's working!
Thanks for that -Dev. I had noticed that and added 1 to the formula. I will now change it to your suggested formula. I have been offline for 3 days. Now I can proceed with hard wiring. Cheers
-Dev, I have been away and just had the chance to test again using your latest formula. Unfortunately it gave erroneous results and jumped around - eg one moment it might indicate 45 and a second later it could be 28; so I have gone back to your previous formula and all is well. Barrie
I have now made a slight modification to the Speed formula to capture decimal amounts > 0.5; it is:
Speed = ((uint32_t)(fix.spd.whole + .27) * 1852UL)/1000UL; // avoids floating-point
Speed = ((uint32_t)(fix.spd.whole + .27) * 1852UL)/1000UL; // avoids floating-point
^
This no longer avoids floating point. Your use of the "0.27" floating-point constant forces the compiler to use the floating-point library for this calculation. If you check your sketch size, you will see that it about 600 bytes bigger. Not a big deal, but now the comment is wrong. ![]()
Also, that calculation skips some values, like 8kph. When the GPS speed is 4.9 knots, the calculated kph is 7. When the GPS speed is 5.0 knots, the calculated kph is 9.
This exact code will correctly calculate the integer speed, without skipping any kph values, and without using floating-point numbers:
void loop()
{
if (gps.available( gpsPort )) {
gps_fix fix;// = gps.read();
if (fix.valid.speed) {
Speed = ((fix.spd.whole * 100UL + fix.spd.frac) * 18520UL) / 1000000UL; // avoids floating-point
// For debugging, display the whole and fractional (hundredths) of the GPS knots
Serial.print( fix.spd.whole );
Serial.print( '.' );
if (fix.spd.frac < 10)
Serial.print( '0' );
Serial.print( fix.spd.frac );
Serial.print( '=' );
Serial.print(Speed);
Serial.println( F(" kmh") );
sevseg.setNumber(Speed,0);
} else {
// blank display?
}
}
sevseg.refreshDisplay();
}
And if you want to round the kph up, use this calculation instead:
Speed = (((fix.spd.whole * 100UL + fix.spd.frac) * 18520UL) + 500000UL)/ 1000000UL; // rounds, avoids floating-point
It simply adds half the last divisor amount before dividing down to the integer speed.
I should also point out that you weren't checking to see if there is a valid speed from the GPS device. It may not report any speed, so you could blank the display, or show a "-". The code above leaves the last valid speed on the display.
Cheers,
/dev