本帖最后由 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[DADOS_LEN]; //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[12]; //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[TEMPLEN]; //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);
- int adc_key_val[5] ={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[conta] = nss.read(); //Read a byte of the serial port
- if(data[conta]==13){ //If the received byte is = to 13, end of transmission
- verificador[GPRMC]=0; //verifies idnmea[0] ($GPRMC)
- //verificador[GPGGA]=0;//verifies idnmea[1] ($GPGGA)
- for(byte i=1;i<=IDLEN;i++){ //checking the ID NMEA of string received
- if(data[i]==idnmea[GPRMC][i-1]){ //Verifies that is $GPRMC
- verificador[GPRMC]++; //increases 1
- }
-
- //I will not implement $GPGGA do not get too confused
- /*if(data[i]==idnmea[GPGGA][i-1]){ //Verifies that is $GPGGA
- verificador[GPGGA]++; //increases 1
- }*/
- }
- if(verificador[GPRMC]==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[contindice] = 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[i]==','){ //found the final of a data
- indice[contindice] = 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 on LCD the key pressed
- case 4: //SELECT 4-key
- lcd.setCursor(1,0); //move cursor to LCD column 1 row 0
- lcd.print("True course"); //print text to LCD
- lcd.setCursor(1,1); //move cursor to LCD column 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: //DOWN 2-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[conta] this at position 0
- clearBuffer(); //clear data[]
- }else{
- conta++; //increases conta, in other words, data[conta] skips to the next position
- }
-
- }
- }
- void clearBuffer(){
- for (byte i=0;i<DADOS_LEN;i++){ // clear variavel (buffer) received GPS data
- data[i]=' ';
- }
- }
- void clearTemp(){
- for(byte i=0;i<TEMPLEN;i++)
- tempmsg[i]=' ';
- }
- 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[inicio+1]-2;
- inicio = indice[inicio];
- for(i=0;i<=(fim-inicio);i++){
- tempmsg[i] = data[inicio+i];
- }
- tempmsg[i] = '\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[i]){
- k=i;
- return k;
- }
- }
- return k;
- }
复制代码
对于以上基本功能,也试过直接调用TinyGPS库,代码更简单,但是光是没有按键选择功能的代码就有将近8KB,而本程序加入按键功能也才8KB大小。对于只需要基本定位信息而言,TinyGPS库可以不用。
GPS板淘宝上找的,如图,最便宜的一个就是了。
请大家指教啊! |