【六足机器人】01功能开发

包含:WIFI模块、GPS模块、语言模块、调试信息接口。

一、硬件连接

huart4( PA0、 PA1 )与GPS模块连接。

huart3(PB10、PB11)与ESP8266模块连接。

huart2( PA2、 PA3 )与语音模块连接。

huart1(PB14、PB15)与PC端连接,用于打印调试信息。

二、串口配置代码

2.1 开启中断:

开启串口的接收中断 or 空闲中断。

cpp 复制代码
	/* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */
  HAL_UART_Receive_IT(&huart1, (uint8_t *)g_rx_buffer, 1);

  // __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
	// HAL_UART_Receive_DMA(&huart3,(uint8_t*)ATCmdRxBuffer,ATCmdRxBuffe_MAX_SIZE); //重新启动DMA接收

  __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);	//使能IDLE中断	
	HAL_UART_Receive_DMA(&huart2, voiceBuf, voiceBuf_MAX_SIZE);
//HAL_UART_Receive_DMA(&huart3, (uint8_t *)g_rx_buffer, 1);
  __HAL_UART_ENABLE_IT(&huart3, UART_IT_RXNE);                          /* 使能UART接收中断 */
  __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);                          /* 使能UART总线空闲中断 */
2.2 中断函数:
cpp 复制代码
/* USER CODE BEGIN 1 */

