GPS Verisini Parçalara Ayırmak

Başlatan Cemre., 09 Nisan 2016, 16:55:26

Cemre.

Merhaba,
Rx_Buffer adındaki diziye UART'tan gelen veriyi alabiliyorum. Ancak bunu aşağıdaki fonksiyonla parçalara ayırmak istediğimde yeni diziler hep boş dönüyor. Misal Time_of_Fix dizisinin tüm elemanları "0". Nerede hata yapıyor olabilirim? Ya da önerebileceğiniz daha düzgün bir algoritma, örnek var mı?

void GPS_Converter(void)
{
			uint8_t i,j,CommaCounter;
			while(CommaCounter < 11 && i<99)
			{
				if(Rx_Buffer[i] == ',')
				{	
					CommaCounter++;
					switch(CommaCounter)
					{
						case 1 :
							j = 0;
							i++;
							while(Rx_Buffer[i] != ',')
							{	
								Time_of_Fix[j] = Rx_Buffer[i];
								j++;
								i++;
							}
							break;
						case 2 :
							j = 0;
							i++;
							while(Rx_Buffer[i] != ',')
							{	
								A_or_V[j] = Rx_Buffer[i];
								j++;
								i++;
							}
							break;
						case 3 :
							j = 0;
							i++;
							while(Rx_Buffer[i] != ',')
							{	
								Latitude[j] = Rx_Buffer[i];
								j++;
								i++;
							}
							break;
						case 4 :
							j = 0;
						i++;
							while(Rx_Buffer[i] != ',')
							{	
								North_or_South[j] = Rx_Buffer[i];
								j++;
								i++;
							}
							break;
						case 5 :
							j = 0;
						i++;
							while(Rx_Buffer[i] != ',')
							{	
								Longitude[j] = Rx_Buffer[i];
								j++;
								i++;
							}
							break;
						case 6 :
							j = 0;
							i++;
							while(Rx_Buffer[i] != ',')
							{	
								East_or_West[j] = Rx_Buffer[i];
								j++;
								i++;
							}
							break;
						case 7 :
							j = 0;
						i++;
							while(Rx_Buffer[i] != ',')
							{	
								Speed[j] = Rx_Buffer[i];
								j++;
								i++;
							}
							break;
						case 8 :
							j = 0;
						i++;
							while(Rx_Buffer[i] != ',')
							{	
								CMG[j] = Rx_Buffer[i];
								j++;
								i++;
							}
							break;
						case 9 :
							j = 0;
						i++;
							while(Rx_Buffer[i] != ',')
							{	
								Date[j] = Rx_Buffer[i];
								j++;
								i++;
							}
							break;
						case 10 :
							j = 0;
						i++;
							while(Rx_Buffer[i] != ',')
							{	
								MagVar[j] = Rx_Buffer[i];
								j++;
								i++;
							}
							break;
						case 11 :
							j = 0;
						i++;
							while(Rx_Buffer[i] != ',')
							{	
								MagVar2[j] = Rx_Buffer[i];
								j++;
								i++;
							}
							break;
					}
				}
				else if(Rx_Buffer[i] == '*')
				{
					CommaCounter++;
					Checksum[0] = Rx_Buffer[i++];
					Checksum[1] = Rx_Buffer[i++];
				}
				else i++;
			}
}



Klein

$GPRMC"  başlıklı veri için  decode örneği

/*  "$GPRMC"  başlıklı veri için  decode örneği */

/*
 $GPRMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,ddmmyy,x.x,a*hh
1    = UTC of position fix
2    = Data status (V=navigation receiver warning)
3    = Latitude of fix
4    = N or S
5    = Longitude of fix
6    = E or W
7    = Speed over ground in knots
8    = Track made good in degrees True
9    = UT date
10   = Magnetic variation degrees (Easterly var. subtracts from true course)
11   = E or W
12   = Checksum
*/

struct{
  float time;
  char status;
  float pos_ltd;
  char vert_ind;
  float pos_lgt;
  char hrz_ind;
  float speed;
  float direction;
  long date;
  float variation;
  char variation_direction;
  float altitude;
  char altitude_unit;
  float update_time;
} gps_raw_data;


void decode_gps_data(void)
{
        sscanf(gps_comm_buf , "%f,%c,%f,%c,%f,%c,%f,%f,%lu,%f,%c",
                  &gps_raw_data.time,
                  &gps_raw_data.status,
                  &gps_raw_data.pos_ltd,
                  &gps_raw_data.vert_ind,
                  &gps_raw_data.pos_lgt,
                  &gps_raw_data.hrz_ind,
                  &gps_raw_data.speed,
                  &gps_raw_data.direction,
                  &gps_raw_data.date,                  
                  &gps_raw_data.variation,
                  &gps_raw_data.variation_direction                  
                    );
}

