极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 68698|回复: 44

简易GPS,本人第一个作品

[复制链接]
发表于 2013-3-26 11:04:25 | 显示全部楼层 |阅读模式
本帖最后由 nngh 于 2013-3-26 12:24 编辑

     
很久以前就对Arduino产生兴趣,在论坛潜水很久了,新近入手一块Arduino UNO R3,一块LCD1602 Keypad Shield和一个GPS Shield,上Google搜索了一下,找到一个葡萄牙人编写的GPS解码程序,稍微修改了一下,增加了串口输出数据功能。
   然后,一个简易GPS诞生了,目前只有日期,时间和地点,速度显示功能而已。本人第一个作品。Arduino IDE 1.01编译通过。
代码如下:

  1. #include <LiquidCrystal.h>  
  2. #include <SoftwareSerial.h>
  3. #define DADOS_LEN 100
  4. #define IDLEN 6
  5. #define TEMPLEN 11
  6. #define GPRMC 0
  7. #define GPGGA 1
  8. char data[DADOS_LEN]; //buffer for GPS data
  9. byte conta=0; //variavel auxiliar para contar
  10. char* idnmea[] = {"$GPRMC","$GPGGA"}; //IDs dos NMEA que vou utilizar
  11. byte verificador[]= {0,0}; //variavel auxiliar para verificar ID NMEA
  12. byte indice[12]; //Em uma linha $GPRMC contem 12 valores separados por virgulas. Esta variavel guarda a posi&#231;&#227;o do caracter de inicio de cada valor.
  13. byte contindice=0; //variavel auxiliar de controle usada na variavel indice[];
  14. byte menu=0; // Menu do LCD: 0-key RIGHT, 1-key UP, 2-key DOWN, 3-key LEFT, 4-key SELECT
  15. char tempmsg[TEMPLEN]; //variavel temporaria auxiliar para guarda o valor de um dado extraido do GPS.
  16. SoftwareSerial nss(3, 2);
  17. LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7);
  18. int  adc_key_val[5] ={30, 150, 360, 535, 760 }; //valores do divisor de tens&#227;o do teclado do LCD Shield
  19. #define NUM_KEYS 5 //numero de teclas do teclado
  20. int adc_key_in; //valor da entrada analogica do teclado
  21. byte key=-1; //tecla pressionada
  22. byte oldkey=-1; //tecla pressionada anteriormente

  23. void setup()
  24.    {
  25.   Serial.begin(9600);
  26.   nss.begin(9600);
  27.   lcd.clear(); //Clear LCD
  28.   lcd.begin(16,2);
  29.   lcd.print("Arduino.cc");
  30.   lcd.setCursor(0, 2); //set cursor on LCD at col 0 and row 2
  31.   lcd.print("Arduino GPS");
  32.   clearBuffer(); //clear buffer for GPS (databuffer)
  33.   clearTemp(); //clear data for GPS (tempmsg)
  34.   //Serial.begin(9600); //Inicia UART para comunicar com módulo GPS
  35.    delay(3000);
  36. }

  37. void loop(){   
  38.     while(nss.available()){//if serial port available
  39.       data[conta] = nss.read(); //Read a byte of the serial port
  40.       if(data[conta]==13){  //If the received byte is = to 13, end of transmission
  41.         verificador[GPRMC]=0; //verifies idnmea[0] ($GPRMC)
  42.         //verificador[GPGGA]=0;//verifies idnmea[1] ($GPGGA)
  43.         for(byte i=1;i<=IDLEN;i++){ //checking the ID NMEA of string received
  44.           if(data[i]==idnmea[GPRMC][i-1]){ //Verifies that is $GPRMC
  45.             verificador[GPRMC]++; //increases 1
  46.           }
  47.          
  48.           //I will not implement $GPGGA do not get too confused
  49.           /*if(data[i]==idnmea[GPGGA][i-1]){ //Verifies that is $GPGGA
  50.             verificador[GPGGA]++; //increases 1
  51.           }*/
  52.         }
  53.         if(verificador[GPRMC]==IDLEN){ // if the line received is $GPRMC
  54.           //A line string of GPRMC has 11 "," Divided into 12 data
  55.           //exemplo: $GPRMC,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,W*70
  56.           //            0      1   2    3    4     5    6    7    8     9     10    11
  57.           // we interesting: 2-timestamp (UTC), 3-latitude, 4-North/South, 5-Longitude, 6-East/West,7-Speed in knots,9-date stamp
  58.           contindice = 0;
  59.           indice[contindice] = 1; //data[] inicia no caracter 1
  60.           contindice++;
  61.           for(byte i=1; i<DADOS_LEN;i++){ //crosses every line data[] identifying where each value of GPS
  62.             if(data[i]==','){ //found the final of a data
  63.               indice[contindice] = i+1;
  64.               contindice++;
  65.             }
  66.           }
  67.           adc_key_in = analogRead(0); //verifica entrada analogica do teclado
  68.           key = get_key(adc_key_in); //interpreta valor da entrada analogica
  69.           if (key != oldkey){ //verifica se o valor encontrado é diferente do valor anterior
  70.             delay(50);                // faz um delay para o debounce
  71.             adc_key_in = analogRead(0);   
  72.             key = get_key(adc_key_in);                        // interpreta
  73.             if (key != oldkey){                        //verifica se é diferente
  74.               oldkey = key; //atualiza oldkey
  75.               lcd.clear(); //clear LCD
  76.               if (key >=0){ //se alguma tecla foi pressionada
  77.                 menu = key; //atualiza o menu
  78.               }
  79.             }
  80.           }

  81.           switch(menu){
  82.              //show on  LCD the key pressed
  83.             case 4: //SELECT 4-key
  84.                 lcd.setCursor(1,0); //move cursor to LCD  column 1 row 0
  85.                 lcd.print("True course"); //print text to LCD
  86.                 lcd.setCursor(1,1); //move cursor to LCD  column 1 row 1
  87.                 lcd.print(datastream(7)); //print text to LCD
  88.               break;            
  89.             case 3: //LEFT 3-key
  90.                 lcd.clear();
  91.                 lcd.setCursor(0,0);
  92.                 lcd.print("Lat:");
  93.                 lcd.print(datastream(4));
  94.                 lcd.print(" ");
  95.                 lcd.print(datastream(3)); // datastream(byte)
  96.                 lcd.setCursor(0, 1);
  97.                 lcd.print("Lon:");
  98.                 lcd.print(datastream(6));
  99.                 lcd.print(" ");
  100.                 lcd.print(datastream(5));
  101.                 break;
  102.             case 1: //UP   1-key
  103.               lcd.setCursor(1,0);
  104.               lcd.print("Date:");
  105.               lcd.print(datastream(9));
  106.               lcd.setCursor(1,1);
  107.               lcd.print("Time:");
  108.               lcd.print(datastream(1));
  109.               break;
  110.             case 2: //DOWN  2-key
  111.               lcd.setCursor(1,0);
  112.               lcd.print("Speed:");
  113.               lcd.print(datastream(7));
  114.               lcd.setCursor(1,1);
  115.               lcd.print("knots");
  116.               break;
  117.            }
  118.             Serial.println("---------------");
  119.          for (int i=0;i<=12;i++){
  120.            switch(i){
  121.              case 0 :Serial.print("Time in UTC (HhMmSs): ");Serial.print(datastream(1));break;
  122.              case 1 :Serial.print("Status (A=OK,V=KO): ");Serial.print(datastream(2));break;
  123.              case 2 :Serial.print("Latitude: ");Serial.print(datastream(3));break;
  124.              case 3 :Serial.print("Direction (N/S): ");Serial.print(datastream(4));break;
  125.              case 4 :Serial.print("Longitude: ");Serial.print(datastream(5));break;
  126.              case 5 :Serial.print("Direction (E/W): ");Serial.print(datastream(6));break;
  127.              case 6 :Serial.print("Velocity in knots: ");Serial.print(datastream(7));break;
  128.              case 7 :Serial.print("Heading in degrees: ");Serial.print(datastream(8));break;
  129.              case 8 :Serial.print("Date UTC (DdMmAa): ");Serial.print(datastream(9));break;
  130.              case 9 :Serial.print("Magnetic degrees: ");break;
  131.              case 10 :Serial.print("(E/W): ");break;
  132.              case 11 :Serial.print("Mode: ");break;
  133.              case 12 :Serial.print("Checksum: ");Serial.print(datastream(11));break;
  134.            }
  135.            
  136.            Serial.println("");
  137.          }
  138.          Serial.println("---------------");
  139.         }

  140.         conta = 0; //zero conta, or is, will start next line of GPS and data[conta] this at position 0
  141.         clearBuffer(); //clear data[]
  142.       }else{
  143.         conta++; //increases conta, in other words, data[conta] skips to the next position
  144.       }
  145.       
  146.     }
  147. }
  148. void clearBuffer(){
  149.   for (byte i=0;i<DADOS_LEN;i++){       // clear variavel (buffer) received GPS data
  150.     data[i]=' ';
  151.   }  
  152. }
  153. void clearTemp(){
  154.   for(byte i=0;i<TEMPLEN;i++)
  155.     tempmsg[i]=' ';
  156. }

  157. char* datastream(byte inicio){
  158.   /*
  159.   Receive Datastream from GPS devices,then convert to Data We can read directly
  160.   remenber that: 2-timestamp (UTC), 3-latitude, 4-North/South, 5-Longitude, 6-East/West,7-Speed in knots,9-date stamp
  161.   */
  162.   clearTemp();
  163.   byte i;
  164.   byte fim = indice[inicio+1]-2;
  165.   inicio = indice[inicio];
  166.   for(i=0;i<=(fim-inicio);i++){
  167.     tempmsg[i] = data[inicio+i];
  168.   }
  169.   tempmsg[i] = '\0';
  170.   return tempmsg;
  171. }

  172. // Convert ADC value to key number
  173. byte get_key(unsigned int input)
  174. {
  175.   int k=menu;
  176.   for (byte i = 0; i < NUM_KEYS; i++){
  177.     if (input < adc_key_val[i]){
  178.       k=i;
  179.       return k;
  180.     }
  181.   }
  182.   return k;

  183. }