void HAL_UART_MyIdleCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART2)
  {
    Voice_Length = voiceBuf_MAX_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);
    flag_voice = 1; // 设置接收完成标志
  }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) // 串口接收完成中断回调函数
{
  if (huart->Instance == USART1)                      /* 如果是串口1 */
  {
    if ((myHexapodRx.recv_end_flag & 0x8000) == 0)    /* 接收未完成    1000 0000 0000 0000 */ 
    {
      if (myHexapodRx.recv_end_flag & 0x4000)         /* 接收到了0x0D /r  0100 0000 0000 0000 */
      {
        if (g_rx_buffer[0] != 0x0a)      /* \n 0x0A*/
        {
          myHexapodRx.recv_end_flag = 0;              /*  接收错误,重新开始 */
        }
        else
        {
          myHexapodRx.recv_end_flag |= 0x8000;        /* 接收完成了 */
        }
      }
      else                                            /* 还没收到0X0D */
      {
        if (g_rx_buffer[0] == 0x0d)
        {
          myHexapodRx.recv_end_flag |= 0x4000;
        } 
        else
        {                                          //0011 1111 1111 1111
          myHexapodRx.HexapodRxBuf[myHexapodRx.recv_end_flag & 0X3FFF] = g_rx_buffer[0];
          myHexapodRx.recv_end_flag++;
          if (myHexapodRx.recv_end_flag > (HexapodRxBuf_MAX_SIZE - 1))
          {
            myHexapodRx.recv_end_flag = 0;            /* 接收数据错误,重新开始接收 */
          }
        }
      }
    }
    HAL_UART_Receive_IT(&huart1, (uint8_t *)g_rx_buffer, 1);
  }
	
	
  if (huart->Instance == USART2)
  {
    HAL_UART_Receive_DMA(&huart2, (uint8_t *)voiceBuf, voiceBuf_MAX_SIZE);
  }

三、功能模块

3.1 ESP8266模块

3.1.1 atk_ESP8266D
atk_mw8266d_usart.c
cpp 复制代码
#include "atk_mw8266d_usart.h"
#include "usart.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

g_uart_rx_frame myATCmdRx = {0};

static uint8_t g_uart_tx_buf[ATK_MW8266D_UART_TX_BUF_SIZE]; /* ATK-MW8266D UART发送缓冲 */

/**
 * @brief       ATK-MW8266D UART printf
 * @param       fmt: 待发送的数据
 * @retval      无
 */
void atk_mw8266d_uart_printf(char *fmt, ...)
{
    va_list ap;
    uint16_t len;
    
    va_start(ap, fmt);
    vsprintf((char *)g_uart_tx_buf, fmt, ap);
    va_end(ap);
    
    len = strlen((const char *)g_uart_tx_buf);
    HAL_UART_Transmit(&g_uart_handle, g_uart_tx_buf, len, HAL_MAX_DELAY);
    //HAL_UART_Transmit_IT(&g_uart_handle, g_uart_tx_buf, sizeof(g_uart_tx_buf));
}

/**
 * @brief       ATK-MW8266D UART重新开始接收数据
 * @param       无
 * @retval      无
 */
void atk_mw8266d_uart_rx_restart(void)
{
    myATCmdRx.sta.len     = 0;
    myATCmdRx.sta.finsh   = 0;
}

/**
 * @brief       获取ATK-MW8266D UART接收到的一帧数据
 * @param       无
 * @retval      NULL: 未接收到一帧数据
 *              其他: 接收到的一帧数据
 */
uint8_t *atk_mw8266d_uart_rx_get_frame(void)
{
    if (myATCmdRx.sta.finsh == 1)
    {
        myATCmdRx.buf[myATCmdRx.sta.len] = '\0';
        //printf("接收到的数据: %s\r\n", myATCmdRx.buf);
        return myATCmdRx.buf;        
    }
    else
    {
        return NULL;
    }
}

/**
 * @brief       获取ATK-MW8266D UART接收到的一帧数据的长度
 * @param       无
 * @retval      0   : 未接收到一帧数据
 *              其他: 接收到的一帧数据的长度
 */
uint16_t atk_mw8266d_uart_rx_get_frame_len(void)
{
    if (myATCmdRx.sta.finsh == 1)
    {
        return myATCmdRx.sta.len;
    }
    else
    {
        return 0;
    }
}

/**
 * @brief       ATK-MW8266D UART初始化
 * @param       baudrate: UART通讯波特率
 * @retval      无
 */
void atk_mw8266d_uart_init(uint32_t baudrate)
{
    g_uart_handle.Instance          = ATK_MW8266D_UART_INTERFACE;   /* ATK-MW8266D UART */
    g_uart_handle.Init.BaudRate     = baudrate;                     /* 波特率 */
    g_uart_handle.Init.WordLength   = UART_WORDLENGTH_8B;           /* 数据位 */
    g_uart_handle.Init.StopBits     = UART_STOPBITS_1;              /* 停止位 */
    g_uart_handle.Init.Parity       = UART_PARITY_NONE;             /* 校验位 */
    g_uart_handle.Init.Mode         = UART_MODE_TX_RX;              /* 收发模式 */
    g_uart_handle.Init.HwFlowCtl    = UART_HWCONTROL_NONE;          /* 无硬件流控 */
    g_uart_handle.Init.OverSampling = UART_OVERSAMPLING_16;         /* 过采样 */
    HAL_UART_Init(&g_uart_handle);                                  /* 使能ATK-MW8266D UART
                                                                     * HAL_UART_Init()会调用函数HAL_UART_MspInit()
                                                                     * 该函数定义在文件usart.c中
                                                                     */
}

/**
 * @brief       ATK-MW8266D UART中断回调函数
 * @param       无
 * @retval      无
 */
void ATK_MW8266D_UART_IRQHandler(void)
{
    uint8_t tmp;
    
    if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_ORE) != RESET)        /* UART接收过载错误中断 */
    {
        __HAL_UART_CLEAR_OREFLAG(&g_uart_handle);                           /* 清除接收过载错误中断标志 */
        (void)g_uart_handle.Instance->ISR;                                  /* I先读SR寄存器,再读RDR寄存器 */
        (void)g_uart_handle.Instance->RDR;
    }
    
    if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_RXNE) != RESET)       /* UART接收中断 */
    {
		HAL_UART_Receive(&g_uart_handle, &tmp, 1, 1000);          /* UART接收数据 */
        
        if (myATCmdRx.sta.len < (ATK_MW8266D_UART_RX_BUF_SIZE - 1))   /* 判断UART接收缓冲是否溢出
                                                                             * 留出一位给结束符'\0'
                                                                             */
        {
            myATCmdRx.buf[myATCmdRx.sta.len] = tmp;             /* 将接收到的数据写入缓冲 */
            myATCmdRx.sta.len++;                                      /* 更新接收到的数据长度 */
        }
        else                                                                /* UART接收缓冲溢出 */
        {
            myATCmdRx.sta.len = 0;                                    /* 覆盖之前收到的数据 */
            myATCmdRx.buf[myATCmdRx.sta.len] = tmp;             /* 将接收到的数据写入缓冲 */
            myATCmdRx.sta.len++;                                      /* 更新接收到的数据长度 */
        }
    }
    
    if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_IDLE) != RESET)       /* UART总线空闲中断 */
    {
        myATCmdRx.sta.finsh = 1;                                      /* 标记帧接收完成 */
        
        __HAL_UART_CLEAR_IDLEFLAG(&g_uart_handle);                          /* 清除UART总线空闲中断 */
    }
}
atk_mw8266d_usart.h
cpp 复制代码
#ifndef __ATK_MW8266D_UART_H
#define __ATK_MW8266D_UART_H

