Hướng dẫn lập trình Module GPS L80 và Arduino

Module GPS L80 là module thu thập thông tin được gửi về từ các vệ tinh GPS . Các thông tin này bao gồm: thời gian thực, vị trí, tọa độ, vận tốc ...Kết hợp module này với một máy tính hoặc một board mạch Vi xử lý như Arduino là bạn đã có thể làm được một số ứng dụng như thiết bị theo dõi hành trình,  thiết bị chống trộm, đồng hồ thời gian thực ... 

Module GPS L80 được MLAB thiết kế dựa trên module L80 của hãng Quectel.
Module được thiết kế, sản xuất  đảm bảo chất lượng với mục tiêu không chỉ hướng tới việc xây dựng các mô hình nghiên cứu, học tập mà muốn nó trở thành một phần trong các sản phẩm điện tử thương mại của người dùng.
 
Module GPS L80 được tích hợp Pin CR1202, giúp lưu trữ thông tin khi mất điện, GPS L80 còn có cơ chế chuyển đổi Anten linh hoạt, tích hợp Anten trên Chip và Anten ngoài, tự động chuyển Anten khi có lỗi
 
Bài viết hôm nay hướng dẫn các bạn lập trình lấy dữ liệu từ module GPS L80 sử dụng Arduino, hiển thị thông tin nhận được trên màn hình LCD 
 
Chuẩn bị phần cứng
   1 Kit Arduino Uno VN01
   http://mlab.vn/1697809-uno-vn01-arduino-uno-phien-ban-viet-nam.html
   1 LCD Keypad shield
   http://mlab.vn/980100-lcd-1206-keypad-shield-mlab.html
   1 Module GPS L80
   http://mlab.vn/2082249-module-gps-l80.html
   Dây kết nối   
 
 
Sơ đồ kết nối
 
Arduino và LCD Keypad Shield
 

ARDUINO

LCD Keypad Shield

5V

5V

Gnd

Gnd

Pin 4

D4

Pin 5

D5

Pin 6

D6

Pin 7

D7

Pin 8

RS

Pin 9

EN

A0

Nút bấm ADC

 

Arduino và Module GPS L80

ARDUINO

Module GPS L80

5V

5V

Gnd

Gnd

Pin 0 – Rx

RxD

Pin 1 - Tx

TxD

 

Code tham khảo trên mạch Arduino - Uno VN01:

Code này sẽ hiển thị các thông tin về thời gian, tọa độ, tốc độ nhận được từ module GPS lên màn hình LCD, các bạn dùng phím bấm "RIGHT" trên shield LCD để chuyển trang màn hình.

(Lưu ý: Anten GPS phải để ngoài trời hoặc gần cửa sổ thì mới có thể bắt được tín hiệu từ vệ tinh GPS )

 

// code tham khảo do MLAB xây dựng dành cho Arduino, LCD Keypad Shield, Module GPS L80
// website: http://mlab.vn/
// Nội dung: Hiển thị các thông tin về thời gian, tốc độ, tọa độ nhận được từ GPS L80 lên LCD. Sử dụng nút bấm Right để chuyển trang.
// include the library code:
#include <LiquidCrystal.h>
#include "string.h"
#include "stdlib.h"



// Buttons
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5


// GPRMC
#define GPRMC_MID          0
#define GPRMC_UTC         1
#define GPRMC_STS         2
#define GPRMC_LAT         3
#define GPRMC_LAT_NS      4
#define GPRMC_LON         5
#define GPRMC_LON_EW      6
#define GPRMC_SOG         7
#define GPRMC_COG         8
#define GPRMC_DAT         9 
#define GPRMC_MAV         10
#define GPRMC_MAV_EW      11
#define GPRMC_MOD         12

typedef union
{
  unsigned char array_time[7];
  struct
  {
    unsigned char year;
    unsigned char month;
    unsigned char date;
    unsigned char hour;
    unsigned char minute;
    unsigned char sec;
  }time;
}SysTime;

typedef enum
{
  DISPLAY_GPS = 0,
  DISPLAY_RTC,
  DISPLAY_SPEED_ORG,
  DISPLAY_MAX
}DISPLAY_E;

