nmea.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #include "NMEA.h"
  2. #include "stdio.h"
  3. #include "stdarg.h"
  4. #include "string.h"
  5. #include "math.h"
  6. //
  7. //BC20 NMEA解析
  8. //
  9. //从buf里面得到第cx个逗号所在的位置
  10. //返回值:0~0XFE,代表逗号所在位置的偏移.
  11. // 0XFF,代表不存在第cx个逗号
  12. uint8_t NMEA_Comma_Pos(uint8_t *buf,uint8_t cx)
  13. {
  14. uint8_t *p=buf;
  15. while(cx)
  16. {
  17. if(*buf=='*'||*buf<' '||*buf>'z')return 0XFF;//遇到'*'或者非法字符,则不存在第cx个逗号
  18. if(*buf==',')cx--;
  19. buf++;
  20. }
  21. return buf-p;
  22. }
  23. //m^n函数
  24. //返回值:m^n次方.
  25. uint32_t NMEA_Pow(uint8_t m,uint8_t n)
  26. {
  27. uint32_t result=1;
  28. while(n--)result*=m;
  29. return result;
  30. }
  31. //str转换为数字,以','或者'*'结束
  32. //buf:数字存储区
  33. //dx:小数点位数,返回给调用函数
  34. //返回值:转换后的数值
  35. int NMEA_Str2num(uint8_t *buf,uint8_t*dx)
  36. {
  37. uint8_t *p=buf;
  38. uint32_t ires=0,fres=0;
  39. uint8_t ilen=0,flen=0,i;
  40. uint8_t mask=0;
  41. int res;
  42. while(1) //得到整数和小数的长度
  43. {
  44. if(*p=='-'){mask|=0X02;p++;}//是负数
  45. if(*p==','||(*p=='*'))break;//遇到结束了
  46. if(*p=='.'){mask|=0X01;p++;}//遇到小数点了
  47. else if(*p>'9'||(*p<'0')) //有非法字符
  48. {
  49. ilen=0;
  50. flen=0;
  51. break;
  52. }
  53. if(mask&0X01)flen++;
  54. else ilen++;
  55. p++;
  56. }
  57. if(mask&0X02)buf++; //去掉负号
  58. for(i=0;i<ilen;i++) //得到整数部分数据
  59. {
  60. ires+=NMEA_Pow(10,ilen-1-i)*(buf[i]-'0');
  61. }
  62. if(flen>5)flen=5; //最多取5位小数
  63. *dx=flen; //小数点位数
  64. for(i=0;i<flen;i++) //得到小数部分数据
  65. {
  66. fres+=NMEA_Pow(10,flen-1-i)*(buf[ilen+1+i]-'0');
  67. }
  68. res=ires*NMEA_Pow(10,flen)+fres;
  69. if(mask&0X02)res=-res;
  70. return res;
  71. }
  72. //分析GPGSV信息
  73. //gpsx:nmea信息结构体
  74. //buf:接收到的GPS数据缓冲区首地址
  75. void NMEA_GPGSV_Analysis(nmea_msg *gpsx,uint8_t *buf)
  76. {
  77. uint8_t *p,*p1,dx;
  78. uint8_t len,i,j,slx=0;
  79. uint8_t posx;
  80. p=buf;
  81. p1=(uint8_t*)strstr((const char *)p,"$GPGSV");
  82. len=p1[7]-'0'; //得到GPGSV语句条数
  83. posx=NMEA_Comma_Pos(p1,3); //得到可见卫星总数
  84. if(posx!=0XFF)gpsx->svnum=NMEA_Str2num(p1+posx,&dx);
  85. for(i=0;i<len;i++)
  86. {
  87. p1=(uint8_t*)strstr((const char *)p,"$GPGSV");
  88. for(j=0;j<4;j++)
  89. {
  90. posx=NMEA_Comma_Pos(p1,4+j*4);
  91. if(posx!=0XFF)gpsx->slmsg[slx].num=NMEA_Str2num(p1+posx,&dx); //得到卫星编号
  92. else break;
  93. posx=NMEA_Comma_Pos(p1,5+j*4);
  94. if(posx!=0XFF)gpsx->slmsg[slx].eledeg=NMEA_Str2num(p1+posx,&dx);//得到卫星仰角
  95. else break;
  96. posx=NMEA_Comma_Pos(p1,6+j*4);
  97. if(posx!=0XFF)gpsx->slmsg[slx].azideg=NMEA_Str2num(p1+posx,&dx);//得到卫星方位角
  98. else break;
  99. posx=NMEA_Comma_Pos(p1,7+j*4);
  100. if(posx!=0XFF)gpsx->slmsg[slx].sn=NMEA_Str2num(p1+posx,&dx); //得到卫星信噪比
  101. else break;
  102. slx++;
  103. }
  104. p=p1+1;//切换到下一个GPGSV信息
  105. }
  106. }
  107. //分析GBGSV信息
  108. //gpsx:nmea信息结构体
  109. //buf:接收到的GPS数据缓冲区首地址
  110. void NMEA_GBGSV_Analysis(nmea_msg *gpsx,uint8_t *buf)
  111. {
  112. uint8_t *p,*p1,dx;
  113. uint8_t len,i,j,slx=0;
  114. uint8_t posx;
  115. p=buf;
  116. p1=(uint8_t*)strstr((const char *)p,"$GBGSV");
  117. len=p1[7]-'0'; //得到GBGSV的条数
  118. posx=NMEA_Comma_Pos(p1,3); //得到可见北斗卫星总数
  119. if(posx!=0XFF)gpsx->beidou_svnum=NMEA_Str2num(p1+posx,&dx);
  120. for(i=0;i<len;i++)
  121. {
  122. p1=(uint8_t*)strstr((const char *)p,"$GBGSV");
  123. for(j=0;j<4;j++)
  124. {
  125. posx=NMEA_Comma_Pos(p1,4+j*4);
  126. if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_num=NMEA_Str2num(p1+posx,&dx); //得到卫星编号
  127. else break;
  128. posx=NMEA_Comma_Pos(p1,5+j*4);
  129. if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_eledeg=NMEA_Str2num(p1+posx,&dx);//得到卫星仰角
  130. else break;
  131. posx=NMEA_Comma_Pos(p1,6+j*4);
  132. if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_azideg=NMEA_Str2num(p1+posx,&dx);//得到卫星方位角
  133. else break;
  134. posx=NMEA_Comma_Pos(p1,7+j*4);
  135. if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_sn=NMEA_Str2num(p1+posx,&dx); //得到卫星信噪比
  136. else break;
  137. slx++;
  138. }
  139. p=p1+1;//切换到下一个BDGSV信息
  140. }
  141. }
  142. //分析GNGGA信息
  143. //gpsx:nmea信息结构体
  144. //buf:接收到的GPS数据缓冲区首地址
  145. void NMEA_GNGGA_Analysis(nmea_msg *gpsx,uint8_t *buf)
  146. {
  147. uint8_t *p1,dx;
  148. uint8_t posx;
  149. p1=(uint8_t*)strstr((const char *)buf,"$GNGGA");
  150. posx=NMEA_Comma_Pos(p1,6); //得到GPS状态
  151. if(posx!=0XFF)gpsx->gpssta=NMEA_Str2num(p1+posx,&dx);
  152. posx=NMEA_Comma_Pos(p1,7); //得到用于定位的卫星数
  153. if(posx!=0XFF)gpsx->posslnum=NMEA_Str2num(p1+posx,&dx);
  154. posx=NMEA_Comma_Pos(p1,9); //得到海拔高度
  155. if(posx!=0XFF)gpsx->altitude=NMEA_Str2num(p1+posx,&dx);
  156. }
  157. //分析GNGSA信息
  158. //gpsx:nmea信息结构体
  159. //buf:接收到的GPS数据缓冲区首地址
  160. void NMEA_GNGSA_Analysis(nmea_msg *gpsx,uint8_t *buf)
  161. {
  162. uint8_t *p1,dx;
  163. uint8_t posx;
  164. uint8_t i;
  165. p1=(uint8_t*)strstr((const char *)buf,"$GNGSA");
  166. posx=NMEA_Comma_Pos(p1,2); //得到定位类型
  167. if(posx!=0XFF)gpsx->fixmode=NMEA_Str2num(p1+posx,&dx);
  168. for(i=0;i<12;i++) //得到定位卫星编号
  169. {
  170. posx=NMEA_Comma_Pos(p1,3+i);
  171. if(posx!=0XFF)gpsx->possl[i]=NMEA_Str2num(p1+posx,&dx);
  172. else break;
  173. }
  174. posx=NMEA_Comma_Pos(p1,15); //得到PDOP位置精度因子
  175. if(posx!=0XFF)gpsx->pdop=NMEA_Str2num(p1+posx,&dx);
  176. posx=NMEA_Comma_Pos(p1,16); //得到HDOP位置精度因子
  177. if(posx!=0XFF)gpsx->hdop=NMEA_Str2num(p1+posx,&dx);
  178. posx=NMEA_Comma_Pos(p1,17); //得到VDOP位置精度因子
  179. if(posx!=0XFF)gpsx->vdop=NMEA_Str2num(p1+posx,&dx);
  180. }
  181. //分析GNRMC信息
  182. //gpsx:nmea信息结构体
  183. //buf:接收到的GPS数据缓冲区首地址
  184. void NMEA_GNRMC_Analysis(nmea_msg *gpsx,uint8_t *buf)
  185. {
  186. uint8_t *p1,dx;
  187. uint8_t posx;
  188. uint32_t temp;
  189. float rs;
  190. p1=(uint8_t*)strstr((const char *)buf,"$GNRMC");//"$GNRMC",经常有&和GNRMC分开的情况,故只判断GPRMC.
  191. posx=NMEA_Comma_Pos(p1,1); //得到UTC时间
  192. if(posx!=0XFF)
  193. {
  194. temp=NMEA_Str2num(p1+posx,&dx)/NMEA_Pow(10,dx); //得到UTC时间,去掉ms
  195. gpsx->utc.hour=temp/10000;
  196. gpsx->utc.min=(temp/100)%100;
  197. gpsx->utc.sec=temp%100;
  198. }
  199. posx=NMEA_Comma_Pos(p1,3); //得到纬度
  200. if(posx!=0XFF)
  201. {
  202. temp=NMEA_Str2num(p1+posx,&dx);
  203. gpsx->latitude=temp/NMEA_Pow(10,dx+2); //得到°
  204. rs=temp%NMEA_Pow(10,dx+2); //得到'
  205. gpsx->latitude=gpsx->latitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//转换为°
  206. }
  207. posx=NMEA_Comma_Pos(p1,4); //南纬还是北纬
  208. if(posx!=0XFF)gpsx->nshemi=*(p1+posx);
  209. posx=NMEA_Comma_Pos(p1,5); //得到经度
  210. if(posx!=0XFF)
  211. {
  212. temp=NMEA_Str2num(p1+posx,&dx);
  213. gpsx->longitude=temp/NMEA_Pow(10,dx+2); //得到°
  214. rs=temp%NMEA_Pow(10,dx+2); //得到'
  215. gpsx->longitude=gpsx->longitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//转换为°
  216. }
  217. posx=NMEA_Comma_Pos(p1,6); //东经还是西经
  218. if(posx!=0XFF)gpsx->ewhemi=*(p1+posx);
  219. posx=NMEA_Comma_Pos(p1,9); //得到UTC日期
  220. if(posx!=0XFF)
  221. {
  222. temp=NMEA_Str2num(p1+posx,&dx); //得到UTC日期
  223. gpsx->utc.date=temp/10000;
  224. gpsx->utc.month=(temp/100)%100;
  225. gpsx->utc.year=2000+temp%100;
  226. }
  227. }
  228. //分析GNVTG信息
  229. //gpsx:nmea信息结构体
  230. //buf:接收到的GPS数据缓冲区首地址
  231. void NMEA_GNVTG_Analysis(nmea_msg *gpsx,uint8_t *buf)
  232. {
  233. uint8_t *p1,dx;
  234. uint8_t posx;
  235. p1=(uint8_t*)strstr((const char *)buf,"$GNVTG");
  236. posx=NMEA_Comma_Pos(p1,7); //得到地面速率
  237. if(posx!=0XFF)
  238. {
  239. gpsx->speed=NMEA_Str2num(p1+posx,&dx);
  240. if(dx<3)gpsx->speed*=NMEA_Pow(10,3-dx); //确保扩大1000倍
  241. }
  242. }
  243. //提取NMEA-0183信息
  244. //gpsx:nmea信息结构体
  245. //buf:接收到的GPS数据缓冲区首地址
  246. void NMEA_Analysis(nmea_msg *gpsx,uint8_t *buf)
  247. {
  248. NMEA_GNRMC_Analysis(gpsx,buf); //GPNMC解析
  249. NMEA_GPGSV_Analysis(gpsx,buf); //GPGSV解析
  250. NMEA_GBGSV_Analysis(gpsx,buf); //GBGSV解析
  251. NMEA_GNGGA_Analysis(gpsx,buf); //GNGGA解析
  252. NMEA_GNGSA_Analysis(gpsx,buf); //GPNSA解析
  253. NMEA_GNVTG_Analysis(gpsx,buf); //GPNTG解析
  254. }