#include "main.h"

/* 引脚定义 */
#define ATK_MW8266D_UART_TX_GPIO_PORT           GPIOB
#define ATK_MW8266D_UART_TX_GPIO_PIN            GPIO_PIN_10
#define ATK_MW8266D_UART_TX_GPIO_AF             GPIO_AF7_USART2
#define ATK_MW8266D_UART_TX_GPIO_CLK_ENABLE()   do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)     /* PA口时钟使能 */

#define ATK_MW8266D_UART_RX_GPIO_PORT           GPIOB
#define ATK_MW8266D_UART_RX_GPIO_PIN            GPIO_PIN_11
#define ATK_MW8266D_UART_RX_GPIO_AF             GPIO_AF7_USART2
#define ATK_MW8266D_UART_RX_GPIO_CLK_ENABLE()   do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)     /* PA口时钟使能 */

#define ATK_MW8266D_UART_INTERFACE              USART3
#define ATK_MW8266D_UART_IRQn                   USART3_IRQn
//#define ATK_MW8266D_UART_IRQHandler             USART3_IRQHandler
#define ATK_MW8266D_UART_CLK_ENABLE()           do{ __HAL_RCC_USART3_CLK_ENABLE(); }while(0)    /* USART3 时钟使能 */

/* UART收发缓冲大小 */
#define ATK_MW8266D_UART_RX_BUF_SIZE            128
#define ATK_MW8266D_UART_TX_BUF_SIZE            64
#define g_uart_handle   huart3

typedef struct
{
    uint8_t buf[ATK_MW8266D_UART_RX_BUF_SIZE];              /* 帧接收缓冲 */
    struct
    {
        uint16_t len    : 15;                               /* 帧接收长度,sta[14:0] */
        uint16_t finsh  : 1;                                /* 帧接收完成标志,sta[15] */
    } sta;                                                  /* 帧状态信息 */
} g_uart_rx_frame;                                    /* ATK-MW8266D UART接收帧缓冲信息结构体 */

extern g_uart_rx_frame myATCmdRx;


