最近在做GPS相关的功能,主控芯片使用的是STM32H7系列的,遂做个记录留念~
CUBEMX配置底层驱动
ST芯片驱动用cuber来配置还是相当方便的,这里就简单配置一下UART,因为ATGM芯片是通过串口来通讯的,就是简单的配置了一下串口:
首先配置RCC:
根据需要配置一下时钟树,这里就不多做赘述~
这里简单选个异步通讯,其他全默认即可,然后我们生成工程。
串口接收队列
为了方便解析GPS数据,我这边写了一个队列来处理这个问题:
#define MAX_SIZE 10000
typedef struct
{
uint8_t data[MAX_SIZE];
int front, rear;
} Queue;
void initQueue(Queue *q)
{
q->front = 0;
q->rear = 0;
}
int isFull(Queue *q)
{
return (q->rear + 1) % MAX_SIZE == q->front;
}
int isEmpty(Queue *q)
{
return q->front == q->rear;
}
int queueSize(Queue *q)
{
return (q->rear - q->front + MAX_SIZE) % MAX_SIZE;
}
void enqueue(Queue *q, uint8_t item)
{
if (!isFull(q))
{
q->data[q->rear] = item;
q->rear = (q->rear + 1) % MAX_SIZE;
}
else
{
// todo :: if full
}
};
uint8_t dequeue(Queue *q)
{
uint8_t item = q->data[q->front];
q->front = (q->front + 1) % MAX_SIZE;
return item;
}
uint8_t getLastValidData(Queue *q)
{
int size = queueSize(q);
if (size == 0)
{
return 0;
}
else
{
return q->data[(q->rear - 1 + MAX_SIZE) % MAX_SIZE];
}
}
uint8_t getDataAtPosition(Queue *q, int position)
{
int size = queueSize(q);
if (size == 0 || position >= size || position < 0)
{
return 0;
}
else
{
return q->data[(q->front + position) % MAX_SIZE];
}
}
随后在回调函数中接收数据:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
// SCB_InvalidateDCache_by_Addr((uint32_t *)uart_rxdata, 128);
for (int i = 0; i < 200; i++)
{
enqueue(&gps2can_q, uart_rxdata[i]);
}
HAL_UART_Receive_DMA(&huart1, uart_rxdata, 200);
}
}
在主循环中处理数据:
void Gps_Poll(Queue *q)
{
uint8_t data[300] = {0};
uint16_t size = 0;
// judge empty
if (isEmpty(q))
{
return;
}
// get datalength
size = queueSize(q);
if (size < 3)
{
return;
}
// judge front
if (0x24 != dequeue(q))
{
return;
}
else
{
data[0] = 0x24;
}
// judge rear
for (int i = 1; i < size; i++)
{
if (getDataAtPosition(q, i) == 0x0A)
{
for (int j = 1; j <= (i + 1); j++)
{
data[j] = dequeue(q);
}
Gps_process(data, (i + 2));
return;
}
}
}
void Gps_process(uint8_t pData[], uint16_t pDataLength)
{
uint8_t gnss = 0;
if (pData[0] != '$')
{
return;
}
if (pData[1] == 'B' && pData[2] == 'D')
{
gnss = bd;
}
else if (pData[1] == 'G' && pData[2] == 'P')
{
gnss = gp;
}
else if (pData[1] == 'G' && pData[2] == 'L')
{
gnss = gl;
}
else if (pData[1] == 'G' && pData[2] == 'N')
{
gnss = gn;
}
else
{
return;
}
if (pData[3] == 'G' && pData[4] == 'G' && pData[5] == 'A')
{
switch (gnss)
{
case bd:
Gps_gga(pData, pDataLength, &gps2can.atgm332d.bd.gga);
break;
case gp:
break;
case gl:
Gps_gga(pData, pDataLength, &gps2can.atgm332d.gl.gga);
break;
case gn:
break;
default:
break;
}
}
else if (pData[3] == 'G' && pData[4] == 'L' && pData[5] == 'L')
{
}
else if (pData[3] == 'G' && pData[4] == 'S' && pData[5] == 'A')
{
}
else if (pData[3] == 'G' && pData[4] == 'S' && pData[5] == 'V')
{
}
else if (pData[3] == 'R' && pData[4] == 'M' && pData[5] == 'C')
{
}
else if (pData[3] == 'V' && pData[4] == 'T' && pData[5] == 'G')
{
}
else if (pData[3] == 'Z' && pData[4] == 'D' && pData[5] == 'A')
{
}
}
至于为什么这样处理,感兴趣的小伙伴可以去看一下对应的NEMA协议~
我这里只给出了GGA的处理,目前我只需要用到GGA语句解析:
unsigned char AsciiToHex(uint8_t *str, uint8_t size, uint8_t *result)
{
unsigned char temp;
for (*result = 0; size; size--, str++)
{
if (('9' >= *str) && (*str >= '0'))
temp = *str - '0';
else if (('F' >= *str) && (*str >= 'A'))
temp = *str - 'A' + 10;
else if (('f' >= *str) && (*str >= 'a'))
temp = *str - 'a' + 10;
else
return 1;
*result |= temp << ((size - 1) * 4);
}
return 0;
}
uint8_t MMEA_CheckSum(uint8_t *buf)
{
unsigned char i;
unsigned char chk, result;
for (chk = buf[1], i = 2; (buf[i] != '*') && (i < 255); i++)
{
chk ^= buf[i];
}
if (AsciiToHex(&buf[i + 1], 2, &result))
return 3;
if (i >= 255)
return 2;
if (chk != result)
return 1;
return 0; // 校验成功
}
void Gps_gga(uint8_t pData[], uint16_t pDataLength, nema_gga *pGGA)
{
// next must be ,
uint8_t index = 6;
uint8_t count = 0;
uint8_t hex_data = 0;
// count ,
for (int i = 0; i < pDataLength; i++)
{
if (pData[i] == ',')
{
count++;
}
}
if (count != 14)
{
return;
}
if (MMEA_CheckSum(pData) != 0)
{
return;
}
if (pData[index] != ',')
{
return;
}
index++;
// utc_time
if (pData[index] == ',')
{
pGGA->utc_time_flag = 0;
index++;
}
else
{
pGGA->utc_time_flag = 1;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->utc_time = hex_data * 10000000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->utc_time += hex_data * 1000000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->utc_time += hex_data * 100000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->utc_time += hex_data * 10000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->utc_time += hex_data * 1000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->utc_time += hex_data * 100;
index++;
while (pData[index] != ',')
{
index++;
}
index++;
}
// lat
if (pData[index] == ',')
{
pGGA->lat_flag = 0;
index++;
}
else
{
pGGA->lat_flag = 1;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lat = hex_data * 10000000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lat += hex_data * 1000000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lat += hex_data * 100000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lat += hex_data * 10000;
index++;
if (pData[index] == '.')
{
index++;
}
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lat += hex_data * 1000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lat += hex_data * 100;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lat += hex_data * 10;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lat += hex_data;
index++;
while (pData[index] != ',')
{
index++;
}
index++;
}
// ulat
if (pData[index] == ',')
{
pGGA->ulat_flag = 0;
index++;
}
else
{
pGGA->ulat_flag = 1;
if (pData[index] == 'N')
{
pGGA->ulat = 0;
}
else if (pData[index] == 'S')
{
pGGA->ulat = 1;
}
while (pData[index] != ',')
{
index++;
}
index++;
}
// lon
if (pData[index] == ',')
{
pGGA->lon_flag = 0;
index++;
}
else
{
pGGA->lon_flag = 1;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lon = hex_data * 100000000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lon += hex_data * 10000000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lon += hex_data * 1000000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lon += hex_data * 100000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lon += hex_data * 10000;
index++;
if (pData[index] == '.')
{
index++;
}
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lon += hex_data * 1000;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lon += hex_data * 100;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lon += hex_data * 10;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->lon += hex_data;
index++;
while (pData[index] != ',')
{
index++;
}
index++;
}
// ulon
if (pData[index] == ',')
{
pGGA->ulon_flag = 0;
index++;
}
else
{
pGGA->ulon_flag = 1;
if (pData[index] == 'E')
{
pGGA->ulon = 0;
}
else if (pData[index] == 'W')
{
pGGA->ulon = 1;
}
while (pData[index] != ',')
{
index++;
}
index++;
}
// FS
if (pData[index] == ',')
{
pGGA->fs_flag = 0;
index++;
}
else
{
pGGA->fs_flag = 1;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->fs = hex_data;
while (pData[index] != ',')
{
index++;
}
index++;
}
// numSv
if (pData[index] == ',')
{
pGGA->numsv_flag = 0;
index++;
}
else
{
pGGA->numsv_flag = 1;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->numsv = hex_data * 10;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->numsv += hex_data;
index++;
while (pData[index] != ',')
{
index++;
}
index++;
}
// HDOP
if (pData[index] == ',')
{
pGGA->hdop_flag = 0;
index++;
}
else
{
pGGA->hdop_flag = 1;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->hdop = hex_data * 100;
index++;
if (pData[index] == '.')
{
index++;
}
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->hdop += hex_data * 10;
index++;
if (pData[index] == '.')
{
index++;
}
if (pData[index] != ',')
{
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->hdop += hex_data;
index++;
}
while (pData[index] != ',')
{
index++;
}
index++;
}
// msl
if (pData[index] == ',')
{
pGGA->msl_flag = 0;
index++;
}
else
{
pGGA->msl_flag = 1;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->msl = hex_data * 100;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->msl += hex_data * 10;
index++;
if (pData[index] == '.')
{
index++;
}
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->msl += hex_data;
index++;
while (pData[index] != ',')
{
index++;
}
index++;
}
// M
if (pData[index] == ',')
{
pGGA->msl_flag = 0;
index++;
}
else
{
if (pData[index] != 'M')
{
pGGA->msl_flag = 0;
}
index++;
while (pData[index] != ',')
{
index++;
}
index++;
}
// sep
if (pData[index] == ',')
{
pGGA->sep_flag = 0;
index++;
}
else
{
pGGA->sep_flag = 1;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->sep = hex_data * 100;
index++;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->sep += hex_data * 10;
index++;
if (pData[index] == '.')
{
index++;
}
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->sep += hex_data;
index++;
while (pData[index] != ',')
{
index++;
}
index++;
}
// M
if (pData[index] == ',')
{
pGGA->sep_flag = 0;
index++;
}
else
{
if (pData[index] != 'M')
{
pGGA->sep_flag = 0;
}
index++;
while (pData[index] != ',')
{
index++;
}
index++;
}
// diffage
if (pData[index] == ',')
{
pGGA->diffage_flag = 0;
index++;
}
else
{
pGGA->diffage_flag = 1;
AsciiToHex(&pData[index], 1, &hex_data);
pGGA->diffage = hex_data;
index++;
while (pData[index] != ',')
{
index++;
}
index++;
}
// diffsta * cs
if (pData[index] != '*')
{
// pGGA->diffsta_flag = 1;
index++;
while (pData[index] != '*')
{
index++;
}
index++;
}
else
{
// pGGA->diffage_flag = 0;
}
}
我这边处理上是将多个字符合并成一个大数据来处理了,可以根据需要自行选用合适的处理方案~
希望能够帮到你。