复制代码


对于以上基本功能,也试过直接调用TinyGPS库,代码更简单,但是光是没有按键选择功能的代码就有将近8KB,而本程序加入按键功能也才8KB大小。对于只需要基本定位信息而言,TinyGPS库可以不用。
GPS板淘宝上找的,如图,最便宜的一个就是了。

请大家指教啊!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2013-3-26 11:11:06 | 显示全部楼层
太好了,正在找这样的程序!谢谢楼主!
回复 支持 反对

使用道具 举报

发表于 2013-3-26 11:16:17 | 显示全部楼层
尝试编译,出三处错误:
GPS_pde:173: error: incompatible types in assignment of 'char' to 'char [11]'
GPS_pde.cpp: In function 'byte get_key(unsigned int)':
GPS_pde:182: error: ISO C++ forbids comparison between pointer and integer
我是新手,楼主看看什么问题?
另外楼主请问你接的GPS输出的格式有哪些?我手头的GPS输出格式有五六种之多,还关不掉,感觉处理起来很麻烦。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-3-26 11:32:46 | 显示全部楼层
本帖最后由 nngh 于 2013-3-26 12:31 编辑
fangtaonj 发表于 2013-3-26 11:16
尝试编译,出三处错误:
GPS_pde:173: error: incompatible types in assignment of 'char' to 'char [11] ...