/* 操作函数 */
void atk_mw8266d_uart_printf(char *fmt, ...);       /* ATK-MW8266D UART printf */
void atk_mw8266d_uart_rx_restart(void);             /* ATK-MW8266D UART重新开始接收数据 */
uint8_t *atk_mw8266d_uart_rx_get_frame(void);       /* 获取ATK-MW8266D UART接收到的一帧数据 */
uint16_t atk_mw8266d_uart_rx_get_frame_len(void);   /* 获取ATK-MW8266D UART接收到的一帧数据的长度 */
void atk_mw8266d_uart_init(uint32_t baudrate);      /* ATK-MW8266D UART初始化 */
void ATK_MW8266D_UART_IRQHandler(void);
#endif
3.1.2 myTask_atk8266D
myTask_atk8266D.c
cpp 复制代码
#include "myTask_ATK8266D.h"
#include "atk_mw8266d.h"
#include "usart.h"
#include "main.h"
#include "stdio.h"
#include "string.h"
#include "led.h"

#define DEMO_WIFI_SSID "guilin88"
#define DEMO_WIFI_PWD "12345678"
#define DEMO_TCP_SERVER_IP "192.168.96.95"
#define DEMO_TCP_SERVER_PORT "6688"

void myTask_ATK8266D(void)
{
	uint8_t ret;
	//char ip_buf[16];
	/* 初始化ATK-MW8266D */
	printf("开始连接AP.......\r\n");
	ret = atk_mw8266d_init(115200);
	if (ret != 0)
	{
		printf("ATK-MW8266D init failed!\r\n");
		while (1)
		{
			LED_R_Toggle;
			delay_ms(200);
		}
	}
//	printf("正在恢复出厂设置...\r\n");
//	while (atk_mw8266d_restore())
//	{
//		color_debug();
//	}
	printf("正在进行AT测试...\r\n");
	while (atk_mw8266d_at_test())
	{
		color_debug();
	}
//	printf("正在设置波特率...\r\n");
//	ret = atk_mw8266d_send_at_cmd("AT+UART=115200,8,1,0,0", "OK", 500);
//	while (ret != 0)
//	{
//		color_debug();
//	}
	printf("正在设置Station模式...\r\n");
	while (atk_mw8266d_set_mode(1))
	{
		color_debug();
	}
//	printf("正在进行软件复位...\r\n");
//	while (atk_mw8266d_sw_reset())
//	{
//		color_debug();
//	}
//	printf("关闭回显功能...\r\n");
//	while (atk_mw8266d_ate_config(0))
//	{
//		color_debug();
//	}
	printf("正在连接WIFI...\r\n");
	while (atk_mw8266d_join_ap(DEMO_WIFI_SSID, DEMO_WIFI_PWD))
	{
		printf("Error to connect tcp server! 2秒后重新连接!\r\n");
		color_debug();
	}
//	printf("获取IP地址中...\r\n");
//	while (atk_mw8266d_get_ip(ip_buf))
//	{
//		color_debug();
//	}

//	printf("IP: %s\r\n", ip_buf);

	/* 连接TCP服务器 */
	printf("正在连接TCP服务器...\r\n");
	while (atk_mw8266d_connect_tcp_server(DEMO_TCP_SERVER_IP, DEMO_TCP_SERVER_PORT))
	{
		printf("Error to connect tcp server! 2秒后重新连接!\r\n");
		color_debug();
	}

	/* 进入透传 */
	printf("进入透传...\r\n");
	while (atk_mw8266d_enter_unvarnished())
	{
		color_debug();
	}
	printf("成功进入透传\r\n");

	atk_mw8266d_uart_rx_restart(); // 重新开始接收数据
}
myTask_atk8266D.h
cpp 复制代码
#ifndef _MYTASK_ATK8266D_H
#define _MYTASK_ATK8266D_H

void myTask_ATK8266D(void);

#endif

3.2 GPS模块

3.2.1 ATGM336H
ATGM336H.c
cpp 复制代码
#include "ATGM336H.h"
#include "main.h"
#include "usart.h"
#include "string.h"
#include "stdio.h"

char rxdatabufer;
u16 point1 = 0;

_SaveData Save_Data;
LatitudeAndLongitude_s g_LatAndLongData =
{
	.E_W = 0,
	.N_S = 0,
	.latitude = 0.0,
	.longitude = 0.0
};

