1.说明
接上篇发送端,此篇主要实现将接收到的GPS坐标数据显示到另外一块TKB-620 OLED上,并且通过串口发给手机上位机,记录无人机运动轨迹,这个上位机后续实现。
2.代码实现
(1).模组数据接收解析实现,此处代码主要解析TK8620接收到的数据,并且将数据还原成"0001020304-N_S %s,latitude %s,E_W %s,longitude %s,\r\n",此处略其他AT指令处理代码,解析GPS定位数据具体实现如下:
`
case FSM_RCVDATA:
if (WorkUartRcv.USART_RX_STA.b.rdy)
{
if (strstr((char *)WorkUartRcv.DataBuffer,"+DI"))
{
RF_DEBUG("%s", WorkUartRcv.DataBuffer);
pStrSnr = strstr((char *)WorkUartRcv.DataBuffer, "SNR ");
pStrRssi = strstr((char *)WorkUartRcv.DataBuffer, "RSSI ");
pStrData = strstr((char *)WorkUartRcv.DataBuffer, "Data ");
if (pStrSnr)
{
token = strtok(pStrSnr + 4, ",");
if (token)
sys_param.snr = atoi(token);
}
if (pStrRssi)
{
token = strtok(pStrRssi + 5, ",");
if (token)
sys_param.rssi = atoi(token);
}
if (pStrData)
{
token = strtok(pStrData + 5, "\\r\\n");
if (token && !strncmp(token, "0001020304", strlen("0001020304")))
{
sys_param.rx_count++;
token = strtok(pStrData + 15, "\\r\\n");
if (token)
{
txSideCnt = strtol(token, NULL, 16);
if (sys_param.rx_count > txSideCnt)
{
sys_param.rx_count = txSideCnt;
}
sys_param.rxPktLossRate = 100 - (((float)sys_param.rx_count / txSideCnt) * 100);
sys_param.screen_refresh = 1;
}
}
pStrGPS = strtok(pStrData + 15, "\\r\\n");
memset(buffer,0,64);
Str2Data(pStrGPS,(uint8_t*)buffer,strlen(pStrGPS));
pStrNS = strstr(buffer,"N_S:");
pStrEW = strstr(buffer,"E_W:");
pStrLatitude = strstr(buffer,"latitude:");
pStrLongitude = strstr(buffer,"longitude:");
if(pStrNS)
{
token = strtok(pStrNS + 4, ",");
if (token)
{
memcpy(gpsData.N_S,token,strlen(token)>N_S_Length?N_S_Length:strlen(token));
RF_DEBUG("gpsData.N_S:%s\\n", gpsData.N_S);
gpsData.isGetData = true;
sys_param.screen_refresh = 1;
}
else
{
gpsData.isGetData = false;
sys_param.screen_refresh = 0;
}
}
else
{
gpsData.isGetData = false;
sys_param.screen_refresh = 0;
}
if(pStrEW)
{
token = strtok(pStrEW + 4, ",");
if (token)
{
memcpy(gpsData.E_W,token,strlen(token)>E_W_Length?E_W_Length:strlen(token));
RF_DEBUG("gpsData.E_W:%s\\n", gpsData.E_W);
gpsData.isGetData = true;
sys_param.screen_refresh = 1;
}
else
{
gpsData.isGetData = false;
sys_param.screen_refresh = 0;
}
}
else
{
gpsData.isGetData = false;
sys_param.screen_refresh = 0;
}
if(pStrLatitude)
{
token = strtok(pStrLatitude + 9, ",");
if (token)
{
memcpy(gpsData.latitude,token,strlen(token)>latitude_Length?latitude_Length:strlen(token));
RF_DEBUG("gpsData.latitude:%s\\n", gpsData.latitude);
gpsData.isGetData = true;
sys_param.screen_refresh = 1;
}
else
{
gpsData.isGetData = false;
sys_param.screen_refresh = 0;
}
}
else
{
gpsData.isGetData = false;
sys_param.screen_refresh = 0;
}
if(pStrLongitude)
{
token = strtok(pStrLongitude + 10, ",");
if (token)
{
memcpy(gpsData.longitude,token,strlen(token)>longitude_Length?longitude_Length:strlen(token));
RF_DEBUG("gpsData.longitude:%s\\n", gpsData.longitude);
gpsData.isGetData = true;
sys_param.screen_refresh = 1;
}
else
{
gpsData.isGetData = false;
sys_param.screen_refresh = 0;
}
}
else
{
gpsData.isGetData = false;
sys_param.screen_refresh = 0;
}
}
}
WorkUartRcvClr();
}
break;
(2)OLED显示部分代码:
OLED要增加一个页面来显示GPS数据。
菜单新增代码:
`
{
.screenIdx = 4,
.screen_param =
{
{.x_base = 0, .y_base = 0, .string = "5.GPS Display ", .modifyPos = 0, .modify = 0},
{.x_base = 0, .y_base = 1, .string = "Longitudes: ", .modifyPos = 0, .modify = 0},
{.x_base = 0, .y_base = 2, .string = "Invalid", .modifyPos = 0, .modify = 0},
{.x_base = 0, .y_base = 3, .string = "Latitude:", .modifyPos = 0, .modify = 0},
{.x_base = 0, .y_base = 4, .string = "Invalid", .modifyPos = 0, .modify = 0},
}
}
(3).OLED显示代码:
`
case 4:
if(gpsData.isGetData)
{
xPos = show_param[screenIdx].screen_param[0].x_base;
yPos = show_param[screenIdx].screen_param[0].y_base;
pStr = show_param[screenIdx].screen_param[0].string;
OLED_ShowString(xPos, yPos, pStr, 1);
xPos = show_param[screenIdx].screen_param[1].x_base;
yPos = show_param[screenIdx].screen_param[1].y_base;
pStr = show_param[screenIdx].screen_param[1].string;
OLED_ShowString(xPos, yPos, pStr, 1);
//经度
xPos = show_param[screenIdx].screen_param[2].x_base;
yPos = show_param[screenIdx].screen_param[2].y_base;
memset(str,0,12);
strcat((char *)str, gpsData.E_W);
strcat((char *)str, ":");
strcat((char *)str, gpsData.longitude);
pStr = str;
OLED_ShowString(xPos, yPos, pStr, 1);
xPos = show_param[screenIdx].screen_param[3].x_base;
yPos = show_param[screenIdx].screen_param[3].y_base;
pStr = show_param[screenIdx].screen_param[3].string;
OLED_ShowString(xPos, yPos, pStr, 1);
//纬度
xPos = show_param[screenIdx].screen_param[4].x_base;
yPos = show_param[screenIdx].screen_param[4].y_base;
memset(str,0,12);
strcat((char *)str, gpsData.N_S);
strcat((char *)str, ":");
strcat((char *)str, gpsData.latitude);
pStr = str;
OLED_ShowString(xPos, yPos, pStr, 1);
gpsData.isGetData = false;
}
else
{
xPos = show_param[screenIdx].screen_param[0].x_base;
yPos = show_param[screenIdx].screen_param[0].y_base;
pStr = show_param[screenIdx].screen_param[0].string;
OLED_ShowString(xPos, yPos, pStr, 1);
xPos = show_param[screenIdx].screen_param[1].x_base;
yPos = show_param[screenIdx].screen_param[1].y_base;
pStr = show_param[screenIdx].screen_param[1].string;
OLED_ShowString(xPos, yPos, pStr, 1);
xPos = show_param[screenIdx].screen_param[2].x_base;
yPos = show_param[screenIdx].screen_param[2].y_base;
pStr = show_param[screenIdx].screen_param[2].string;
OLED_ShowString(xPos, yPos, pStr, 1);
xPos = show_param[screenIdx].screen_param[3].x_base;
yPos = show_param[screenIdx].screen_param[3].y_base;
pStr = show_param[screenIdx].screen_param[3].string;
OLED_ShowString(xPos, yPos, pStr, 1);
xPos = show_param[screenIdx].screen_param[4].x_base;
yPos = show_param[screenIdx].screen_param[4].y_base;
pStr = show_param[screenIdx].screen_param[4].string;
OLED_ShowString(xPos, yPos, pStr, 1);
}
break;
3.结果展示


测试的时候我找了一条东西向的路走了一公里,经度数据还是有变化的,注意图片里面显示的坐标并非本人实际坐标,左边为发送端,右边为接收端。






4.开发心得
本次开发大量时间都都浪费到调试GPS定位数据接收解析,OLED数据显示上,大约花费了3个工作日实现了基本功能,无线通讯上基本没有花费时间,TurMass模块的优势在于无线通讯部分协议厂家全部开发好了,用户到手其实不用关心复杂的无线协议和模块寄存器配置,只需使用AT指令就能很快实现sub-1G无线通讯应用,相较于传统的LoRa和GFSK,具有快速上手和低成本的优势,因为LoRa和GFSK你要买第三方厂家封装好支持AT指令且支持快速组网的模组少说20元/pcs起步,目前已有第三方厂家生产的基于turmass技术的模组,如EBYTE的EWM-293-470,20dbm的版本目前报价不到16块/pcs,看了他的datasheet,似乎只是重新做了pcb layout,AT指令与道生提供的一模一样,对这个模组感兴趣可以买来玩玩,还有海凌科HLK-L08,也是基于tk8620实现。