握手,我也是新手上路!我也不太懂。
代码我从IDE窗口直接复制过来的。现在是Arduino1.0.3版本。编译通过,GPS速率9600,GPS板TX3号端口,RX2号端口,程序目前只处理GPMRC信息流。目前只能提供这些了
回复 支持 反对

使用道具 举报

发表于 2013-3-26 12:03:50 | 显示全部楼层
这么给力的作品是绝对要顶的
楼主你的GPS模块多少米啊?
回复 支持 反对

使用道具 举报

发表于 2013-3-26 18:26:02 | 显示全部楼层
nngh 发表于 2013-3-26 11:32
握手,我也是新手上路!我也不太懂。
代码我从IDE窗口直接复制过来的。现在是Arduino1.0.3版 ...

握手! 我正在准备吧你的程序在我的机器上运行起来。已把你的程序打印下来正在琢磨。请问您的外围电路有哪些?只是在串口接GPS吗?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-3-26 18:37:56 | 显示全部楼层
fangtaonj 发表于 2013-3-26 18:26
握手! 我正在准备吧你的程序在我的机器上运行起来。已把你的程序打印下来正在琢磨。请问您的外 ...

对呀,就图片中那么多了,还有个GPS天线没拍到,在窗外。
回复 支持 反对

使用道具 举报