// 串口1中断服务程序
// 注意,读取USARTx->SR能避免莫名其妙的错误
char USART_RX_BUF[USART_REC_LEN];	// 接收缓冲,最大USART_REC_LEN个字节.
uint8_t uart_A_RX_Buff;

// 接收状态
// bit15,	接收完成标志
// bit14,	接收到0x0d
// bit13~0,	接收到的有效字节数目
u16 USART_RX_STA=0;	// 接收状态标记

void atgm336h_init(void)
{
	clrStruct();
	HAL_UART_Receive_IT(&huart4, &uart_A_RX_Buff, 1);
}

//GPS中断回调函数,需要放入串口接收中断中
void atgm336h_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == UART4)
	{
//		printf("%c", uart_A_RX_Buff);
		if(uart_A_RX_Buff == '$')
		{
			point1 = 0;
		}
		USART_RX_BUF[point1++] = uart_A_RX_Buff;

		if(USART_RX_BUF[0] == '$' && USART_RX_BUF[4] == 'M' && USART_RX_BUF[5] == 'C')	//确定是否收到"GPRMC/GNRMC"这一帧数据
		{
			if(uart_A_RX_Buff == '\n')
			{
				memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length);      //清空
				memcpy(Save_Data.GPS_Buffer, USART_RX_BUF, point1); 	//保存数据
				Save_Data.isGetData = true;
				point1 = 0;
				memset(USART_RX_BUF, 0, USART_REC_LEN);      //清空
			}
		}
		if(point1 >= USART_REC_LEN)
		{
			point1 = USART_REC_LEN;
		}

		HAL_UART_Receive_IT(&huart4, &uart_A_RX_Buff, 1);
	}
}

u8 Hand(char *a)	// 串口命令识别函数
{
    if(strstr(USART_RX_BUF, a)!=NULL)
	    return 1;
	else
		return 0;
}

void CLR_Buf(void)	// 串口缓存清理
{
	memset(USART_RX_BUF, 0, USART_REC_LEN);	//清空
  point1 = 0;
}

void clrStruct(void)
{
	Save_Data.isGetData = false;
	Save_Data.isParseData = false;
	Save_Data.isUsefull = false;
	memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length);	//清空
	memset(Save_Data.UTCTime, 0, UTCTime_Length);
	memset(Save_Data.latitude, 0, latitude_Length);
	memset(Save_Data.N_S, 0, N_S_Length);
	memset(Save_Data.longitude, 0, longitude_Length);
	memset(Save_Data.E_W, 0, E_W_Length);
}

void errorLog(int num)
{

	while (1)
	{
	  	printf("ERROR%d\r\n",num);
	}
}

