由于一个项目中需要采集GPS坐标信息,就想利用已有材料做一个简易的坐标采集装置。手头又正好有太阳能电池板,就索性加上了太阳能充电的功能。
【选型】
由于Arduino比较简单,所以就选择Arduino平台作为主控。20mA/5v。
需要显示的信息也比较少,主要是GPS坐标和时间、航速信息。所以用LCD1602即可,为了编码方便,用的是转成串口输入的LCD模块。20~80mA/5v。
GPS模块先找的最普遍的ublox m6n,定位精度水平5m以内吧,不是太高,所以后续换成了M8N,输出解析上略有区别(下文中均是按照ublox m6n进行解析),但是都是Uart接口,160mA/5v。
TF卡模块,用来存储坐标信息,20mA/5v。
算了下,上面的所有装置电流200mA/5v,户外连续工作十小时计算,需要5V,2000mAh的电能一节3.7V,2600mAh的锂电池差不多满足需求。
这里只是做验证,就把闲置3.6V,380mAh的Li-Ge电池拿来用了,后续只需要调一下电压就可以换别的锂电池了。
太阳能模块是200mA/1.5v的模块,其实阳光好直晒的时候电压更高(测量太阳能电池板输出必须带负载测量,不能空载),带负载能力更强。采用两块串联,提高整体输出电压。
因为太阳能模块输出随光照情况变化大,所以需要能自动升降压的稳压模块,LM2596S模块可以满足,效率在90%以上,于是采用。
另外增加两个按键,主要用于LCD显示内容切换以及记录坐标按钮。
【列下材料】:
太阳能电池板 3v/200mA *2
充电电池 3.7V 380mv
LM2596s可调升降压稳压模块
Arduino
Ublox M6N模块(GPS信号接收),3.3V/5V,70mA,uart接口。
LCD1602液晶屏,5V,背光开启20mA,无背光时uA级别耗电可忽略,uart接口。
TF卡模块,SPI接口,5V/0.2~200mA,典型工作80mA。
5V升压稳压模块
其他电子耗材
由于不是专业电子出生,电路方面知识欠缺,在设计充放电功能时纠结了很久,主要是电压转换方式的选取,太阳能电池板的输出随光照条件变化,而且不能逆流,所以在太阳能电池无光不工作的时候保证电池不能反向输出至太阳能板,于是在电池的充电端加了整流二极管,副作用是压降0.7v(其实LM2596S模块也带有防逆流功能)。
【电路设计】:
略。。。比较简单就不画电路图了,说下模块连线。
1602LCD为I2C总线:
1602模块的SDA连接arduino的A4
SCL连接arduino的A5
ublox模块为uart总线,因为我们不需要控制ublox模块,只需从ublox模块读取信息,因而只用连接ublox的Tx:
ublox的Tx连接到arduino的Rx(引脚D0)
TF卡模块为SPI总线:
TF卡模块的SS连接Arduino的引脚D10
MOSI------>D11
MISO------>D12
SCLK------->D13
另外用到的两个按键:
记录键----->D8
翻页键----->D9
【程序】:
【1602LCD】:
这里引用了1602LCD的库LiquidCrystal_I2C的库,但是网上的很多库不能直接用,可能是版本问题,需要多试试,不行可以换IDE试试(本程序1.6.6通过)。从库名可以看出,1602是用I2C总线,所以接线就是A4、A5。
初始化LCD:
#include <Wire.h> #include "LiquidCrystal_I2C.h" LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display const int chipSelect = 4; //设定CS接口
注意因为是I2C接口,所以要引用Wire.h文件。输出欢迎信息:
lcd.init(); // initialize the lcd lcd.backlight(); lcd.setCursor(0,0); lcd.print("Welcome to GPS"); lcd.setCursor(0,1); lcd.print("Recorder --atp"); delay(1000);
后续使用输出其他信息也是同样方法,lcd.setCursor(x,y)调整光标
然后lcd.print(str)从指定光标起输出内容。
【sd】:
Arduino官方IDE自带SD卡读写函数库,引用头文件后可以直接调用,初始化:
#include <SD.h> File dataFile = SD.open("GPScord.txt", FILE_WRITE);
剩下的读写和其他IO方式类似,print函数搞定。
if (dataFile) { dataFile.print(latitude); …… }
【GPS】:
GPS模块数据解析需要对照模块手册,主要涉及字符串操作,宏定义如下:
#define GPRMC_TERM "$GPRMC,"
该宏定义要解析的指令的指令头,选择该指令是因为这条指令包含定位和时间信息。
初始化:
Serial.begin(9600);
UBLOX模块使用uart总线,默认波特率9600,因而直接串口初始化即可。
while (Serial.available()) //串口获取到数据开始解析 { char c = Serial.read(); //读取一个字节获取的数据 switch(c) //判断该字节的值 { case '$': //若是$,则说明是一帧数据的开始 …… } }
主循环不断检测按键状态与GPS模块的输入,并将GPS模块获取到的信息输出到LCD,当检测到按键按下,切换显示状态或者将GPS信息记录到TF卡上。
GPS模块输出包括很多数据,如$GPGGA( GPS定位信息, Global Positioning System Fix Data),$GPGSA(当前卫星信息),$GPGSV(可见卫星数, GPS Satellites in View),$GPRMC(推荐定位信息, Recommended Minimum Specific GPS/Transit Data),$GPVTG(地面速度信息, Track Made Good and Ground Speed),$GPGLL(定位地理信息, Geographic Position),$GPZDA(当前时间信息)等等,均是按照NMEA-0813协议的命令帧格式。而我们取用的数据就是GPRMC的推荐定位。
$GPRMC语句的基本格式如下:
$GPRMC,(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)*hh(CR)(LF)
(1) UTC时间, hhmmss(时分秒)
(2) 定位状态, A=有效定位, V=无效定位
(3) 纬度ddmm.mmmmm(度分)
(4) 纬度半球N(北半球)或S(南半球)
(5) 经度dddmm.mmmmm(度分)
(6) 经度半球E(东经)或W(西经)
(7) 地面速率( 000.0~999.9节)
(8) 地面航向( 000.0~359.9度,以真北方为参考基准)
(9) UTC日期, ddmmyy(日月年)
(10)磁偏角( 000.0~180.0度,前导位数不足则补0)
(11) 磁偏角方向, E(东)或W(西)
(12) 模式指示( A=自主定位, D=差分, E=估算, N=数据无效)
举例如下:
$GPRMC,023543.00,A,2308.28715,N,11322.09875,E,0.195,,240213,,,A*78
以获取其中纬度信息为例:
String parseGprmcLat(String s) { int pLoc = 0; //paramater location pointer int lEndLoc = 0; //lat parameter end location int dEndLoc = 0; //direction parameter end location String lat; if(s.substring(0,4) == "GPRM") { for(int i = 0; i < 5; i++) { if(i < 3) { pLoc = s.indexOf(',', pLoc+1); } if(i == 3) { lEndLoc = s.indexOf(',', pLoc+1); lat = s.substring(pLoc+1, lEndLoc); } else { dEndLoc = s.indexOf(',', lEndLoc+1); lat = lat + "-" + s.substring(lEndLoc+1, dEndLoc); } } return lat; } }
因为都是字符串截取操作,所以其余字段获取方法这里不再重复。
如下成品效果图:
图1 成品图
图2 经纬度显示
图3 速度、时间显示
代码见【http://download.youkuaiyun.com/download/atp1992/10209010】
原文链接【http://www.straka.cn/blog/solar_gps_recorder/】