Shop OBEX P1 Docs P2 Docs Learn Events
VPN1513 Smart Mode with Arduino Mega 2560 — Parallax Forums

VPN1513 Smart Mode with Arduino Mega 2560

dchapma6dchapma6 Posts: 4
edited 2015-03-07 12:46 in General Discussion
Hi - I have seen many articles on trying to get Smart Mode working. I have connected a 1n914 diode between Tx & Rx pointing toward Tx with Rx connected to SIO. I am using the Serial3 port on the Mega 2560 and I can see my !GPSn command echoed back but no response from the SIO port. If I pull /RAW low, I see the streams of raw data coming out of SIO so that half works. I see reference to a level problem trying to drive the commands into the SIO port. If I need a level shifter, what do I use and how do I mux Rx & Tx in that case? Help or pointing to a reference would help. Thanks. Dean

Comments

  • Invent-O-DocInvent-O-Doc Posts: 768
    edited 2012-02-02 15:47
    Interesting.

    Are you attempting to use the diode for the voltage drop? Do you have a schematic?

    My understanding is that the Arduino is a 5V part and that the VPN1513 is 3.3V - data returning from the GPS unit to the arduino, if passing through a diode, might not be high enough voltage to register - try a 1K inline resistor instead from the SIO to Rx on GPS and have the Tx to SIO be a simple wire. (Assuming you aren't trying to share the same pin for Rx and Tx)

    Is your 'echo' really coming back from the GPS unit or is your terminal program echoing? (Need to ensure serial coms are correctly configured)
  • dchapma6dchapma6 Posts: 4
    edited 2012-02-02 15:54
    The diode is to allow Rx to go low while Tx is idleing high. Tx--|<---Rx---SIO so data from SIO does not pass through diode. If I hook it up your way, the SIO will not be able to pull down against the Tx?? Yes, the echo is really coming from the GPS interface as it disappears if I don't use the diode.
  • GordonMcCombGordonMcComb Posts: 3,366
    edited 2012-02-02 16:59
    Here's how to do it with an Uno and SoftwareSerial:

    VPN1513-Arduino.png


    Sample code (Arduino 1.0):
    #include <SoftwareSerial.h>
    SoftwareSerial gps(6, 7);      // Rx=6, Tx=7
    long timeout = 1000;           // Timeout if invalid data
    
    #define GetLat    0x05         // Command for latitude
    #define GetLong   0x06         // Command for longitude
    
    void setup() {
      Serial.begin(9600);
      gps.begin(9600);
    }
    
    void loop() {
      delay(1000);
      getData(GetLat);
      Serial.print(",");
      getData(GetLong);
      Serial.println("");
    }
    
    void getData(byte gpsType) {
      if (sendGps(gpsType, 5) == 5) {
        byte degs = gps.read();
        byte mins = gps.read();
        long minsD = gps.read()<<8;
        minsD += gps.read();
        byte dir = gps.read();
        if(dir) { Serial.print("-"); }
        Serial.print(degs, DEC);
        Serial.print(".");
        long workVal = (mins * 1000 / 6) + (minsD / 60);
        Serial.print(workVal, DEC);
      }
    }
    
    byte sendGps (byte cmd, byte numBytes) {
      gps.print("!GPS");  
      gps.write(cmd);
      unsigned long oldMillis = millis();
      while(gps.available() < numBytes) {
        if (millis() - oldMillis > timeout)
          return (0);
      }
      return(gps.available());
    }
    

    Try that.

    -- Gordon
    642 x 393 - 116K
  • GordonMcCombGordonMcComb Posts: 3,366
    edited 2012-02-02 17:06
    My understanding is that the Arduino is a 5V part and that the VPN1513 is 3.3V - data returning from the GPS unit to the arduino, if passing through a diode, might not be high enough voltage to register - try a 1K inline resistor instead from the SIO to Rx on GPS and have the Tx to SIO be a simple wire. (Assuming you aren't trying to share the same pin for Rx and Tx)

    The VPN1513 is a 5V part (actually 4.5 to 12V; it has its own 3.3V regulator for the onboard Propeller and GPS receiver). There is a 1K resistor inline with SIO, so another is not needed. Because the Arduino does not have open collector I/O, and the VPN1513 has a single pin for Tx and Rx, some simple half-duplex steering is needed to connect to the two serial pins. Thus the resistor and diode, as shown in the previous illustration.

    -- Gordon
  • dchapma6dchapma6 Posts: 4
    edited 2012-02-02 19:45
    Thanks much! I'll give that a shot..

    Dean
  • dchapma6dchapma6 Posts: 4
    edited 2012-02-03 15:03
    OK - it works with Qualifications. The pin assignments for SoftwareSerial need to be changed to conform to the Mega2560's limitations on which pins can be used for Tx. I used pin 11 for Rx and pin 10 for Tx. The 1K resistor chokes off the receive stream so I removed it and it works fine. Thanks. I needed to download Arduino V 1.0 to use the SoftwareSerial (I had a previous version). Thanks again for the help.

    Dean
  • SnyperBobSnyperBob Posts: 5
    edited 2012-04-03 08:20
    Hello everyone,
    I was debating on whether or not I should start a new thread or not. I decided to post here, in hopes that Dean or Gordon are subscribed to this thread already and can provide help.

    I have a VPN1513 GPS module hooked up to a Mega. I did the same thing Dean mentioned, I have Rx going to pin 11, Tx to pin 10, and I omitted the resistor. I can get everything working very well, but I am unable to figure out how to code my Arduino to pull the heading. I think I got the speed working, but the same code I used for speed doesn't seem to be working for heading.

    This is driving me nuts and I can't find any VPN1513 smart mode code ANYWHERE for the Arduino, except this thread. (Thanks Gordon!!!)

    I have Lat/Long, speed, validity, and number of sats working. Whatever I'm doing with my heading code seems to cause a buffer overflow or something.

    Here is what I'm working with, I apologize if I should have started a new thread, but I think this is related. Can someone explain to me how the GPS module returns the speed and heading? It says 2 bytes. A byte can only be like 255 maximum, so I guess it has to use some sort of Most Significant Bit and Least Significant Bit or something like that to return the full value of speed/heading. I can't see to figure it out. Can you go into explaining a little bit about how it works, along with a code example?

    Here are parts of my code pertinent to what I'm trying to do.....pieces of it are what Gordon posted.

    I'm also wondering if I'm doing the speed correctly too. It seems to work, but I wonder if I go over 255 mph if that would cause a problem. I don't expect to go that fast ever, but I do want to learn how to code this correctly. Also, is it safe to assume the GPS module will only return a valid heading if you are in motion? That's why I have a little check to make sure speed is > 5.
    #define GetSpeed  0x08          // Command for speed
    #define GetHead   0x09          // Heading/direction of travel in tenths of degrees
    
    
    LiquidCrystal lcd(27, 26, 23, 22, 25, 24);
    
    long Heading = 1;
    long Speed = 0;
    
    
    sendGps(GetSpeed, 2);
      
    Speed = gps.read()<<8;    // First byte of speed
       
      
    Speed += gps.read();          // Add second byte of speed
      
       
    long convertSpeed = Speed/10;    // Speed has MSB and LSB combined, divide by 10 to get the non-decimal equivalent.
       
    Speed = convertSpeed*1.151;    // Converts speed from knots to mph
    
    lcd.print(Speed); 
    
    
    
    void getData(byte gpsType) {
    
    // Heading loop
      if(gpsType == GetHead) {
    
      lcd.clear();
       
       sendGps(gpsType, 2);
       
       // Read each byte one at a time and add it into the string
       
       
       // only update the heading if Speed is faster than 5 knots/mph, otherwise display old heading.
       if(Speed > 5){
         
         
         Heading = gps.read()<<8;        // Change heading 
       
         Heading += gps.read();
         
       }
    
        // Check heading validity.  Not valid if negative!
       if(Heading >= 1){
         
         lcd.print(Heading/10);    // valid heading (positive heading), print it
         
       
       }
       else{
         
         lcd.print("N/A");      // invalid heading, print not available
         
       }
    
    }
    
    
    
    void printHeading(int row) {
      lcd.setCursor(0, row);
    
      lcd.print("Heading: ");
     
      getData(GetHead);
     
    }
    
    
    byte sendGps (byte cmd, byte numBytes) {
      gps.print("!GPS");
      gps.write(cmd);
      unsigned long oldMillis = millis();
      while(gps.available() < numBytes) {
        if (millis() - oldMillis > timeout)
          return (0);
      }
      return(gps.available());
    }
    
    
  • SnyperBobSnyperBob Posts: 5
    edited 2012-04-03 08:27
    I tried to copy what Gordon posted for the Lat/Long with my heading code, but I think I just don't understand what his code does exactly. For example, this code below. I see 5 gps.read() commands sent for grabbing latitude. Three out of the five reads are stored as bytes. One is stored as a long (minsD), but then the next gps.read() is also added onto the previous minsD? I also don't understand what the <<8 does. Why is there on the first gps.read() that is stored into minsD, but not a <<8 on the next line of code, that is also added to minsD?

    void getData(byte gpsType) {
      if (sendGps(gpsType, 5) == 5) {
        byte degs = gps.read();
        byte mins = gps.read();
        long minsD = gps.read()<<8;
        minsD += gps.read();
        byte dir = gps.read();
        if(dir) { Serial.print("-"); }
        Serial.print(degs, DEC);
        Serial.print(".");
        long workVal = (mins * 1000 / 6) + (minsD / 60);
        Serial.print(workVal, DEC);
      }
    }
    
    
    
  • GordonMcCombGordonMcComb Posts: 3,366
    edited 2012-04-03 09:54
    The GPS returns values one byte at a time, which as you surmise means each value is limited to 0-255. Some of the values used with GPS data are meant to form larger numbers, so they require two bytes, combined together. The <<8 construct is a bit-shifter; it takes the eight bits of a byte and pushes them up eight bit positions into the long variable. The second byte read from the GPS fills in the lower 8 bits.

    I didn't look closely at your code but assuming that part is correct, if you're getting what looks like invalid data it could very well be the GPS isn't giving valid data. You really have to be moving for the GPS to deliver useful heading information, and even then, it's often off by several degrees. The 5 MPH you state may not be enough, or it could be sufficient but only after an accumulation of data. If you need accurate heading info you need a digital compass.

    (On edit: I see a logic error in your code. You need to put all of your heading code inside the if block for >5 MPH.The way you have it all of the code after the if test runs, regardless of whether the if test is true or false. )

    -- Gordon
  • SnyperBobSnyperBob Posts: 5
    edited 2012-04-03 11:44
    yes, I was trying to be clever with the heading code. ie...if the speed is above 5 mph/knots, then update the heading. If the speed is below 5 mph, don't update the heading. The heading variable is global, so my thought was that you have to be moving to get a valid heading. So if you are moving (5 mph or faster), update the heading. Otherwise, just display the old heading value if you are stopped. So if you were already heading North before you stopped....the heading stays the same and still shows North.

    With this, I'm just looking for a rudimentary 'compass', like you have in your car. So ideally I will just have the LCD display N/E/W/S based on the GPS heading. It doesn't have to be super accurate, or anything like that.

    I should note that I'm fairly new at programming, so my question probably yields a really basic answer on how to code this.

    I guess my question is, what does the GetHead parameter return? The document says 2 bytes are returned, Heading (Word). It says it is in tenths of degrees.
    So AFAIK, a heading can be between 0 and 360 degrees. If you're talking tenths of degrees, what data should GetHead return if you are traveling 359.9 degrees?

    Would the first byte be 255? Second byte would be what? You can't express a number higher than 255 in a byte, so I'm not understanding how even do a tenth of a degree via bytes.

    if I was traveling 359.0 degrees, I would guess the first byte is 255, second byte is 104. You add the two together to get 359?

    For GetHead, how many times should I be calling gps.read()? Would I call it only twice because it returns 2 bytes?

    I keep looking at how you did the Lat/Long code in this thread, and I don't understand what you're doing with the minsD portion of your code. I'm so confused now
  • PublisonPublison Posts: 12,366
    edited 2012-04-03 11:55
    @SnyperBob,

    Not a very fitting avitar for these forums. You might want to consider changing it, (before the moderators do).
  • SnyperBobSnyperBob Posts: 5
    edited 2012-04-03 12:32
    Thanks, should be changed now.
  • GordonMcCombGordonMcComb Posts: 3,366
    edited 2012-04-03 14:22
    First, though I'm not a moderator I don't think it matters that you've selected an Arduino Mega as an avatar on a Parallax forum. Parallax officially supports the Arduino platform in numerous ways -- including a shield-based product specifically for it -- so I'm not sure using a picture of it should be considered heretical.

    Don't worry why the lat/long code uses two separate several variables for returning minutes. That's simply reflects the way GPS's bundle up their data, in a format usually shown as ddmm.mmmm. The set of four m's needs to be represented by a value larger than 255, hence the need to retrieve it as two separate bytes, then combine the value into a variable type that can hold a value larger than 255.

    To get heading, with is returned as two bytes, you read it twice. The code you have should be close. You've said only that the code "doesn't seem to be working for heading" but haven't elaborated what that means. How is it not working? Is there no data? Is there data but it's random? Is there data but it's always off?

    If the docs say it's in tenths of degrees, the number returned will be more like 0 to 3599 (no decimal point). You can divide by 10 to get 0-359. And no, you don't add them together. You must shift the bits of the first byte as shown. Again, the code you already posted should be pretty close:

    Heading = gps.read()<<8;
    Heading += gps.read();

    It would be helpful if you could be more specific about what the code is doing, even if it's wrong.

    -- Gordon
  • SnyperBobSnyperBob Posts: 5
    edited 2012-04-03 17:42
    Hi Gordon,

    Thanks again for the help, and for looking over my code. After much testing, I realized that the output from the GPS went wonky whenever I was stopped. When I was moving, the heading displayed correctly.

    I kept thinking about it, and an hour later realized my problem. With that Speed loop, it worked great....except I was calling the sendGps(gpsType, 2) function before I checked if the Speed was > 5. So if I was moving, the two gps.read() would execute. But if I was stopped, they would not execute, and it would leave the GPS serial outputs hanging.

    Anyway, here is the corrected code, I moved the sendGps(gpsType, 2) into the loop. This works great, displays last known heading if not moving. The negative heading check in the code below could be eliminated...I had that in there because of all the other problems I had with that bug
    if(gpsType == GetHead) {
       
       
       
       // Read each byte one at a time and add it into the string
       
       
       // only update the heading if Speed is faster than 5 knots/mph, otherwise display 
       if(Speed > 5){
        [B] sendGps(gpsType, 2);            // have to call this when we are going to actually read the data!!![/B]
         
         Heading = gps.read()<<8;        // Change heading 
       
         Heading += gps.read();
         
       }
       else{
         
         lcd.print("* ");      // if I see this character before heading number, means speed is less than 5
         
       }
       
       
       // Check heading validity.  Not valid if negative!
       if(Heading > 1){
         
         lcd.print(Heading/10);    // valid heading (positive heading), print it
         
       
       }
       else{
         
         lcd.print("N/A");      // invalid heading, print not available
         
       }
    
    
  • Chiung-Chan,LiuChiung-Chan,Liu Posts: 1
    edited 2012-12-13 00:04
    I have a question about communication problems.USE VPN1513 Smart Mode with Arduino UNO.

    Connect the line the way:
    GND fpr Ground: 0 V
    Vdd for Supply Voltage: 5 VDC
    SIO for pin 8.
    not other electronic components.

    code:
    #include <SoftwareSerial.h>
    SoftwareSerial gps=SoftwareSerial(8,8);//RX TX onr pin for TX、RX .

    byte getInfo=0x00; //test GPS Receiver Module Version

    void setup()
    {
    // start serial port at 9600 bps:
    Serial.begin(9600);
    Serial.println("gps start");
    //start gps SMART Mode.
    gps.begin(9600);
    }
    void loop()
    {
    gps.print("!GPS");
    gps.write(getInfo);// send Command 0x00 to gps
    delay(500);
    //test YES or NO for communication
    if (gps.available() > 0) {
    delay(50);
    byte info=gps.read(); //read GPS Receiver Module Version
    Serial.println(info); //and print
    delay(1000);
    } else Serial.println("error");

    }


    This is LAB just test communication and code 、Connected Line can normal run.but this's can'n work.
    I do not know where my question.Imagine asking everyone what the problem is?
    Thanks.
  • pilot0315pilot0315 Posts: 912
    edited 2015-03-07 12:46
    Hey guys, just kill the code in the eeprom and write your own. see the my thread under pilot0315 and this device. you would be just programming a prop chip that is attached to the board and you have access to all of the pins below 25 so use it like a quickstart.
Sign In or Register to comment.