void parseGpsBuffer(void)
{
	char *subString;
	char *subStringNext;
	char i = 0;

	uint16_t Number=0, Integer=0, Decimal=0;


	if (Save_Data.isGetData)
	{
		Save_Data.isGetData = false;
		printf("**************\r\n");
		printf("%s\r\n", Save_Data.GPS_Buffer);

		for (i = 0 ; i <= 6 ; i++)
		{
			if (i == 0)
			{
				if ((subString = strstr(Save_Data.GPS_Buffer, ",")) == NULL)
					errorLog(1);	//解析错误
			}
			else
			{
				subString++;
				if ((subStringNext = strstr(subString, ",")) != NULL)
				{
					char usefullBuffer[2];
					switch(i)
					{
						case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break;	//获取UTC时间
						case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break;	//获取UTC时间
						case 3:memcpy(Save_Data.latitude, subString, subStringNext - subString);break;	//获取纬度信息
						case 4:memcpy(Save_Data.N_S, subString, subStringNext - subString);break;	//获取N/S
						case 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break;	//获取经度信息
						case 6:memcpy(Save_Data.E_W, subString, subStringNext - subString);break;	//获取E/W

						default:break;
					}
					subString = subStringNext;
					Save_Data.isParseData = true;
					if(usefullBuffer[0] == 'A')
						Save_Data.isUsefull = true;
					else if(usefullBuffer[0] == 'V')
						Save_Data.isUsefull = false;
				}
				else
				{
					errorLog(2);	//解析错误
				}
			}
		}

		if (Save_Data.isParseData)
		{
			if(Save_Data.isUsefull)
			{
				// 获取 N/S 和 E/W
				g_LatAndLongData.N_S = Save_Data.N_S[0];
				g_LatAndLongData.E_W = Save_Data.E_W[0];

				// 获取纬度
				for(uint8_t i=0; i<9; i++)
				{
					if(i<2)
					{
						Number *= 10;
						Number += Save_Data.latitude[i]-'0';
					}
					else if(i<4)
					{
						Integer *= 10;
						Integer += Save_Data.latitude[i]-'0';
					}
					else if(i==4);
					else if(i<9)
					{
						Decimal *= 10;
						Decimal += Save_Data.latitude[i]-'0';
					}
				}
				g_LatAndLongData.latitude = 1.0*Number + (1.0*Integer+1.0*Decimal/10000)/60;

				Number = 0;
				Integer = 0;
				Decimal = 0;

				// 获取经度
				for(uint8_t i=0; i<10; i++)
				{
					if(i<3)
					{
						Number *= 10;
						Number += Save_Data.longitude[i]-'0';
					}
					else if(i<5)
					{
						Integer *= 10;
						Integer += Save_Data.longitude[i]-'0';
					}
					else if(i==5);
					else if(i<10)
					{
						Decimal *= 10;
						Decimal += Save_Data.longitude[i]-'0';
					}
				}
				g_LatAndLongData.longitude = 1.0*Number + (1.0*Integer+1.0*Decimal/10000)/60;
			}
		}
	}
}

void printGpsBuffer(void)
{
	if (Save_Data.isParseData)
	{
		Save_Data.isParseData = false;

		printf("Save_Data.UTCTime = %s\r\n", Save_Data.UTCTime);

		if(Save_Data.isUsefull)
		{
			Save_Data.isUsefull = false;
			printf("Save_Data.latitude = %s\r\n", Save_Data.latitude);
			printf("Save_Data.N_S = %s", Save_Data.N_S);
			printf("Save_Data.longitude = %s", Save_Data.longitude);
			printf("Save_Data.E_W = %s\r\n", Save_Data.E_W);

			printf("latitude: %c,%.4f\r\n", g_LatAndLongData.N_S, g_LatAndLongData.latitude);
			printf("longitude: %c,%.4f\r\n", g_LatAndLongData.E_W, g_LatAndLongData.longitude);
		}
		else
		{
			printf("GPS DATA is not usefull!\r\n");
		}
	}
}
ATGM336H.h
cpp 复制代码
#ifndef __ATGM336H_H
#define __ATGM336H_H

#include "usart.h"
#include "sys.h"
// #include "stdbool.h"

#define USART_REC_LEN 200 // 定义最大接收字节数 200
#define EN_USART1_RX 1	  // 使能(1)/禁止(0)串口1接收

#define false 0
#define true 1

// 定义数组长度
#define GPS_Buffer_Length 80
#define UTCTime_Length 11
#define latitude_Length 11
#define N_S_Length 2
#define longitude_Length 12
#define E_W_Length 2

typedef struct SaveData
{
	char GPS_Buffer[GPS_Buffer_Length];
	char isGetData;					  // 是否获取到GPS数据
	char isParseData;				  // 是否解析完成
	char UTCTime[UTCTime_Length];	  // UTC时间
	char latitude[latitude_Length];	  // 纬度
	char N_S[N_S_Length];			  // N/S
	char longitude[longitude_Length]; // 经度
	char E_W[E_W_Length];			  // E/W
	char isUsefull;					  // 定位信息是否有效
} _SaveData;

