About using the super-core HI600D to obtain UTC time, latitude and longitude, east longitude, ground speed, ground heading, and date.

This article uses the stm32f103vet6 development board + super-core HI600D to obtain a series of information

1. Serial port data

When we connect the Super Core 600D with a type-B data cable and connect it to the computer, open the serial port assistant and get a series of information

as the picture shows:

This is unpositioned raw data. If we want to obtain effective data, we must perform positioning in an open environment or in a place with a base station.

The data after positioning is shown in the figure:

What I want to read is the information of RMC

$GNRMC,044125.000,A,2951.1711260,N,11419.9958340,E,0.12,106.68,070823,,,A,V*03

These data are NMEA0183 V4.10 protocol, as shown in the figure

GGA is the time, position and positioning related data of the receiver.

GSV is to output visible satellite status, including: visible satellite number, satellite identification number, elevation angle, azimuth angle and signal-to-noise ratio (SNR).

RMC is the simplest navigation to transmit data. (It is also the data that this article wants to read and parse)

VTG outputs ground speed information.

Mainly for GGA, GSV, RMC. Readers can read the desired NMEA protocol according to their desired data, see the user manual of HI600 for details.

2. The use of stm32 connection ultra-core HI600D

I am a stm32f103vet6 development board + HAL library development. I have also tried the stm32 code of Supercore’s own hi600, but there is no response when burning it into the serial port. It may be that the chip model is wrong or the serial port is not configured properly. The official routine is stm32f103zet6 + standard library development, using serial port 1 and serial port 2, I use serial port 1 and serial port 3, connect HI600 to serial port 3 of stm32.

Super core 600 connection stm32
TX0 —-> PB11
RX0 —> PB10
GND —> GND
5V — ->

5V

The picture shows the connection method

2.1 Configure the serial port

void USART1_Init(unsigned int BPS, void Tx_Over(void), void (*RxFunction)(unsigned char RX_Data))
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
   
\t\t
__HAL_RCC_USART1_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
\t  
    Usart_ISR.U1TXOver = Tx_Over;
    Usart_ISR.U1RXOperation = RxFunction;

    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, & GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, & GPIO_InitStruct);
\t\t
huart1.Instance = USART1;
    huart1.Init.BaudRate = BPS;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init( & amp;huart1) != HAL_OK)
    {
      Error_Handler();
    }
\t\t
__HAL_UART_ENABLE_IT( &huart1, UART_IT_RXNE);

\t 
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
void USART3_Init(unsigned int BPS, void Tx_Over(void), void (*RxFunction)(unsigned char RX_Data))
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
 
__HAL_RCC_USART3_CLK_ENABLE();
     __HAL_RCC_GPIOB_CLK_ENABLE();
\t 
     Usart_ISR.U3TXOver = Tx_Over;
Usart_ISR.U3RXOperation = RxFunction;
\t\t
GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, & GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, & GPIO_InitStruct);
\t\t
huart3.Instance = USART3;
    huart3.Init.BaudRate = BPS;
    huart3.Init.WordLength = UART_WORDLENGTH_8B;
    huart3.Init.StopBits = UART_STOPBITS_1;
    huart3.Init.Parity = UART_PARITY_NONE;
    huart3.Init.Mode = UART_MODE_TX_RX;
    huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart3.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init( & amp;huart3) != HAL_OK)
    {
     Error_Handler();
    }
\t\t
__HAL_UART_ENABLE_IT( &huart3, UART_IT_RXNE);

\t 
HAL_NVIC_SetPriority(USART3_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(USART3_IRQn);
\t
}

After configuring the serial port, you can test it yourself, whether the data of serial port 3 can be sent to serial port 1 for printing.

void ESP_RX_ISR( uint8_t RX_Data)
{
\t\t
esp_recv_buff[esp_rx_index++] = RX_Data;
}

Because I am adapting the 8266 code, the names of some functions have not changed, sorry, but the essential content remains the same. In this function, we get the most important serial port 3 RX_Data, and store it in the esp_recv_buff array.

USART1_Send_Poll(esp_recv_buff,esp_recv_len);

void USART1_Send_Poll(uint8_t *buff, uint16_t Size)
{
uint16_t i;
\t
for(i = 0; i < Size; i ++ )
{
USART1_SendByte(*buff + + );
\t  
}
}