Cemre.

sprintf(Tx_Buffer, "Time = %f", gps_raw_data.time);

yapıp UART'tan gönderdiğimde Time = 0.0 geliyor @Klein hocam. Ama debug'da baktığımda verdiğiniz fonksiyona girdiğim gps_comm_buf boş değil. Neden böyle birşey oluyor olabilir?

Klein

Buffer boş değil ama gerçekten beklediğimiz veri mi?
Buffer içeriğini  paylaşırsan belki sonuca ulaşabiliriz.
Ayrıca verdiğim decode fonksiyonunun çalışması için  buffer başlangıcının Time bilgisinin başladığı adres olması gerek.
Eğer buffer adresi olarak array  başını vereceksen , scanf() fonksiyonuna verdiğimiz format metnini ona göre düzenlemen gerek. 

Cemre.

Alıntı yapılan: Klein - 09 Nisan 2016, 18:03:44
Buffer boş değil ama gerçekten beklediğimiz veri mi?
Buffer içeriğini  paylaşırsan belki sonuca ulaşabiliriz.
Ayrıca verdiğim decode fonksiyonunun çalışması için  buffer başlangıcının Time bilgisinin başladığı adres olması gerek.
Eğer buffer adresi olarak array  başını vereceksen , scanf() fonksiyonuna verdiğimiz format metnini ona göre düzenlemen gerek. 


Hocam dediğiniz gibi beklediğimiz veri gelmiyor, benim verim &GPRMC ile başlıyor ve sorun da bundan kaynaklanıyor. Struct'a birde gps_raw_data.mode gibi birşey ekleyip düzeltince olacak sanıyorum. Hemen deniyorum.

Klein

Struct'a bir şey eklemene gerek yok.
Buffer adresi olarak  "$GPRMC,"  sonrasını verirseniz sorun kalmaz.
sscanf(buffer+7, ......) şeklinde
veya
sscanf(&buffer[7], .....)

Cemre.

#6
@Klein hocam, çok pratik bir yöntem önerdiniz ancak bu yöntem sadece gelen veri mükemmel olduğunda işe yarıyor. Çoğu zaman GPS sensöründen gelen veride boş kısımlar oluyor ve bu tür durumlarda kod sadece ilk veri olan saati okuyabiliyor. Diğer kısımlar yine 0 dönüyor. Buna bir çözüm var mı?

Klein

Eğer GPRMC mesajında boşluklar oluşuyorsa, zaten GPS verisini alamamışsın demektir. Bu durumda bağlantı yok hatası vereceksiniz. 

Cemre.

#8
@Klein hocam bana Tarih Zaman Enlem Boylam verileri yeterli, misal Speed ya da Magnetig Variation verileri benim için lüzumsuz ve bazen bu veriler gelmediğinde de bana lazım olanlar gelebiliyor. uBlox Neo6m kullanıyorum GPS alıcısı olarak. Bu durumlarda enlem boylam gibi bilgileri de geçersiz saymak mı gerekir?

Klein

#9
Enlem boylam verileri geliyorsa, diğer alanların da geliyor olması lazım. Enlem boylam bilgileri alınamadığında diğerleri de hesaplanamadığı için boş gelir.

Eğer enlem ve boylam geldiği halde  boş gelen alanlar oluyorsa ( zannetmiyorum)
o alanların değişkenini yeterli uzunlukta array yap. format metnine o alanlar için "%s"  koy. 

Cemre.




@Klein hocam, birinci görselde eksiksiz bir NMEA cümlesi var, ikincide ise sadece Status kısmını sildim, bu durumda Enlem ve Boylam değişkenlerim de olması gereken değeri göstermiyor. Şuan strtok fonksiyonunu kullanarak yapmaya çalışıyorum ve yine aynı sorunu yaşıyorum. GPS modülü boşluklara rağmen Checksum bilgisi bulunduran cümleler gönderiyor normal zamanda. Ben her durumda hatasız bir şekilde gelen veriyi almak ve daha sonra kullanıp kullanmayacağıma karar vermek istiyorum. Bu tarz string fonksiyonlarıyla bu söylediğim mümkün mü acaba?

Klein

#11
Aradan bir şey silersen tabi ki doğru göstermez. Ama enlem boylam bilgisi olduğu sürece de eksik bilgi gelmez.
ama diyorsan ki  enlem boylam gelmese de  diğer kısımlar bana lazım, o zaman str fonksiyonları ile yola devam.