typedef struct{       
  bool State_gps;     /*!< trang thai gps 1 = co tin hieu, 0 = mat tin hieu */
  SysTime time_gps;   /*!< time gps  */
  float Lat;     /*!< vi do */
  float Lng;     /*!< kinh do */
  float SpeedGPS;     /*!< Toc do GPS */
  float OrGPS;      /*!< Huong GPS 360 do */
}GPS_T;     /*!< cau truc du lieu hanh trinh */

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);



static float gps_convert_lon_to_float(unsigned char *lon_str, unsigned char *WE);
static float gps_convert_lat_to_float(unsigned char *lon_str, unsigned char *NS);
static void  NMEA_GPRMC_Decoder(GPS_T *gps_data, String data);
static int   GetMessageFeilds(unsigned char **message_feildls, unsigned char *msg, unsigned char separate_char, int max_feild_get);

GPS_T g_gps_data = {false, {0,0,0,0,0,0,0}, 0, 0, 0, 0};

int read_LCD_buttons(){               // read the buttons
    int adc_key_in = analogRead(0);       // read the value from the sensor 

    // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
    // we add approx 50 to those values and check to see if we are close
    // We make this the 1st option for speed reasons since it will be the most likely result

    if (adc_key_in > 1000) return btnNONE; 

    // For V1.1 us this threshold
    if (adc_key_in < 50)   return btnRIGHT;  
    if (adc_key_in < 250)  return btnUP; 
    if (adc_key_in < 450)  return btnDOWN; 
    if (adc_key_in < 650)  return btnLEFT; 
    if (adc_key_in < 850)  return btnSELECT;  
    return btnNONE;                // when all others fail, return this.
}



void setup() {

  
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  Serial.setTimeout(5);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // prints title with ending line break
  Serial.println("$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n");

  
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("MLAB:Hello World!");
  lcd.setCursor(0, 1);
  lcd.print("mlab.vn");
  

}
int button_pressed, tmp_button, table_display = 0;
void loop() {
  char print_lcd[16];
  char float_str[10];
  int index_gprmc = 0;
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):

  tmp_button = read_LCD_buttons();
  if(button_pressed != tmp_button)
  {
    Serial.println("Key pressed");
    button_pressed = tmp_button;
    if(button_pressed == btnRIGHT)
    {
      table_display++;
      if(table_display >= DISPLAY_MAX)
      {
        table_display = 0;
      }
    }
    if(button_pressed == btnLEFT)
    {
      if(table_display == 0)
      {
        table_display = DISPLAY_MAX - 1;
      }
      else
      {
        table_display--;  
      }
    }
  }
  while (Serial.available() > 0) 
  {
    String str = Serial.readStringUntil(0x0D);
    index_gprmc = str.indexOf("GPRMC");
    if(index_gprmc != -1)  // Just run gprmc
    {
      str = str.substring(index_gprmc);
      NMEA_GPRMC_Decoder(&g_gps_data, str);
      switch(table_display)
      {
        case DISPLAY_GPS:
        {
          if(g_gps_data.State_gps == true)
          {
            lcd.clear();
            lcd.setCursor(0, 0);
            dtostrf(g_gps_data.Lat, 10, 6, float_str);
            sprintf(print_lcd, "lat: %s", float_str);
            lcd.print(print_lcd);
            lcd.setCursor(0, 1);
            dtostrf(g_gps_data.Lng, 10, 6, float_str);
            sprintf(print_lcd, "lng: %s", float_str);
            lcd.print(print_lcd);
            
          }
          else
          {
            lcd.clear();
            lcd.setCursor(0, 0);
            lcd.print("GPS not fix");
          }
          break;
        }
        case DISPLAY_RTC:
        {
          lcd.clear();
          lcd.setCursor(0, 0);
          sprintf(print_lcd, "%04d/%02d/%02d"  , 2000 + g_gps_data.time_gps.time.year  \
                                              , g_gps_data.time_gps.time.month  \
                                              , g_gps_data.time_gps.time.date);
          lcd.print(print_lcd);
          lcd.setCursor(0, 1);
          sprintf(print_lcd, "%02d:%02d:%02d", g_gps_data.time_gps.time.hour   \
                                              , g_gps_data.time_gps.time.minute   \
                                              , g_gps_data.time_gps.time.sec);
          lcd.print(print_lcd);
          break;
        }
        case DISPLAY_SPEED_ORG:
        {
          lcd.clear();
          lcd.setCursor(0, 0);
          dtostrf(g_gps_data.SpeedGPS, 5, 2, float_str);
          sprintf(print_lcd, "SPEED : %s", float_str);
          lcd.print(print_lcd);
          lcd.setCursor(0, 1);
          dtostrf(g_gps_data.OrGPS, 5, 2, float_str);
          sprintf(print_lcd, "ORG : %s", float_str);
          lcd.print(print_lcd);
          break;
        }
        default:
        break;
      }
    }
  }
}