// 经纬度数据
typedef struct _LatitudeAndLongitude_s
{
	float latitude;	 // 纬度
	float longitude; // 经度

	char N_S; // 北南
	char E_W; // 东西
} LatitudeAndLongitude_s;

extern char rxdatabufer;
extern u16 point1;
extern _SaveData Save_Data;
extern LatitudeAndLongitude_s g_LatAndLongData;

void atgm336h_UART_RxCpltCallback(UART_HandleTypeDef *huart);
void atgm336h_init(void); // 初始化
void clrStruct(void); // 清除结构体数据
void parseGpsBuffer(void); // 解包函数
void printGpsBuffer(void); // 打印函数

#endif // __ATGM336H_H
3.2.2 myTask_GPS
myTask_GPS.c
cpp 复制代码
#include "myTask_GPS.h"
#include "stdio.h"
#include "ATGM336H.h"

void myTask_GPS(void){
  atgm336h_init();
  while (1){
	if (Save_Data.isParseData){
		Save_Data.isParseData = false;
		if(Save_Data.isUsefull){
			Save_Data.isUsefull = false;
			printf("latitude: %c,%.4f\r\n", g_LatAndLongData.N_S, g_LatAndLongData.latitude);
			printf("longitude: %c,%.4f\r\n", g_LatAndLongData.E_W, g_LatAndLongData.longitude);
		}
		else{
			printf("GPS DATA is not usefull!\r\n");
		}
	}
	HAL_Delay(30);
  }
}

3.3 语音模块

直接使用串口2接收指令信息。

3.4 串口重定义

支持printf函数,便于打印调试信息到PC端,适配STM32H7系列。其他系列需要查看不同的芯片手册。

cpp 复制代码
/******************************************************************************************/
/* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */

#if 1
#if (__ARMCC_VERSION >= 6010050)           /* 使用AC6编译器时 */
__asm(".global __use_no_semihosting\n\t"); /* 声明不使用半主机模式 */
__asm(".global __ARM_use_no_argv \n\t");   /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */

#else
/* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
#pragma import(__use_no_semihosting)

struct __FILE
{
  int handle;
  /* Whatever you require here. If the only file you are using is */
  /* standard output using printf() for debugging, no file handling */
  /* is required. */
};

#endif

/* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
int _ttywrch(int ch)
{
  ch = ch;
  return ch;
}

/* 定义_sys_exit()以避免使用半主机模式 */
void _sys_exit(int x)
{
  x = x;
}

char *_sys_command_string(char *cmd, int len)
{
  return NULL;
}

/* FILE 在 stdio.h里面定义. */
FILE __stdout;

/* 重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
int fputc(int ch, FILE *f)
{
  while ((USART1->ISR & 0X40) == 0); /* 等待上一个字符发送完成 */
  USART1->TDR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */
  return ch;
}
#endif
/***********************************************END*******************************************/
相关推荐
小林熬夜学编程1 小时前
【Linux网络编程】第十四弹---构建功能丰富的HTTP服务器:从状态码处理到服务函数扩展
linux·运维·服务器·c语言·网络·c++·http
Jackey_Song_Odd1 小时前
C语言 单向链表反转问题
c语言·数据结构·算法·链表
A懿轩A2 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
半盏茶香3 小时前
在21世纪的我用C语言探寻世界本质 ——编译和链接(编译环境和运行环境)
c语言·开发语言·c++·算法
字节高级特工4 小时前
【C++】深入剖析默认成员函数3:拷贝构造函数
c语言·c++
计算机学长大白5 小时前
C中设计不允许继承的类的实现方法是什么?
c语言·开发语言
yutian06068 小时前
Keil MDK下载程序后MCU自动重启设置
单片机·嵌入式硬件·keil
XH华10 小时前
初识C语言之二维数组(下)
c语言·算法
析木不会编程11 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
Uu_05kkq13 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法