diziyi baştan sona tara.  virgül gördüğün yerin adresini bir arraya kaydet.  sonra yine sscanf, atoi, atof gibi fonksiyonlar  ile bu adreslerdeki veriyi ayrı ayrı al. .

Cemre.

#12
Alıntı yapılan: Klein - 09 Nisan 2016, 22:34:02
Aradan bir şey silersen tabi ki doğru göstermez. Ama enlem boylam bilgisi olduğu sürece de eksik bilgi gelmez.
ama diyorsan ki  enlem boylam gelmese de  diğer kısımlar bana lazım, o zaman str fonksiyonları ile yola devam.

diziyi baştan sona tara.  virgül gördüğün yerin adresini bir arraya kaydet.  sonra yine sscanf, atoi, atof gibi fonksiyonlar  ile bu adreslerdeki veriyi ayrı ayrı al. .

char *p_start, *p_end;
char i;

	p_start = Rx_Buffer;
	while(1) {
 		p_end = strchr(p_start, ',');
 		if (p_end) {
  			strncpy(parts[i], p_start, p_end-p_start);
  			//parts[i][p_end-p_start] = 0;
  			i++;
  			p_start = p_end + 1;
 		}
 		else {
			strncpy(parts[i], p_start, 1);
			i++;
			strncpy(parts[i], p_start+2, 2);
  		break;
 		}
	}
	gps_raw_data.type = parts[0];
	gps_raw_data.time = atol(parts[1]);
	gps_raw_data.status = *parts[2];
	gps_raw_data.pos_ltd = atof(parts[3]);
	gps_raw_data.vert_ind = *parts[4];
	gps_raw_data.pos_lgt = atof(parts[5]);
	gps_raw_data.hrz_ind = *parts[6];
	gps_raw_data.speed = atof(parts[7]);
	gps_raw_data.direction = atof(parts[8]);
	gps_raw_data.date = atol(parts[9]); 
	gps_raw_data.variation = atof(parts[10]);
	gps_raw_data.variation_direction = *parts[11];
	gps_raw_data.checksum = *parts[12];


Hocam böyle birşey yaptım ama yine sorun var, aslında bu kod online gnu gcc compiler ile sorunsuz çalışıyor, keil'e geçince yine 0'lar dönüyor, nerede hata yaptım bu sefer yine :(

Klein

GNU'da çalışıp Keil'de çalışmıyorsa,  sorun runtime kütüphanede olabilir.
Önce part dizilerinin içeriğini bir kontrol et. Oraya yaptığın kopyalama doğru mu?
Kopyalanmış dizinin başında sonunda istenmeyen karakterler var mı? sonunda null var mı?
eğer dizi içeriği doğru ise, sorun çevirme fonksiyonlarındadır.

Cemre.

void GPS_Parse(char* string, char* storage, char part){
    while(*string >= ' ' && part){ //catch cr/lf/etc
        if(*string++ == ',') part--; //find ',' 'part' times
    }
    while(*string >= ' ' && *string != ',' && *string != '*'){ //until cr/lf/etc or ','
        *storage++ = *string++; //save
    }
    *storage = 0; //0 terminate string
}	 

void GPS_Parse_Checksum(char* string, char* storage){
    char part = 1;
		while(*string >= ' ' && part){ //catch cr/lf/etc
        if(*string++ == '*') part--; //find ',' 'part' times
    }
    while(*string >= ' ' && *string != '*'){ //until cr/lf/etc or ','
        *storage++ = *string++; //save
    }
    *storage = 0; //0 terminate string
}	 

void GPS_Converter(){
	for(int i=0;i<12;i++) GPS_Parse(Rx_Buffer, parts[i], i);
	GPS_Parse_Checksum(Rx_Buffer, parts[12]);
	
	gps_raw_data.type = parts[0];
	gps_raw_data.time = atol(parts[1]);
	gps_raw_data.status = *parts[2];
	gps_raw_data.pos_ltd = atof(parts[3]);
	gps_raw_data.vert_ind = *parts[4];
	gps_raw_data.pos_lgt = atof(parts[5]);
	gps_raw_data.hrz_ind = *parts[6];
	gps_raw_data.speed = atof(parts[7]);
	gps_raw_data.direction = atof(parts[8]);
	gps_raw_data.date = atol(parts[9]); 
	gps_raw_data.variation = atof(parts[10]);
	gps_raw_data.variation_direction = *parts[11];
	gps_raw_data.checksum = atol(parts[12]);
}


Derdimi tam olarak yukarıdaki kodla çözdüm. @Klein hocam yardımlarınız için teşekkürler.
Şuan boş da olsa dolu da olsa istediğim gibi bölüyor hatasız. Yapılabilecek bir iyileştirme var mı bu kod için hocam?