发表于 2013-3-26 19:05:38 | 显示全部楼层
看了半天才看懂,这个GPS解析程序是先接收完一帧,然后才进行解析的~~
回复 支持 反对

使用道具 举报

发表于 2013-3-26 19:24:42 | 显示全部楼层
{:soso_e179:}厉害啊
回复 支持 反对

使用道具 举报

发表于 2013-3-26 21:14:05 | 显示全部楼层
飞翔的红猪 发表于 2013-3-26 19:05
看了半天才看懂,这个GPS解析程序是先接收完一帧,然后才进行解析的~~

朋友,我是新手,烦您给解释一下串口读GPS数据那一段程序好吗?我总是有点不太理解。楼主的注释有好些似乎不是英语也不太理解。
回复 支持 反对

使用道具 举报

发表于 2013-3-26 21:16:35 | 显示全部楼层
nngh 发表于 2013-3-26 18:37
对呀,就图片中那么多了,还有个GPS天线没拍到,在窗外。

楼主才看出来你的GPS模块是针对arduino专门设计的模块是嘛?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-3-28 10:09:56 | 显示全部楼层
fangtaonj 发表于 2013-3-26 21:16
楼主才看出来你的GPS模块是针对arduino专门设计的模块是嘛?

是,但本程序对所有串行输出的GPS应该都是适用的。本人新手上路,刚开始没搞懂,也为了省事和保险起见,所有板子都在一家店里买了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-3-28 10:19:12 | 显示全部楼层
fangtaonj 发表于 2013-3-26 21:14
朋友,我是新手,烦您给解释一下串口读GPS数据那一段程序好吗?我总是有点不太理解。楼主的注释有好些似乎 ...

简单回复:先接收一段数据,再从中找出$GPRMC数据头,将之后的数据写入一个一维数组中(缓存),读取时以是否检测到逗号来分隔每个数据。
请专业人士补充
回复 支持 反对

使用道具 举报

发表于 2013-3-28 18:57:13 | 显示全部楼层
谢谢楼主!请专业人士在补充!
回复 支持 反对

使用道具 举报

发表于 2013-3-28 18:59:48 | 显示全部楼层
有高手路过的话请看看那三个错误提示是什么意思?本人纯菜鸟!帮我改好这三个错误我就能跑起来慢慢试验了。谢谢啊!
GPS_pde:173: error: incompatible types in assignment of 'char' to 'char [11]'
GPS_pde.cpp: In function 'byte get_key(unsigned int)':
GPS_pde:182: error: ISO C++ forbids comparison between pointer and integer
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-17 10:07 , Processed in 0.040706 second(s), 22 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表