Energia – Bài 7: Lấy dữ liệu từ GPS với TIVA C
Ở bài viết này mình sẽ hướng dẫn các bạn lấy dữ liệu từ một modul GPS sử dụng TIVA C
Chuẩn bị
Phần cứng
- TIVA C Launchpad
- Modul GPS ( Ở đây mình sử dụng modul Neo 6M)
- Modul USB2UART PL2303 (hoặc tương tự)
Phần mềm
Kiểm tra modul GPS
Trước tiên chúng ta cần kiểm tra hoạt động của GPS như thế nào, kết nối PL2303 và GPS theo sơ đồ chân như sau
PL2303 | GPS |
---|---|
3v3 | VCC |
TX | RX |
RX | TX |
GND | GND |
Khi đã kết nối dây và cắm vào cổng USB máy tính ta sẽ thấy đèn LED của PL2303 chớp, quan sát qua terminal với baud 9600 sẽ có dữ liệu
Ta thấy có dữ liệu tức là đã giao tiếp được thành công, tuy nhiên giá trị toàn là 99.99 có nghĩa là GPS chưa lấy được tọa độ chính xác. Chúng ta phải chờ một lúc mới có tín hiệu
Khi có được kết quả như trên nghĩa là đã giao tiếp thành công và lấy được dữ liệu về vị trí tọa độ, thời gian,… Coi như yên tâm có thể lấy modul GPS này để giao tiếp với anh TIVA C mà không phải lo lắng nhiều rồi.
Lưu ý:
Một số lưu ý quan trọng khi test modul GPS mà các bạn cần lưu ý
Nguồn cấp: GPS Neo 6M hoạt động với nguồn từ 3.3V – 5V
Kết nối dây đúng: khi nào ra được tọa độ 99.99 là giao tiếp thành công
Đèn báo hiệu: khi LED trên modul GPS chớp tắt thì mới lấy được tọa độ hiện tại
Vị trí: nên test ở modul ở vị trí thoáng mát, ở ngoài trời thì càng tốt để bắt được vị trí nhanh hơn.
Kiên nhẫn: nhiều modul có thể lấy được tọa độ ngay, nhiều cái thì rất lâu, 20 30ph tới cả tiếng, nên bạn cần phải kiên nhẫn nếu có gặp phải trường hợp này thì cứ treo máy để đó làm việc khác cho nhanh.
Lấy dữ liệu GPS với TIVA C
Lấy dữ liệu thô
Ở bước này mình sẽ bỏ PL2303 ra kết nối GPS với TIVA C và lập trình để bắt dữ liệu từ GPS gửi lên, dữ liệu này là dữ liệu thô toàn là GPGxx. Chương trình mình sẽ sử dụng 2 Serial, 1 là để giao tiếp nhận dữ liệu từ GPS với baud 9600
, 1 để debug hiển thị dữ liệu lên máy tính với baud 115200
, cách kết nối dây mình xin ghi chú ở trong code luôn.
/*
Chương trình đọc dữ liệu thô từ GPS
HocARM.org
Kết nối:
GPS TIVA
---------------
VCC | VBUS
RX | PB1
TX | PB0
GND | GND
*/
#define GPSSerial Serial1
void setup() {
// Đợi thông tin từ GPS
while (!Serial);
// Khởi tạo Serial debug baud 115200
Serial.begin(115200);
// 9600 baud is the default rate for the Ultimate GPS
GPSSerial.begin(9600);
}
void loop() {
// Kiểm tra nếu có dữ liệu từ GPS thì in dữ liệu này ra cổng Serial debug
if (GPSSerial.available()) {
char c = GPSSerial.read();
Serial.write(c);
}
}
Kết quả
Xem như chúng ta đã lấy được dữ liệu thô từ GPS rồi, giờ làm sao để biết đâu là kinh độ, đâu là vĩ độ, đâu là thời gian, tốc độ ? Có 2 cách để làm việc này, thứ nhất là tự viết các hàm để xử lý, cách còn lại thì đơn giản và dễ dàng hơn là sử dụng thư viện sẵn có, mình chọn cách 2 cho đơn giản, tận dụng kế thừa được cái người ta đã viết khá ổn rồi. Ở đây mình chọn thư viện TinyGPS có thay đổi và chỉnh sửa để chạy được với TIVA C
Xử lý thông tin GPS
#include <TinyGPS.h>
/* Chương trình hiển thị thông tin GPS đơn giản
Tạo bởi Mikal Hart
Chỉnh sửa cho TIVA C Launchpad bởi hocARM.org
Sử dụng TIVA với modul GPS Neo6M
Sơ đồ kết nối chân:
GPS TIVA
---------------
VCC | VBUS
RX | PB1
TX | PB0
GND | GND
*/
TinyGPS gps;
#define ss Serial1
void setup()
{
//Cấu hình baud debug là 115200 và baud để giao tiếp GPS là 9600
Serial.begin(115200);
ss.begin(9600);
// In thông tin thư viện
Serial.print("Simple TinyGPS library v. "); Serial.println(TinyGPS::library_version());
Serial.println("by Mikal Hart");
Serial.println("Modified for TIVA C Launchpad by hocARM.org");
Serial.println();
}
void loop()
{
bool newData = false;
unsigned long chars;
unsigned short sentences, failed;
// Lấy thông tin từ GPS mỗi 1s
for (unsigned long start = millis(); millis() - start < 1000;)
{
while (ss.available())
{
char c = ss.read();
// Serial.write(c); // Nếu bạn muốn xem dữ liệu thô thì mở dòng này ra
if (gps.encode(c)) // Kiểm tra thông tin từ GPS có đúng không
newData = true;
}
}
//Kiểm tra khi có dữ liệu mới đúng chuẩn thì in thông tin kinh độ, vĩ độ,...
if (newData)
{
float flat, flon;
unsigned long age;
gps.f_get_position(&flat, &flon, &age);
Serial.print("LAT=");
Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
Serial.print(" LON=");
Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
Serial.print(" SAT=");
Serial.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites());
Serial.print(" PREC=");
Serial.print(gps.hdop() == TinyGPS::GPS_INVALID_HDOP ? 0 : gps.hdop());
}
gps.stats(&chars, &sentences, &failed);
Serial.print(" CHARS=");
Serial.print(chars);
Serial.print(" SENTENCES=");
Serial.print(sentences);
Serial.print(" CSUM ERR=");
Serial.println(failed);
if (chars == 0)
Serial.println("** No characters received from GPS: check wiring **");
}
Kết quả chúng ta sẽ có được thông tin về tọa độ
Hiển thị tất cả thông tin của GPS
Coi như phần hiển thị thông tin cơ bản đã xong, giờ xử lý tiếp và hiện toàn bộ thông tin xem thế nào
#include <TinyGPS.h>
/* Chương trình hiển thị thông tin GPS đầy đủ
Tạo bởi Mikal Hart
Chỉnh sửa cho TIVA C Launchpad bởi hocARM.org
Sử dụng TIVA với modul GPS Neo6M
Sơ đồ kết nối chân:
GPS TIVA
---------------
VCC | VBUS
RX | PB1
TX | PB0
GND | GND
*/
#define ss Serial1
TinyGPS gps;
static void smartdelay(unsigned long ms);
static void print_float(float val, float invalid, int len, int prec);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);
void setup()
{
// Cấu hình Serial
Serial.begin(115200);
// In thông tin thư viện
Serial.print("Testing TinyGPS library v. "); Serial.println(TinyGPS::library_version());
Serial.println("by Mikal Hart");
Serial.println("Modified for TIVA C Launchpad by hocARM.org");
Serial.println();
Serial.println("Sats HDOP Latitude Longitude Fix Date Time Date Alt Course Speed Card Distance Course Card Chars Sentences Checksum");
Serial.println(" (deg) (deg) Age Age (m) --- from GPS ---- ---- to London ---- RX RX Fail");
Serial.println("-------------------------------------------------------------------------------------------------------------------------------------");
// Cấu hình baud đọc dữ liệu GPS 9600
ss.begin(9600);
}
void loop()
{
float flat, flon;
unsigned long age, date, time, chars = 0;
unsigned short sentences = 0, failed = 0;
static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002; //thông tin tọa độ London
// Lấy thông tin gps và in ra màn hình
print_int(gps.satellites(), TinyGPS::GPS_INVALID_SATELLITES, 5);
print_int(gps.hdop(), TinyGPS::GPS_INVALID_HDOP, 5);
gps.f_get_position(&flat, &flon, &age);
print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 10, 6);
print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 11, 6);
print_int(age, TinyGPS::GPS_INVALID_AGE, 5);
print_date(gps);
print_float(gps.f_altitude(), TinyGPS::GPS_INVALID_F_ALTITUDE, 7, 2);
print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
print_float(gps.f_speed_kmph(), TinyGPS::GPS_INVALID_F_SPEED, 6, 2);
print_str(gps.f_course() == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(gps.f_course()), 6);
print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0xFFFFFFFF : (unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);
print_float(flat == TinyGPS::GPS_INVALID_F_ANGLE ? TinyGPS::GPS_INVALID_F_ANGLE : TinyGPS::course_to(flat, flon, LONDON_LAT, LONDON_LON), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
print_str(flat == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(TinyGPS::course_to(flat, flon, LONDON_LAT, LONDON_LON)), 6);
gps.stats(&chars, &sentences, &failed);
print_int(chars, 0xFFFFFFFF, 6);
print_int(sentences, 0xFFFFFFFF, 10);
print_int(failed, 0xFFFFFFFF, 9);
Serial.println();
smartdelay(1000);
}
// Hàm delay chờ nhận thông tin từ GPS
static void smartdelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.read());
} while (millis() - start < ms);
}
// Hàm in số thực
static void print_float(float val, float invalid, int len, int prec)
{
if (val == invalid)
{
while (len-- > 1)
Serial.print('*');
Serial.print(' ');
}
else
{
Serial.print(val, prec);
int vi = abs((int)val);
int flen = prec + (val < 0.0 ? 2 : 1); // . and -
flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
for (int i=flen; i<len; ++i)
Serial.print(' ');
}
smartdelay(0);
}
// Hàm in số nguyên
static void print_int(unsigned long val, unsigned long invalid, int len)
{
char sz[32];
if (val == invalid)
strcpy(sz, "*******");
else
sprintf(sz, "%ld", val);
sz[len] = 0;
for (int i=strlen(sz); i<len; ++i)
sz[i] = ' ';
if (len > 0)
sz[len-1] = ' ';
Serial.print(sz);
smartdelay(0);
}
// Hàm in ngày tháng
static void print_date(TinyGPS &gps)
{
int year;
byte month, day, hour, minute, second, hundredths;
unsigned long age;
gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
if (age == TinyGPS::GPS_INVALID_AGE)
Serial.print("********** ******** ");
else
{
char sz[32];
sprintf(sz, "%02d/%02d/%02d %02d:%02d:%02d ",
month, day, year, hour, minute, second);
Serial.print(sz);
}
print_int(age, TinyGPS::GPS_INVALID_AGE, 5);
smartdelay(0);
}
// Hàm in chuỗi
static void print_str(const char *str, int len)
{
int slen = strlen(str);
for (int i=0; i<len; ++i)
Serial.print(i<slen ? str[i] : ' ');
smartdelay(0);
}
Kết quả sẽ có rất nhiều thông tin được hiển thị như hình
Tạm kết
Mình đã hướng dẫn các bạn cách test một modul GPS, đọc dữ liệu từ GPS sử dụng TIVA C và hiển thị toàn bộ thông tin từ GPS theo cách đơn giản nhất, với cách này bạn cs thể đọc được tất cả các loại GPS có trên thị trường dùng chuẩn NMEA,chuẩn dữ liệu NMEA của GPS, về những phần như cấu trúc của GPS như thế nào,cách người ta tạo ra thư viện TinyGPS xin hẹn các bạn ở một bài viết khác.