void USART1_SendByte(char ch)
{
while((USART1_SR & UART_LSR_THRE)==0);
SEND_BUF1 = (u8) ch;
}

We can send this esp_recv_buff to the serial port and print it out to judge whether the data has been stored.

void USART3_IRQHandler(void)
{
\t
if(USART3_SR & UART_LSR_RDR)
{
 if(Usart_ISR.U3RXOperation != NULL) Usart_ISR.U3RXOperation(RECV_BUF3);
      
}
\t
HAL_UART_IRQHandler( &huart3);

Here, an interrupt function is added to the main function to determine whether it is being received.

void ESP_RecvProcess(void)
{
USART1_Send_Poll(esp_recv_buff, esp_recv_len);
ProcessRx(esp_recv_buff, esp_recv_len);
ESP_RecvBuff_Clear();
HAL_Delay(1000);

}

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  SysTick_Init(systick_isr);
  USART1_Init(115200, NULL, NULL);
  HI600_Init();
    while(1)
    {
ESP_RecvProcess();
    }
}

We initialize serial ports 1 and 3 in the main function, and print and analyze data in the loop.

Note that in the receiving function, there is also an ESP_RecvBuff_Clear() function and a delay function to help us clear the data in ESP_RecvBuff on time to prevent the array from overflowing.

When we can print the data sent from serial port 3 to serial port 1 normally, we can start data analysis

As shown in the picture:

2.2 Data analysis

Because the NMEA protocol I want to read is RMC, first we look at the output data format of RMC

