UKHAS Wiki

UK High Altitude Society

User Tools

Site Tools


code:interrupt_driven_ubx

under construction…

demo code

#include <stdlib.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <avr/io.h>
 
#include "ubx.h" 
 
volatile ubx_gps_type Gps;
 
int uart_putchar(char c, FILE *stream)
{
	if (c == '\n')
		uart_putchar('\r', stream);
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = c;
	return 0;
}
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar,NULL,_FDEV_SETUP_WRITE);
 
 
void main(void)
{
	UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);//mega xx8 registers - enable tx and rx, with interrupts on RX only
	UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);	//setup 8N1
	UBRR0L = BAUDDIV;
	UBRR0H = BAUDDIV>>8;			//end of UART setup
	DDRD|=0x20;				//use portd 5 as an output for led
	stdout = &mystdout;
	sei();					//enable interrupts
	TOGGLE_PIN;
	for(;;)
	{
		if(Gps.packetflag==REQUIRED_DATA)
		{
			printf("%li,%li,%li,%2X,%2X\n",Gps.latitude,Gps.longitude,Gps.altitude,Gps.status,Gps.nosats);
			Gps.packetflag=0;	//unlock the data
		}
	}
}
 
ISR(USART_RX_vect)				//UART interrupt on mega xx8 series
{
	static u08 state,class,id,checksum_1,checksum_2,counter;
	static u16 lenght;
	static ubx_gps_type gps;
	u08 c = UDR0;
	switch(state)
	{
		case 0:				//start be waiting for the first sync byte
			if(c==SYNC_1)
				state=1;
			else
				state=0;
			break;
		case 1:				//followed by the second one
			if(c==SYNC_2)
				state=2;
			else
				state=0;
			break;
		case 2:				//then store the class
			class=c;
			state=3;
			break;
		case 3:				//then the id
			id=c;
			state=4;
			break;
		case 4:				//the least significant byte of the lenght 
			lenght=c;
			state=5;
			break;
		case 5:				//the most significant byte
			lenght|=c<<8;
			counter=0;
			state=6;
			break;
		case 6:				//the data follows
			if(class==NAV_CLASS)	//we have nav data
			{
				if(id==LLH_DATA)//needs macros defining in the header file for the correct data positions
				{
					if(lenght<POS_END && lenght>POS_START)
						((u08*)&gps)[POS_OFFSET-lenght]=c;
				}
				if(id==VELNED_DATA)
				{
					if(lenght<VEL_END && lenght>VEL_START)
						((u08*)&gps)[VEL_OFFSET-lenght]=c;
				}
				if(id==SOL_DATA && lenght==SOL_POS)
					gps.status=c;
				if(id==SOL_DATA && lenght==SATS_POS)
					gps.nosats=c;				
				/*if(id==SVINFO_DATA)//this appears to find the number of hardware channels avaliable
				{
					counter++;//this counts from the start of data
					if(counter==SATS_POS)
						gps.nosats=c;
				}*/
			}
			lenght--;
			if(!lenght)		//we have reached the end of the data
				state=7;
			break;
		case 7:				//check the checksum
			if(checksum_1==c)
				state=8;
			else
				state=0;
			break;
		case 8:				//second byte of the checksum
			if(checksum_2==c)
			{
				if(class==NAV_CLASS)//if the class was NAV and we have valid id
				{
					if(id==SVINFO_DATA)
						gps.packetflag|=0x08;
					if(id==SOL_DATA)
						gps.packetflag|=0x04;
					if(id==LLH_DATA)
						gps.packetflag|=0x02;
					if(id==VELNED_DATA)
						gps.packetflag|=0x01;
				}
				if(!Gps.packetflag && gps.packetflag==REQUIRED_DATA)//main has unlocked the data and we have all the required data
				{
					TOGGLE_PIN;//toggles pin D5 - flashing LED tells us gps is working				
					Gps=gps;//copy into the global variable
					gps.packetflag=0;//we now wait for more data to arrive
				}		//complete
			}
			state=0;
	}	
	if(state>2 && state<8)			//in the valid range to add to the checksum
	{
		checksum_1+=c;
		checksum_2+=checksum_1;
	}
	else if(!state)
	{
		checksum_1=0;
		checksum_2=0;
	}
}
typedef unsigned char u08;
typedef uint16_t u16;
typedef uint32_t u32;
typedef int32_t s32;
typedef struct
{
	u32 time;					//milliseconds/week
	s32 vnorth;					//cm/s
	s32 veast;
	s32 vdown;
	s32 longitude;					//degrees/10^-7
	s32 latitude;
	s32 altitude;					//height/mm
	u08 packetflag;					//packetflag lets us see when our packet has been updated
	u08 status;					//type of fix
	u08 nosats;					//number of tracked satellites
} ubx_gps_type;
#define REQUIRED_DATA 0x0F
#define LLH_DATA 0x02
#define VELNED_DATA 0x12
#define SVINFO_DATA 0x30
#define SOL_DATA 0x06
#define NAV_CLASS 0x01
#define SATS_POS 5
#define SOL_POS 42
#define POS_OFFSET 40
#define POS_START 12
#define POS_END 25
#define VEL_OFFSET 36 
#define VEL_START 20
#define VEL_END 37
#define SYNC_1 0xB5
#define SYNC_2 0x62
 
#define BAUDRATE 38400UL
#define BAUDDIV 32
//#define BAUDDIV  (u16)( ((float)F_CPU/(BAUDRATE*16UL)) -1 )//baud divider
#define TOGGLE_PIN PIND=0x20				//led on port D.5
code/interrupt_driven_ubx.txt · Last modified: 2009/05/11 20:17 by laurenceb