#include "U8glib.h"
#include <SD.h>
#include
<TinyGPS.h>
#include
<avr/pgmspace.h>
//使用PROGMEM存放GPS方向数组,节省SRAM
prog_char d_0[] PROGMEM
= "N";
prog_char d_1[] PROGMEM = "NNE";
prog_char d_2[] PROGMEM =
"NE";
prog_char d_3[] PROGMEM = "ENE";
prog_char d_4[] PROGMEM =
"E";
prog_char d_5[] PROGMEM = "ESE";
prog_char d_6[] PROGMEM =
"SE";
prog_char d_7[] PROGMEM = "SSE";
prog_char d_8[] PROGMEM =
"S";
prog_char d_9[] PROGMEM = "SSW";
prog_char d_10[] PROGMEM =
"SW";
prog_char d_11[] PROGMEM = "WSW";
prog_char d_12[] PROGMEM =
"W";
prog_char d_13[] PROGMEM = "WNW";
prog_char d_14[] PROGMEM =
"NW";
prog_char d_15[] PROGMEM = "NNW";
PROGMEM const char *dir_table[]
=
{
d_0,
d_1,
d_2,
d_3,
d_4,
d_5,
d_6,
d_7,
d_8,
d_9,
d_10,
d_11,
d_12,
d_13,
d_14,
d_15
};
TinyGPS gps;
//U8GLIB_PCD8544 u8g(3,
4, 99, 5, 6); // SPI Com: SCK = 3, MOSI = 4, CS = 永远接地, A0 = 5, Reset =
6
U8GLIB_ST7920_128X64_4X u8g(3, 9, 8); // 声明液晶屏 8-D/I 9-R/W 3-E
File
myFile;
boolean sderror = false; //TF卡状态
char logname[13];
//记录文件名
boolean writelog = true;
//是否要记录当前数据到TF卡标志
boolean refresh = false;
//是否要更新液晶显示标志
boolean finish_init = false; //初始化完成标志
byte satnum=0;
//连接上的卫星个数
float flat, flon, spd, alt, oflat, oflon;
//GPS信息,经纬度、速度、高度、上一次的经纬度
unsigned long age; //GPS信息
fix age
int year; //GPS信息 年
byte
month, day, hour, minute, second, hundredths; //GPS信息 时间信息
char
crs[4]; //GPS信息 行驶方向
char sz[10];
//文本信息
byte cnt=0; //循环计数器
static void
gpsdump(TinyGPS &gps);
static bool feedgps();
static void
print_date(TinyGPS &gps);
static void print_satnum(TinyGPS
&gps);
static void print_pos(TinyGPS &gps);
static void
print_alt(TinyGPS &gps);
static void print_speed(TinyGPS
&gps);
static void print_course(TinyGPS &gps);
static String
float2str(float val, byte len);
//AVR定时器,每秒触发
ISR(TIMER1_OVF_vect)
{
TCNT1=0x0BDC; // set initial value to remove time error (16bit counter
register)
if (finish_init) refresh = true;
//在完成初始化后,将刷新显示标志设为true
}
void setup()
{
finish_init =
false;
//设置并激活AVR计时器
TIMSK1=0x01; // 启用全局计时器中断
TCCR1A = 0x00; //normal
operation page 148 (mode0);
TCNT1=0x0BDC; //set initial value to remove time
error (16bit counter register)
TCCR1B = 0x04; //启动计时器
pinMode(10,
OUTPUT);
oflat = 0;
oflon = 0;
logname[0]=' ';
Serial.begin(9600);
//GPS模块默认输出9600bps的NMEA信号
u8g.setColorIndex(1); //
设置LCD显示模式,黑白
u8g.setFont(u8g_font_04b_03br);
//字体
//TF卡的片选端口是10
if (!SD.begin(10)) {
sderror =
true;
}
//初始化完成
finish_init = true;
}
void
loop()
{
//读取并分析GPS数据
feedgps();
//刷新显示
if
(refresh)
{
cnt %=10;
writelog = true;
u8g.firstPage();
do{
gpsdump(gps);
u8g.setPrintPos(70,48);
u8g.print( cnt);
} while (
u8g.nextPage() );
//每5秒且GPS信号正常时将数据记录到TF卡
if (cnt %
5 == 0 && writelog)
{
logEvent();
}
//刷新完毕,更新秒计数器
refresh = false;
cnt++;
}
}
static
void gpsdump(TinyGPS
&gps)
{
print_satnum(gps);
print_date(gps);
print_pos(gps);
print_speed(gps);
print_alt(gps);
print_course(gps);
}
//更新并显示卫星个数
static
void print_satnum(TinyGPS &gps)
{
satnum = gps.satellites();
if (
satnum != TinyGPS::GPS_INVALID_SATELLITES){
u8g.setPrintPos( 46, 6);
u8g.print(satnum);
writelog &= true;
}
else {
u8g.drawStr( 10, 15, F("gTracking System"));
u8g.drawStr( 22, 23,
F("build 2506"));
u8g.drawStr( 0, 34, (cnt % 2) ? F("Searching...") : F("
"));
//u8g.drawStr( 7, 48, F("wells.osall.com"));
writelog
= false;
}
feedgps();
}
//更新并显示GPS经纬度信息
static void
print_pos(TinyGPS &gps)
{
gps.f_get_position(&flat, &flon,
&age);
if (flat != TinyGPS::GPS_INVALID_F_ANGLE && flon
!= TinyGPS::GPS_INVALID_F_ANGLE) {
u8g.setPrintPos(0,40);
u8g.print(float2str(flon,8));
u8g.print(F(" : "));
u8g.print(float2str(flat,8));
writelog &= true;
}
else
writelog = false;
feedgps();
}
//更新并显示GPS高度信息
static void
print_alt(TinyGPS &gps)
{
alt = gps.f_altitude();
if (alt !=
TinyGPS::GPS_INVALID_F_ALTITUDE){
u8g.setPrintPos(0,48);
u8g.print(F("Alt: "));
u8g.print(float2str(alt,5));
writelog &=
true;
}
else
{
writelog =
false;
}
feedgps();
}
//更新并显示行驶方向
static void
print_course(TinyGPS &gps)
{
if (gps.f_course() ==
TinyGPS::GPS_INVALID_F_ANGLE)
writelog = false;
else
{
//从PROGMEM中读取数组中的字符串
strcpy_P(crs,(char*)pgm_read_word(&(dir_table[gps.cardinal(gps.f_course())])));
u8g.setPrintPos(60,6);
u8g.print(crs);
}
feedgps();
}
//更新并显示GPS时间
static void
print_date(TinyGPS &gps)
{
gps.crack_datetime(&year, &month,
&day, &hour, &minute, &second, &hundredths, &age);
if
(age != TinyGPS::GPS_INVALID_AGE && month>0 &&
day>0)
{
u8g.setPrintPos( 0, 6);
sprintf(sz, "%02d",((hour+8)
% 24)); //显示北京时间 GMT+8
u8g.print(sz);
u8g.setPrintPos( 11, 6);
u8g.print(second % 2 ? F(":") : F(" "));
u8g.setPrintPos(15,6);
sprintf(sz, "%02d",minute);
u8g.print(sz);
writelog &=
true;
}
else
writelog =
false;
feedgps();
}
//更新并显示时速
static void print_speed(TinyGPS
&gps)
{
spd = gps.f_speed_kmph();
if (spd !=
TinyGPS::GPS_INVALID_F_SPEED)
{
if(spd<0.5) spd=0.0;
//屏蔽0时速时的误差显示
u8g.drawStr(0,14, F("SPEED"));
u8g.setPrintPos(0,32);
u8g.setFont(u8g_font_fub14n); //使用大字体
u8g.print( float2str(spd,5));
u8g.setFont(u8g_font_04b_03br);
u8g.print(F(" km/h"));
writelog &= true;
}
else
writelog
= false;
feedgps();
}
//读取并解码GPS信息
static bool
feedgps()
{
while (Serial.available())
{
if
(gps.encode(Serial.read()))
return true;
}
return
false;
}
//将浮点数转化为字符串(整数部分<1000)
static String float2str(float val,
byte len)
{
String str = "";
char tmp[4];
byte pos = 0;
int
p1;
bool minus=false;
//取绝对值
if (val<0)
{
minus=true;
len--;
val = abs(val);
}
p1=(int)val; //取整数部分
val=val-p1;
//得到小数部分
itoa(p1,tmp,10);
//整数部分转化为字符串
str.concat(tmp);
//获得小数点位置
if (p1 == 0) {
pos =
1;
}
else {
for (pos=0;pos<len && p1>0;pos++)
p1=p1/10;
}
//小数点
if (pos<len && val>0){
pos++;
str.concat('.');
}
//小数部分加入字符串
for (;pos<len&&
val>0;pos++)
{
str.concat((char)('0'+ (byte)(val*10)));
val=
val * 10 - ((byte)(val*10));
}
if (minus) str = "-" + str;
return
str;
}
//记录数据到TF卡
void logEvent()
{
if (logname[0]==' ') {
//获取文件名
sprintf(logname, "%04d%02d%02d.trc", year, month, day, hour,
minute, second);
myFile=SD.open(logname, FILE_WRITE);
if (!myFile)
{
sderror = true;
}
else {
myFile.println(F("#gTracking#b2506#")); //输出数据的版本信息
myFile.close();
delay(10);
}
}
//当位置和上一次(5秒前)相比发生一定变化量时才记录数据(节省数据文件的空间)
if (writelog &&
logname[0]!=' ' && (abs(flat-oflat) > 0.0001 || abs(flon - oflon)
> 0.0001))
{
myFile=SD.open(logname, FILE_WRITE);
if (!myFile)
{
sderror = true;
}
else
{
oflat = flat;
oflon = flon;
sprintf(sz, "%04d-%02d-%02d", year, month, day);
myFile.print(sz);
myFile.print(F(","));
sprintf(sz,
"%02d:%02d:%02d,", hour, minute, second);
myFile.print(sz);
sprintf(sz,"%02d,",satnum);
myFile.print(sz);
myFile.print(float2str(flat,20));
myFile.print(",");
myFile.print(float2str(flon,20));
myFile.print(",");
myFile.print(float2str(alt,10));
myFile.print(",");
myFile.print(float2str(spd,10));
myFile.print(",");
myFile.print(crs);
myFile.println(",");
delay(20);
myFile.flush();
delay(50);
myFile.close();
}
}
}
我把有错误的代码行暂时注释掉后,烧写进我的UNO,发现无法正常运行(arduino uno似乎会死机)!
有哪位帮忙测试一下!
无法编译通过的代码是这个:
//从PROGMEM中读取数组中的字符串
strcpy_P(crs,(char*)pgm_read_word(&(dir_table[gps.cardinal(gps.f_course())])));
#include <SD.h>
#include
<TinyGPS.h>
#include
<avr/pgmspace.h>
//使用PROGMEM存放GPS方向数组,节省SRAM
prog_char d_0[] PROGMEM
= "N";
prog_char d_1[] PROGMEM = "NNE";
prog_char d_2[] PROGMEM =
"NE";
prog_char d_3[] PROGMEM = "ENE";
prog_char d_4[] PROGMEM =
"E";
prog_char d_5[] PROGMEM = "ESE";
prog_char d_6[] PROGMEM =
"SE";
prog_char d_7[] PROGMEM = "SSE";
prog_char d_8[] PROGMEM =
"S";
prog_char d_9[] PROGMEM = "SSW";
prog_char d_10[] PROGMEM =
"SW";
prog_char d_11[] PROGMEM = "WSW";
prog_char d_12[] PROGMEM =
"W";
prog_char d_13[] PROGMEM = "WNW";
prog_char d_14[] PROGMEM =
"NW";
prog_char d_15[] PROGMEM = "NNW";
PROGMEM const char *dir_table[]
=
{
d_0,
d_1,
d_2,
d_3,
d_4,
d_5,
d_6,
d_7,
d_8,
d_9,
d_10,
d_11,
d_12,
d_13,
d_14,
d_15
};
TinyGPS gps;
//U8GLIB_PCD8544 u8g(3,
4, 99, 5, 6); // SPI Com: SCK = 3, MOSI = 4, CS = 永远接地, A0 = 5, Reset =
6
U8GLIB_ST7920_128X64_4X u8g(3, 9, 8); // 声明液晶屏 8-D/I 9-R/W 3-E
File
myFile;
boolean sderror = false; //TF卡状态
char logname[13];
//记录文件名
boolean writelog = true;
//是否要记录当前数据到TF卡标志
boolean refresh = false;
//是否要更新液晶显示标志
boolean finish_init = false; //初始化完成标志
byte satnum=0;
//连接上的卫星个数
float flat, flon, spd, alt, oflat, oflon;
//GPS信息,经纬度、速度、高度、上一次的经纬度
unsigned long age; //GPS信息
fix age
int year; //GPS信息 年
byte
month, day, hour, minute, second, hundredths; //GPS信息 时间信息
char
crs[4]; //GPS信息 行驶方向
char sz[10];
//文本信息
byte cnt=0; //循环计数器
static void
gpsdump(TinyGPS &gps);
static bool feedgps();
static void
print_date(TinyGPS &gps);
static void print_satnum(TinyGPS
&gps);
static void print_pos(TinyGPS &gps);
static void
print_alt(TinyGPS &gps);
static void print_speed(TinyGPS
&gps);
static void print_course(TinyGPS &gps);
static String
float2str(float val, byte len);
//AVR定时器,每秒触发
ISR(TIMER1_OVF_vect)
{
TCNT1=0x0BDC; // set initial value to remove time error (16bit counter
register)
if (finish_init) refresh = true;
//在完成初始化后,将刷新显示标志设为true
}
void setup()
{
finish_init =
false;
//设置并激活AVR计时器
TIMSK1=0x01; // 启用全局计时器中断
TCCR1A = 0x00; //normal
operation page 148 (mode0);
TCNT1=0x0BDC; //set initial value to remove time
error (16bit counter register)
TCCR1B = 0x04; //启动计时器
pinMode(10,
OUTPUT);
oflat = 0;
oflon = 0;
logname[0]=' ';
Serial.begin(9600);
//GPS模块默认输出9600bps的NMEA信号
u8g.setColorIndex(1); //
设置LCD显示模式,黑白
u8g.setFont(u8g_font_04b_03br);
//字体
//TF卡的片选端口是10
if (!SD.begin(10)) {
sderror =
true;
}
//初始化完成
finish_init = true;
}
void
loop()
{
//读取并分析GPS数据
feedgps();
//刷新显示
if
(refresh)
{
cnt %=10;
writelog = true;
u8g.firstPage();
do{
gpsdump(gps);
u8g.setPrintPos(70,48);
u8g.print( cnt);
} while (
u8g.nextPage() );
//每5秒且GPS信号正常时将数据记录到TF卡
if (cnt %
5 == 0 && writelog)
{
logEvent();
}
//刷新完毕,更新秒计数器
refresh = false;
cnt++;
}
}
static
void gpsdump(TinyGPS
&gps)
{
print_satnum(gps);
print_date(gps);
print_pos(gps);
print_speed(gps);
print_alt(gps);
print_course(gps);
}
//更新并显示卫星个数
static
void print_satnum(TinyGPS &gps)
{
satnum = gps.satellites();
if (
satnum != TinyGPS::GPS_INVALID_SATELLITES){
u8g.setPrintPos( 46, 6);
u8g.print(satnum);
writelog &= true;
}
else {
u8g.drawStr( 10, 15, F("gTracking System"));
u8g.drawStr( 22, 23,
F("build 2506"));
u8g.drawStr( 0, 34, (cnt % 2) ? F("Searching...") : F("
"));
//u8g.drawStr( 7, 48, F("wells.osall.com"));
writelog
= false;
}
feedgps();
}
//更新并显示GPS经纬度信息
static void
print_pos(TinyGPS &gps)
{
gps.f_get_position(&flat, &flon,
&age);
if (flat != TinyGPS::GPS_INVALID_F_ANGLE && flon
!= TinyGPS::GPS_INVALID_F_ANGLE) {
u8g.setPrintPos(0,40);
u8g.print(float2str(flon,8));
u8g.print(F(" : "));
u8g.print(float2str(flat,8));
writelog &= true;
}
else
writelog = false;
feedgps();
}
//更新并显示GPS高度信息
static void
print_alt(TinyGPS &gps)
{
alt = gps.f_altitude();
if (alt !=
TinyGPS::GPS_INVALID_F_ALTITUDE){
u8g.setPrintPos(0,48);
u8g.print(F("Alt: "));
u8g.print(float2str(alt,5));
writelog &=
true;
}
else
{
writelog =
false;
}
feedgps();
}
//更新并显示行驶方向
static void
print_course(TinyGPS &gps)
{
if (gps.f_course() ==
TinyGPS::GPS_INVALID_F_ANGLE)
writelog = false;
else
{
//从PROGMEM中读取数组中的字符串
strcpy_P(crs,(char*)pgm_read_word(&(dir_table[gps.cardinal(gps.f_course())])));
u8g.setPrintPos(60,6);
u8g.print(crs);
}
feedgps();
}
//更新并显示GPS时间
static void
print_date(TinyGPS &gps)
{
gps.crack_datetime(&year, &month,
&day, &hour, &minute, &second, &hundredths, &age);
if
(age != TinyGPS::GPS_INVALID_AGE && month>0 &&
day>0)
{
u8g.setPrintPos( 0, 6);
sprintf(sz, "%02d",((hour+8)
% 24)); //显示北京时间 GMT+8
u8g.print(sz);
u8g.setPrintPos( 11, 6);
u8g.print(second % 2 ? F(":") : F(" "));
u8g.setPrintPos(15,6);
sprintf(sz, "%02d",minute);
u8g.print(sz);
writelog &=
true;
}
else
writelog =
false;
feedgps();
}
//更新并显示时速
static void print_speed(TinyGPS
&gps)
{
spd = gps.f_speed_kmph();
if (spd !=
TinyGPS::GPS_INVALID_F_SPEED)
{
if(spd<0.5) spd=0.0;
//屏蔽0时速时的误差显示
u8g.drawStr(0,14, F("SPEED"));
u8g.setPrintPos(0,32);
u8g.setFont(u8g_font_fub14n); //使用大字体
u8g.print( float2str(spd,5));
u8g.setFont(u8g_font_04b_03br);
u8g.print(F(" km/h"));
writelog &= true;
}
else
writelog
= false;
feedgps();
}
//读取并解码GPS信息
static bool
feedgps()
{
while (Serial.available())
{
if
(gps.encode(Serial.read()))
return true;
}
return
false;
}
//将浮点数转化为字符串(整数部分<1000)
static String float2str(float val,
byte len)
{
String str = "";
char tmp[4];
byte pos = 0;
int
p1;
bool minus=false;
//取绝对值
if (val<0)
{
minus=true;
len--;
val = abs(val);
}
p1=(int)val; //取整数部分
val=val-p1;
//得到小数部分
itoa(p1,tmp,10);
//整数部分转化为字符串
str.concat(tmp);
//获得小数点位置
if (p1 == 0) {
pos =
1;
}
else {
for (pos=0;pos<len && p1>0;pos++)
p1=p1/10;
}
//小数点
if (pos<len && val>0){
pos++;
str.concat('.');
}
//小数部分加入字符串
for (;pos<len&&
val>0;pos++)
{
str.concat((char)('0'+ (byte)(val*10)));
val=
val * 10 - ((byte)(val*10));
}
if (minus) str = "-" + str;
return
str;
}
//记录数据到TF卡
void logEvent()
{
if (logname[0]==' ') {
//获取文件名
sprintf(logname, "%04d%02d%02d.trc", year, month, day, hour,
minute, second);
myFile=SD.open(logname, FILE_WRITE);
if (!myFile)
{
sderror = true;
}
else {
myFile.println(F("#gTracking#b2506#")); //输出数据的版本信息
myFile.close();
delay(10);
}
}
//当位置和上一次(5秒前)相比发生一定变化量时才记录数据(节省数据文件的空间)
if (writelog &&
logname[0]!=' ' && (abs(flat-oflat) > 0.0001 || abs(flon - oflon)
> 0.0001))
{
myFile=SD.open(logname, FILE_WRITE);
if (!myFile)
{
sderror = true;
}
else
{
oflat = flat;
oflon = flon;
sprintf(sz, "%04d-%02d-%02d", year, month, day);
myFile.print(sz);
myFile.print(F(","));
sprintf(sz,
"%02d:%02d:%02d,", hour, minute, second);
myFile.print(sz);
sprintf(sz,"%02d,",satnum);
myFile.print(sz);
myFile.print(float2str(flat,20));
myFile.print(",");
myFile.print(float2str(flon,20));
myFile.print(",");
myFile.print(float2str(alt,10));
myFile.print(",");
myFile.print(float2str(spd,10));
myFile.print(",");
myFile.print(crs);
myFile.println(",");
delay(20);
myFile.flush();
delay(50);
myFile.close();
}
}
}
我把有错误的代码行暂时注释掉后,烧写进我的UNO,发现无法正常运行(arduino uno似乎会死机)!
有哪位帮忙测试一下!
无法编译通过的代码是这个:
//从PROGMEM中读取数组中的字符串
strcpy_P(crs,(char*)pgm_read_word(&(dir_table[gps.cardinal(gps.f_course())])));