简易GPS,本人第一个作品
本帖最后由 nngh 于 2013-3-26 12:24 编辑很久以前就对Arduino产生兴趣,在论坛潜水很久了,新近入手一块Arduino UNO R3,一块LCD1602 Keypad Shield和一个GPS Shield,上Google搜索了一下,找到一个葡萄牙人编写的GPS解码程序,稍微修改了一下,增加了串口输出数据功能。
然后,一个简易GPS诞生了,目前只有日期,时间和地点,速度显示功能而已。本人第一个作品。Arduino IDE 1.01编译通过。
代码如下:
#include <LiquidCrystal.h>
#include <SoftwareSerial.h>
#define DADOS_LEN 100
#define IDLEN 6
#define TEMPLEN 11
#define GPRMC 0
#define GPGGA 1
char data; //buffer for GPS data
byte conta=0; //variavel auxiliar para contar
char* idnmea[] = {"$GPRMC","$GPGGA"}; //IDs dos NMEA que vou utilizar
byte verificador[]= {0,0}; //variavel auxiliar para verificar ID NMEA
byte indice; //Em uma linha $GPRMC contem 12 valores separados por virgulas. Esta variavel guarda a posição do caracter de inicio de cada valor.
byte contindice=0; //variavel auxiliar de controle usada na variavel indice[];
byte menu=0; // Menu do LCD: 0-key RIGHT, 1-key UP, 2-key DOWN, 3-key LEFT, 4-key SELECT
char tempmsg; //variavel temporaria auxiliar para guarda o valor de um dado extraido do GPS.
SoftwareSerial nss(3, 2);
LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7);
intadc_key_val ={30, 150, 360, 535, 760 }; //valores do divisor de tensão do teclado do LCD Shield
#define NUM_KEYS 5 //numero de teclas do teclado
int adc_key_in; //valor da entrada analogica do teclado
byte key=-1; //tecla pressionada
byte oldkey=-1; //tecla pressionada anteriormente
void setup()
{
Serial.begin(9600);
nss.begin(9600);
lcd.clear(); //Clear LCD
lcd.begin(16,2);
lcd.print("Arduino.cc");
lcd.setCursor(0, 2); //set cursor on LCD at col 0 and row 2
lcd.print("Arduino GPS");
clearBuffer(); //clear buffer for GPS (databuffer)
clearTemp(); //clear data for GPS (tempmsg)
//Serial.begin(9600); //Inicia UART para comunicar com módulo GPS
delay(3000);
}
void loop(){
while(nss.available()){//if serial port available
data = nss.read(); //Read a byte of the serial port
if(data==13){//If the received byte is = to 13, end of transmission
verificador=0; //verifies idnmea ($GPRMC)
//verificador=0;//verifies idnmea ($GPGGA)
for(byte i=1;i<=IDLEN;i++){ //checking the ID NMEA of string received
if(data==idnmea){ //Verifies that is $GPRMC
verificador++; //increases 1
}
//I will not implement $GPGGA do not get too confused
/*if(data==idnmea){ //Verifies that is $GPGGA
verificador++; //increases 1
}*/
}
if(verificador==IDLEN){ // if the line received is $GPRMC
//A line string of GPRMC has 11 "," Divided into 12 data
//exemplo: $GPRMC,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,W*70
// 0 1 2 3 4 5 6 7 8 9 10 11
// we interesting: 2-timestamp (UTC), 3-latitude, 4-North/South, 5-Longitude, 6-East/West,7-Speed in knots,9-date stamp
contindice = 0;
indice = 1; //data[] inicia no caracter 1
contindice++;
for(byte i=1; i<DADOS_LEN;i++){ //crosses every line data[] identifying where each value of GPS
if(data==','){ //found the final of a data
indice = i+1;
contindice++;
}
}
adc_key_in = analogRead(0); //verifica entrada analogica do teclado
key = get_key(adc_key_in); //interpreta valor da entrada analogica
if (key != oldkey){ //verifica se o valor encontrado é diferente do valor anterior
delay(50); // faz um delay para o debounce
adc_key_in = analogRead(0);
key = get_key(adc_key_in); // interpreta
if (key != oldkey){ //verifica se é diferente
oldkey = key; //atualiza oldkey
lcd.clear(); //clear LCD
if (key >=0){ //se alguma tecla foi pressionada
menu = key; //atualiza o menu
}
}
}
switch(menu){
//show onLCD the key pressed
case 4: //SELECT 4-key
lcd.setCursor(1,0); //move cursor to LCDcolumn 1 row 0
lcd.print("True course"); //print text to LCD
lcd.setCursor(1,1); //move cursor to LCDcolumn 1 row 1
lcd.print(datastream(7)); //print text to LCD
break;
case 3: //LEFT 3-key
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Lat:");
lcd.print(datastream(4));
lcd.print(" ");
lcd.print(datastream(3)); // datastream(byte)
lcd.setCursor(0, 1);
lcd.print("Lon:");
lcd.print(datastream(6));
lcd.print(" ");
lcd.print(datastream(5));
break;
case 1: //UP 1-key
lcd.setCursor(1,0);
lcd.print("Date:");
lcd.print(datastream(9));
lcd.setCursor(1,1);
lcd.print("Time:");
lcd.print(datastream(1));
break;
case 2: //DOWN2-key
lcd.setCursor(1,0);
lcd.print("Speed:");
lcd.print(datastream(7));
lcd.setCursor(1,1);
lcd.print("knots");
break;
}
Serial.println("---------------");
for (int i=0;i<=12;i++){
switch(i){
case 0 :Serial.print("Time in UTC (HhMmSs): ");Serial.print(datastream(1));break;
case 1 :Serial.print("Status (A=OK,V=KO): ");Serial.print(datastream(2));break;
case 2 :Serial.print("Latitude: ");Serial.print(datastream(3));break;
case 3 :Serial.print("Direction (N/S): ");Serial.print(datastream(4));break;
case 4 :Serial.print("Longitude: ");Serial.print(datastream(5));break;
case 5 :Serial.print("Direction (E/W): ");Serial.print(datastream(6));break;
case 6 :Serial.print("Velocity in knots: ");Serial.print(datastream(7));break;
case 7 :Serial.print("Heading in degrees: ");Serial.print(datastream(8));break;
case 8 :Serial.print("Date UTC (DdMmAa): ");Serial.print(datastream(9));break;
case 9 :Serial.print("Magnetic degrees: ");break;
case 10 :Serial.print("(E/W): ");break;
case 11 :Serial.print("Mode: ");break;
case 12 :Serial.print("Checksum: ");Serial.print(datastream(11));break;
}
Serial.println("");
}
Serial.println("---------------");
}
conta = 0; //zero conta, or is, will start next line of GPS and data this at position 0
clearBuffer(); //clear data[]
}else{
conta++; //increases conta, in other words, data skips to the next position
}
}
}
void clearBuffer(){
for (byte i=0;i<DADOS_LEN;i++){ // clear variavel (buffer) received GPS data
data=' ';
}
}
void clearTemp(){
for(byte i=0;i<TEMPLEN;i++)
tempmsg=' ';
}
char* datastream(byte inicio){
/*
Receive Datastream from GPS devices,then convert to Data We can read directly
remenber that: 2-timestamp (UTC), 3-latitude, 4-North/South, 5-Longitude, 6-East/West,7-Speed in knots,9-date stamp
*/
clearTemp();
byte i;
byte fim = indice-2;
inicio = indice;
for(i=0;i<=(fim-inicio);i++){
tempmsg = data;
}
tempmsg = '\0';
return tempmsg;
}
// Convert ADC value to key number
byte get_key(unsigned int input)
{
int k=menu;
for (byte i = 0; i < NUM_KEYS; i++){
if (input < adc_key_val){
k=i;
return k;
}
}
return k;
}
对于以上基本功能,也试过直接调用TinyGPS库,代码更简单,但是光是没有按键选择功能的代码就有将近8KB,而本程序加入按键功能也才8KB大小。对于只需要基本定位信息而言,TinyGPS库可以不用。
GPS板淘宝上找的,如图,最便宜的一个就是了。
请大家指教啊! 太好了,正在找这样的程序!谢谢楼主!
尝试编译,出三处错误:
GPS_pde:173: error: incompatible types in assignment of 'char' to 'char '
GPS_pde.cpp: In function 'byte get_key(unsigned int)':
GPS_pde:182: error: ISO C++ forbids comparison between pointer and integer
我是新手,楼主看看什么问题?
另外楼主请问你接的GPS输出的格式有哪些?我手头的GPS输出格式有五六种之多,还关不掉,感觉处理起来很麻烦。
本帖最后由 nngh 于 2013-3-26 12:31 编辑
fangtaonj 发表于 2013-3-26 11:16 static/image/common/back.gif
尝试编译,出三处错误:
GPS_pde:173: error: incompatible types in assignment of 'char' to 'char ...
握手:handshake,我也是新手上路!我也不太懂。
代码我从IDE窗口直接复制过来的。现在是Arduino1.0.3版本。编译通过,GPS速率9600,GPS板TX3号端口,RX2号端口,程序目前只处理GPMRC信息流。目前只能提供这些了:'( 这么给力的作品是绝对要顶的
楼主你的GPS模块多少米啊? nngh 发表于 2013-3-26 11:32 static/image/common/back.gif
握手,我也是新手上路!我也不太懂。
代码我从IDE窗口直接复制过来的。现在是Arduino1.0.3版 ...
握手!:handshake 我正在准备吧你的程序在我的机器上运行起来。已把你的程序打印下来正在琢磨。请问您的外围电路有哪些?只是在串口接GPS吗? fangtaonj 发表于 2013-3-26 18:26 static/image/common/back.gif
握手! 我正在准备吧你的程序在我的机器上运行起来。已把你的程序打印下来正在琢磨。请问您的外 ...
对呀,就图片中那么多了,还有个GPS天线没拍到,在窗外。 看了半天才看懂,这个GPS解析程序是先接收完一帧,然后才进行解析的~~:L {:soso_e179:}厉害啊 飞翔的红猪 发表于 2013-3-26 19:05 static/image/common/back.gif
看了半天才看懂,这个GPS解析程序是先接收完一帧,然后才进行解析的~~
朋友,我是新手,烦您给解释一下串口读GPS数据那一段程序好吗?我总是有点不太理解。楼主的注释有好些似乎不是英语也不太理解。 nngh 发表于 2013-3-26 18:37 static/image/common/back.gif
对呀,就图片中那么多了,还有个GPS天线没拍到,在窗外。
楼主才看出来你的GPS模块是针对arduino专门设计的模块是嘛? fangtaonj 发表于 2013-3-26 21:16 static/image/common/back.gif
楼主才看出来你的GPS模块是针对arduino专门设计的模块是嘛?
是,但本程序对所有串行输出的GPS应该都是适用的。本人新手上路,刚开始没搞懂,也为了省事和保险起见,所有板子都在一家店里买了。 fangtaonj 发表于 2013-3-26 21:14 static/image/common/back.gif
朋友,我是新手,烦您给解释一下串口读GPS数据那一段程序好吗?我总是有点不太理解。楼主的注释有好些似乎 ...
简单回复:先接收一段数据,再从中找出$GPRMC数据头,将之后的数据写入一个一维数组中(缓存),读取时以是否检测到逗号来分隔每个数据。
请专业人士补充:) 谢谢楼主!请专业人士在补充! 有高手路过的话请看看那三个错误提示是什么意思?本人纯菜鸟!帮我改好这三个错误我就能跑起来慢慢试验了。谢谢啊!
GPS_pde:173: error: incompatible types in assignment of 'char' to 'char '
GPS_pde.cpp: In function 'byte get_key(unsigned int)':
GPS_pde:182: error: ISO C++ forbids comparison between pointer and integer