static int GetMessageFeilds(unsigned char **message_feildls, unsigned char *msg, unsigned char separate_char, int max_feild_get)
{
  int count_feild = 0;
  *message_feildls = msg;
  message_feildls++;
  count_feild++;
  while(*msg !='\0')
  {
    if(*msg == separate_char)
    {
      *msg = '\0';
      *message_feildls = msg + 1;
      message_feildls++;
      count_feild++;
      if(count_feild >= max_feild_get)
        return count_feild;
    }
    msg++;
  }
  return count_feild;
}


static float gps_convert_lon_to_float(unsigned char *lon_str, unsigned char *WE)
{
  unsigned char hours[3+1]; 
  unsigned char minutes[8+1];
  float ret;

  memset(hours,0,sizeof(hours));
  memset(minutes,0,sizeof(minutes));

  strncpy( hours, lon_str, 3 );
  strncpy( minutes, lon_str + 3 , strlen(lon_str) - 3 );

  ret = atof(hours);
  ret += atof(minutes)/60;
  if(strcmp(WE, "W") == 0)
  {
    return -ret;
  }
    return ret;
}

static float gps_convert_lat_to_float(unsigned char *lat_str, unsigned char *NS)
{
  unsigned char hours[2+1]; 
  unsigned char minutes[8+1];
  float ret;

  memset(hours,0,sizeof(hours));
  memset(minutes,0,sizeof(minutes));

  strncpy( hours, lat_str, 2 );
  strncpy( minutes, lat_str + 2 , strlen(lat_str) - 2 );

  ret = atof(hours);
  ret += atof(minutes)/60;
  if(strcmp(NS, "S") == 0)
  {
    return -ret;
  }
    return ret;
}

static void NMEA_GPRMC_Decoder(GPS_T *gps_data, String data)
{
  //Get data
  unsigned char data_bytes[128];
  unsigned long time;
  unsigned char hour, minute, second, date, month, year;
  char *message_field[13];
  data.getBytes(data_bytes, 128);
  if(GetMessageFeilds(message_field, data_bytes, ',', 13) == 13)
  {
      if(strcmp(message_field[GPRMC_MID], "GPRMC") != 0)
      {
        return;
      }
      if( strcmp(message_field[GPRMC_STS],"A") == 0)
      {
        gps_data->State_gps = true;
        
        gps_data->SpeedGPS = atof(message_field[GPRMC_SOG]) * 1.852;
        gps_data->OrGPS = atof(message_field[GPRMC_COG]);
        gps_data->Lat = gps_convert_lat_to_float(message_field[GPRMC_LAT], message_field[GPRMC_LAT_NS]);
        gps_data->Lng = gps_convert_lon_to_float(message_field[GPRMC_LON], message_field[GPRMC_LON_EW]);  
      }
      else if( strcmp(message_field[GPRMC_STS],"V") == 0)
      {
        gps_data->State_gps = false;
        gps_data->Lat = 0;
        gps_data->Lng = 0;
        gps_data->SpeedGPS = 0;
        
      }
      *(message_field[GPRMC_UTC] + 6) = '\0';
      
      time = atof(message_field[GPRMC_UTC]);
    
      hour = (unsigned char)(time / 10000);
      minute = (unsigned char)((time % 10000) / 100);
      second = (unsigned char)(((time % 10000) % 100));
    
      time = atof(message_field[GPRMC_DAT]);
      date = (unsigned char)(time / 10000);
      month = (unsigned char)((time % 10000) / 100);
      year = (unsigned char)(((time % 10000) % 100));
    
    
      gps_data->time_gps.time.year = year;
      gps_data->time_gps.time.month = month;
      gps_data->time_gps.time.date = date;
      gps_data->time_gps.time.hour = hour;
      gps_data->time_gps.time.minute = minute;
      gps_data->time_gps.time.sec = second;
  }
}
 

Video 

Viết đánh giá

Họ và tên:


Đánh giá của bạn: Lưu ý: Không hỗ trợ HTML!

Bình chọn: Dở            Hay

Nhập mã bảo vệ: