2013年12月2日 星期一

[Arduino]GPS測速器


身為一個奉公守法的飆車族,

能夠知道自己真正的車速是一件很重要的事情,

而你永遠不會知道自己的儀表板的快樂程度,

所以就用GPS測定自己的車速了。


在露天上面可以找到許多UART界面的GPS模組,

上電之後,接收器就會自動連上衛星,並且透過Serial Port不斷的傳回數據,

這些數據為NMEA所制定的訊息格式,

因此直接使用TinyGPS++這個Arduino的函式庫來解讀GPS接收器所傳回來的訊息。


GPS除了可以讀回車速,也可傳回許多其他的相關資訊,

而這邊我總共抓取了車速、UTC時間、航向、HDOP(水平2D坐標精度因子) 以及所連接的衛星數量這五個參數。


為了易於判讀資訊以及減小體積,這邊只用一個四位數的七段顯示器來顯示資訊,

搭配Atmega8l上的兩個外部中斷,來調整顯示模式以及顯示亮度。


目前Atmega8l幾乎是市面上最便宜的Atmega系列晶片,甚至比有些attiny還來的便宜,

但也因為8k的flash,所以必須想盡辦法降低程式碼的體積,

因此使用了AVR-GCC直接對IO PORT存取的語法來點亮七段顯示器,

這邊把原本用來接外部振盪器的PB6,PB7也作為GPIO使用。





也為了搭配車上的12V電源,或者9V電池,所以另外規劃了一個5伏特的穩壓。







正面左邊為GPS模組,中間是共陽四位七段顯示器,


右邊兩個中斷的按鈕、2.1DC座以及開關。



背面分別為穩壓IC、Atmega8l以及GPS的陶瓷天線。

為了減小體積,Atmega8l直接焊死到板子上,

所以另外拉出了ICSP腳位方便之後修改程式碼。



顯示時間八點整,靠近七段顯示器的按鈕為中斷1(PD3,arduino pin3),調整亮度用。

另一個按鈕則為中斷0(PD2, arduino pin2),用來改變顯示模式。


Ublox neo 6m GPS module

程式碼:

#include <TinyGPS++.h>
byte displayMode=1; //(mode 1~mode 5)
int displayNum;
byte pointDigit;
byte brightness=205;//the lower, the more bright
byte numPattern[10]={
B11000000,//0
B11111001,//1
B10100100,//2
B10110000,//3
B10011001,//4
B10010010,//5
B10000010,//6
B11011000,//7
B10000000,//8
B10010000,//9
};
TinyGPSPlus gps;
void setup() {
DDRB = B11111111;
DDRC = B1111;
pinMode(2,INPUT_PULLUP);
pinMode(3,INPUT_PULLUP);
attachInterrupt(1, brightnessISR, RISING);
attachInterrupt(0, nextModeISR, RISING);
Serial.begin(9600);//GPS receiver's baud rate
}
void loop() {
lightUp(displayNum,pointDigit);
}
void lightUp(int num, byte point){
PORTC=B0001;//LSB
if(point==0)PORTB=numPattern[num%10]&127;
else PORTB=numPattern[num%10];
lightPeroid();
PORTC=B0010;
if(point==1)PORTB=numPattern[(num/10)%10]&127;
else PORTB=numPattern[(num/10)%10];
lightPeroid();
PORTC=B0100;
if(point==2)PORTB=numPattern[(num/100)%10]&127;
else PORTB=numPattern[(num/100)%10];
lightPeroid();
PORTC=B1000;//MSB
if(point==3)PORTB=numPattern[(num/1000)%10]&127;
else PORTB=numPattern[(num/1000)%10];
lightPeroid();
}
void lightPeroid(){
int t=1000;//digit period:1000us
delayMicroseconds(t-brightness*4);
PORTC=B0000;
PORTB=B11111111;
delayMicroseconds(brightness*4);
}
void serialEvent(){
double kmhr;
while(Serial.available()){
if(gps.encode(Serial.read())){
switch(displayMode){
case 1://UTC time(+8 in Taiwan)
displayNum=((gps.time.hour()+8)%24)*100+gps.time.minute();
pointDigit=2;
break;
case 2: //speed(kilometer per hour)
kmhr=gps.speed.kmph();
displayNum=(byte)(kmhr*10);
pointDigit=1;
break;
case 3: //heading course degree (0~360 degree)
displayNum=gps.course.deg();
pointDigit=0;
break;
case 4://GPS accuracy(HDOP:0.00~99.99)
displayNum=gps.hdop.value();
pointDigit=2;
break;
case 5://number of connected satellite(0~12)
displayNum=gps.satellites.value();
pointDigit=0;
break;
}
}
}
}
void nextModeISR(){
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 150){
displayMode++;
if(displayMode==6)displayMode=1;
}
last_interrupt_time = interrupt_time;
}
void brightnessISR(){
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 300) {
brightness-=25;
if(brightness<=60)brightness=205;
}
last_interrupt_time = interrupt_time;
}
view raw GPS_Meter hosted with ❤ by GitHub



compile後的大小

測試影片:

--------------------


GPS模組-----------------690
Atmega8l---------------39 共陽四位七段顯示器--50   
按鈕
開關
穩壓IC7805
電容104
2.1mm DC jack
洞洞板
接線

-----------------
TinyGPS++
NMEA Reference Manual 
u - blox 6 GPS Modules
Atmega8
Arduino IDE 1.0.1 and ATmega8 running at 8MHz with Optiboot