The beginning of the visible header is $GPRMC

 //The character of each bit of data
     #define BEGIN1 '$'
     #define BEGIN2 'G'
     #define BEGIN3 'N'
     #define BEGIN4 'R'
     #define BEGIN5 'M'
     #define BEGIN6 'C'

    uint8_t receivedbyte, rx_sum, command;
    uint8_t rx_data[100];
    uint16_t rx_dategram_len;
    while (size)
    {
        switch (rx_datagram_state)
        {
        case IDLE:
        { int i=1;
//printf("%s", buff);
token=strchr((char*)buff,B);
*buff=*token;
while(i)
{
receivedbyte = *buff;
            if (BEGIN1 == receivedbyte)
            {
              // printf("HEADER1:%c\r\\
", *buff);
                rx_sum = 0;
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER1;
                buff + + ;
i=0;
            }
else
{
buff + + ;
}
}
            break;
        }
        case SEEN_HEADER1:
        {
            receivedbyte = *buff;
            if (BEGIN2 == receivedbyte)
            {
            // printf("HEADER2:%c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER2;
                buff + + ;
            }
            break;
        }
case SEEN_HEADER2:
        {
\t\t\t\t\t
int i=1;
          while(i)
{
receivedbyte = *buff;
            if (BEGIN3 == receivedbyte)
            {
            // printf("HEADER3:%c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER3;
                buff + + ;
i=0;
                }
else {
buff + + ;
}
}
                break;
                }
case SEEN_HEADER3: //
                {
\t\t\t\t\t
int i=1;
            while(i)
{
receivedbyte = *buff;
            if (BEGIN4 == receivedbyte)
            {
             // printf("HEADER4:%c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER4;
                buff + + ;
i=0;
            }
else {
buff + + ;
}
}
            break;
        }
case SEEN_HEADER4: //
        {
\t\t\t\t\t
int i=1;
           while(i)
{
receivedbyte = *buff;
            if (BEGIN5 == receivedbyte)
            {
            // printf("HEADER5:%c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER5;
                buff + + ;
i=0;
            }
else {
buff + + ;
}
}
            break;
        }
case SEEN_HEADER5: //
        {
           int i=1;
\t\t\t\t\t
while(i)
{
receivedbyte = *buff;
            if (BEGIN6 == receivedbyte)
            {
            // printf("HEADER6:%c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER6;
                buff + + ;
i=0;
            }
else {
buff + + ;
}
}
            break;
           }
case SEEN_HEADER6: //
           {
            receivedbyte = *buff;
            if (BEGIN7 == receivedbyte)
            {
            // printf("HEADER7:%c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER7;
                buff + + ;
            }
            break;
        }

The following is our first data UTC time, note here that UTC time is not Beijing time! ! ! (Thank you Xixi from Supernuclear for the reminder, because I was still asking in the group)

 case SEEN_HEADER7:
        {
           uint8_t TIME[11];
           for(int i=0;i<=10;i ++ )
{
TIME[i]=*buff + + ;
\t\t\t\t\t\t
}
                      UTC.Hour[0]=TIME[0];
UTC.Hour[1]=TIME[1];
UTC.Minute[0]=TIME[2];
UTC.Minute[1]=TIME[3];
UTC.Sconds[0]=TIME[4];
UTC.Sconds[1]=TIME[5];
UTC.mSconds[0]=TIME[7];
UTC.mSconds[1]=TIME[8];
UTC.mSconds[2]=TIME[9];
printf("UTC time is: %c%c:%c%c:%c%c\r\\
",UTC.Hour[0],UTC.Hour[1],UTC.Minute[0 ],UTC.Minute[1],UTC.Sconds[0],UTC.Sconds[1]);
//printf("TIME=%s",TIME);
                rx_datagram_state = SEEN_HEADER8;
// buff++;
break;
        }

OS: If there are readers who want Beijing time, they can query the algorithm for converting UTC time to Beijing time by themselves, so I won’t introduce it here.

 case SEEN_HEADER8: //read A
        {
            receivedbyte = *buff;
            if (BEGIN9 == receivedbyte)
            {
             // printf("HEADER8:%c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER9;
                buff + + ;
            }
            break;
        }

This is the most important position of RMC. After all, this is the place to judge whether it is valid positioning or invalid positioning. If it is A, it means valid positioning, and if it is V, it means invalid positioning.

 case SEEN_HEADER9:
        {
            receivedbyte = *buff;
            if (BEGIN7 == receivedbyte)
            {
              // printf("HEADER9:%c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER10;
                buff + + ;
            }
            break;
        }

This is a judgment for reading commas. If you don’t want to judge, you can add buff ++ before break in the code for reading A, so that you don’t need to read commas, but for the sake of accuracy, I still judge each comma.

case SEEN_HEADER10:
        {
           uint8_t TIME[12];
           for(int i=0;i<=11;i ++ )
{
TIME[i]=*buff + + ;
\t\t\t\t\t\t
}
                    lat.Hour[0]=TIME[0];
lat.Hour[1]=TIME[1];
lat.divide[0]=TIME[2];
lat.divide[1]=TIME[3];
lat.mSconds[0]=TIME[5];
lat.mSconds[1]=TIME[6];
lat.mSconds[2]=TIME[7];
lat.mSconds[3]=TIME[8];
lat.mSconds[4]=TIME[9];
lat.mSconds[5]=TIME[10];
lat.mSconds[6]=TIME[11];
printf("Latitude: %c%c%c%c.%c%c%c%c%c%c%c\r\\
",TIME[0],TIME[1], TIME[2],TIME[3],TIME[5],TIME[6],TIME[7],TIME[8],TIME[9],TIME[10],TIME[11]);
            rx_datagram_state = SEEN_HEADER11;
// buff++;
break;
        }
case SEEN_HEADER11: //
        {
            receivedbyte = *buff;
            if (BEGIN7 == receivedbyte)
            {
             // printf("HEADER9:%c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER12;
                buff + + ;
            }
            break;
        }
\t\t\t\t
case SEEN_HEADER12:
        {
            receivedbyte = *buff;
            if (BEGIN3 == receivedbyte)
            {
           // printf("HEADER10:%c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER13;
                buff + + ;
            }
// buff++;
            break;
        }
//
case SEEN_HEADER13:
        {
            receivedbyte = *buff;
            if (BEGIN7 == receivedbyte)
            {
             // printf("HEADER11:%c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER14;
                buff + + ;
            }
            break;
        }

case SEEN_HEADER14:
        {
           uint8_t TIME[13];
           for(int i=0;i<=12;i + + )
{
TIME[i]=*buff + + ;
\t\t\t\t\t\t
}
            lon.Hour[0]=TIME[0];
lon.Hour[1]=TIME[1];
lon.Hour[2]=TIME[2];
lon.divide[0]=TIME[3];
lon.divide[1]=TIME[4];
lon.mSconds[0]=TIME[6];
lon.mSconds[1]=TIME[7];
lon.mSconds[2]=TIME[8];
lon.mSconds[3]=TIME[9];
lon.mSconds[4]=TIME[10];
lon.mSconds[5]=TIME[11];
lon.mSconds[6]=TIME[12];
printf("Longitude: %c%c%c%c%c.%c%c%c%c%c%c%c\r\\
",TIME[0],TIME[1 ],TIME[2],TIME[3],TIME[4],TIME[6],TIME[7],TIME[8],TIME[9],TIME[10],TIME[11],TIME[12 ]);
            rx_datagram_state = SEEN_HEADER15;
// buff++;
break;
        }
\t\t\t\t
case SEEN_HEADER15:
        {
            receivedbyte = *buff;
            if (BEGIN7 == receivedbyte)
            {
            // printf("HEADER9:%c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER16;
                buff + + ;
            }
            break;
        }
case SEEN_HEADER16:
        {
            receivedbyte = *buff;
            if (BEGIN11 == receivedbyte)
            {
                printf("Eastern Airlines: %c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER17;
                buff + + ;
            }
\t\t\t\t\t
            break;
         }
\t\t\t\t
case SEEN_HEADER17:
          {
             receivedbyte = *buff;
            if (BEGIN7 == receivedbyte)
            {
             // printf("HEADER11:%c\r\\
", *buff);
                rx_sum += receivedbyte;
                rx_datagram_state = SEEN_HEADER18;
                buff + + ;
            }
            break;
        }
//
case SEEN_HEADER18:
        {
           uint8_t TIME[5];
           for(int i=0;i<=4;i++)
{
TIME[i]=*buff + + ;
\t\t\t\t\t\t
}
                    GS.Hour[0]=TIME[0];
GS.mSconds[0]=TIME[2];
GS.mSconds[1]=TIME[3];
// GS.mSconds[2]=TIME[4];
printf("Ground speed%c.%c%c\r\\
",TIME[0],TIME[2],TIME[3]);
                    rx_datagram_state = SEEN_HEADER19;
break;
        }

case SEEN_HEADER19:
        {
                 uint8_t TIME[6];
                 for(int i=0;i<=5;i++)
{
TIME[i]=*buff + + ;
\t\t\t\t\t\t
}
                   GH.Hour[0]=TIME[0];
GH.Hour[1]=TIME[1];
//GH.Hour[2]=TIME[2];
GS.mSconds[0]=TIME[3];
GS.mSconds[1]=TIME[4];
printf("Ground heading %c%c.%c%c\r\\
",TIME[0],TIME[1],TIME[3],TIME[4]);
            rx_datagram_state = SEEN_HEADER20;
break;
        }

The following data is also available in the same way, but you have to judge carefully, otherwise you will make mistakes

case SEEN_HEADER20:
        {
           uint8_t TIME[6];
           for(int i=0;i<=5;i++)
{
TIME[i]=*buff + + ;
\t\t\t\t\t\t
}
            date.YEAR[0]=TIME[0];
date.YEAR[1]=TIME[1];
date.Mon[0]=TIME[2];
date.Mon[1]=TIME[3];
date.DAY[0]=TIME[4];
date.DAY[1]=TIME[5];
printf("Date:%c%c.%c%c.%c%c\r\\
",TIME[4],TIME[5],TIME[2],TIME[3],TIME [0],TIME[1]);
            rx_datagram_state = SEEN_HEADER21;
break;
        }

\t\t\t\t
        case SEEN_HEADER21:
        {
            command = *buff;
            rx_sum += command;
            rx_datagram_state = SEEN_COMMAND;
printf("data over!");
             //printf("SEEN_COMMAND:%x\r\\
", command);
            buff + + ;
        }
        break;

Pay attention to the date here, because it is reversed. For example, today is 070823. The first time I read it, I thought it was an information problem. After being reminded by the official staff, Xixi, I realized that this data is August 23. 07. The following data is not needed for the time being, so I stopped parsing.

Final result:

Summarize:

1. When the serial port 3 is sent to the serial port 1, it is necessary to debug more, otherwise it is very likely that when the serial port is opened, there is nothing.

2. Be patient in the process of parsing, and pay attention to the order of buffs, otherwise it is very likely that the reading will be misplaced or the data will not be displayed.

3. You can convert UTC time to Beijing time later by adding algorithm functions.

4. Only one RMC information is parsed, you can write more parsing functions to parse out GGA and GSV.