cubeIDE配置STM32串口通信及调试问题
本工程使用STM32F407ZET6
串口部分配置套路基本一致,串口接收中断部分提供两种方式,一种只使用一个标志位记录接收状态,另一种定义结构体,分别记录接收发送状态。
printf函数直接使用无输出,和keil有区别,需要添加重定向。
1.添加printf进行重定向
//在main或串口配置文件中添加如下重定向代码
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#ifdef __GNUC__
/* With GCC, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART3 and Loop until the end of transmission */
HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xFFFF);//此处串口号根据实际变更
return ch;
}
/* USER CODE END PD */
2.串口配置并处理接收数据
方式一数据接收过程:
- 1.串口接收到数据,进入接收中断;
- 2.判断是否已经接收到“0x0A”;
- 3.还没有接收到“0x0A”,判断是否接收到“0x0D”;
- 7.还没有接收到“0x0D”,并且当前接收的数据不是“0x0D”,将当前接收的数据放到接收缓存USART3_RX_BUF,地址为前一次结束指向的地址,变量USART3_RX_STA加1,表示接收的字节数加1 ;
- 8.判断如果变量USART3_RX_STA已经超过自定义的最大接收长度(0d,0a不会进入此判断),将此变量清零,接收数据效;
- 9.继续开启接收中断,新数据存放在USART3_NEW_DATA中;
-------以上循环接收正常数据--------
------以下开始接收“0x0D”,“0x0A”---------
-
-
-
- 6.还没有接收到“0x0D”,如果当前接收的数据是“0x0D”,将变量USART3_RX_STA[14]位置1,接收的字节数[13:0]保持不变;
-
-
-
-
- 4.已经接收到“0x0D”,如果本次接收数据不是“0x0A”,将变量USART3_RX_STA清零,接收错误数据无效。
or - 5.已经接收到“0x0D”,如果本次接收数据是“0x0A”,将变量USART3_RX_STA[15]位置1,表示数据全部接收完成。
由此可以知道变量USART3_RX_STA[15:0]位各个数据位的含义:
USART3_RX_STA[15] = 1 — 接收数据“0x0A”;
USART3_RX_STA[14] = 1 — 接收数据“0x0D”;
USART3_RX_STA[13:0] — 累计接收到非“0x0D”,“0x0A”数据个数,即最多0x3FFF个数据。
void MX_USART3_UART_Init(void)
{
/* USER CODE BEGIN USART3_Init 0 */
/* USER CODE END USART3_Init 0 */
/* USER CODE BEGIN USART3_Init 1 */
/* USER CODE END USART3_Init 1 */
huart3.Instance = USART3;
huart3.Init.BaudRate = 115200;
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(&huart3) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART3_Init 2 */
HAL_UART_Receive_IT(&huart3, (uint8_t *)&USART3_NEW_DATA, 1); //此处加入uart3开始中断接收
/* USER CODE END USART3_Init 2 */
}
//添加回调函数,产生中断进入此回调函数,不进入微(weak)回调函数
uint8_t USART3_RX_BUF[USART3_REC_LEN];
uint16_t USART3_RX_STA = 0;//记录接收状态:0a+0d+数据个数
uint8_t USART3_NEW_DATA;//当前中断接收的一个字节缓存
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart3)//1.判断中断源
{
printf("%c",USART3_NEW_DATA);
if((USART3_RX_STA & 0x8000) == 0)//2.
{
if(USART3_RX_STA & 0x4000)//3.
{
if(USART3_NEW_DATA != 0x0a)//4.
USART3_RX_STA = 0;
else
USART3_RX_STA |= 0x8000;//5.
}
else
{
if(USART3_NEW_DATA == 0x0d)//6.
USART3_RX_STA |= 0x4000;
else
{
USART3_RX_BUF[USART3_RX_STA & 0x3fff] = USART3_NEW_DATA;//7.
USART3_RX_STA ++;
if(USART3_RX_STA > (USART3_REC_LEN - 1))//8.
USART3_RX_STA=0;
}
}
}
HAL_UART_Receive_IT(&huart3, (uint8_t *)&USART3_NEW_DATA, 1);//9.
}
}
//处理接收数据
void receive_command(void)
{
if(USART3_RX_STA & 0x8000)
{
USART3_RX_BUF[USART3_RX_STA & 0x3fff] = 0;
printf("USART3_RX_BUF[0]=%02X\r\n",USART3_RX_BUF[0]);
printf("USART3_RX_BUF[1]=%02X\r\n",USART3_RX_BUF[1]);
printf("USART3_RX_BUF[2]=%02X\r\n",USART3_RX_BUF[2]);
printf("USART3_RX_BUF[3]=%02X\r\n",USART3_RX_BUF[3]);
printf("USART3_RX_BUF[4]=%02X\r\n",USART3_RX_BUF[4]);
printf("USART3_RX_BUF[5]=%02X\r\n",USART3_RX_BUF[5]);
if(strcmp(USART3_RX_BUF,"on")==0) //字符串对比
LED_Switch(0);
else if(strcmp(USART3_RX_BUF,"off")==0) //字符串对比
LED_Switch(1);
USART3_RX_STA = 0;
}
方式二相较于方式一更直观,不再描述其执行流程:
//配置方面相同,添加回调函数
UART_TypeDef uart3; //结构体变量
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart3)//判断中断源
{
printf("%c",uart3.rx);
if(uart3.rxComplete == 0)
{
uart3.rxBuffer[uart3.rxPoint] = uart3.rx;
if(uart3.rxPoint < UART_RX_SIZE)
{
uart3.rxPoint++;
}
if(uart3.rx != 0x0A)
{
// HAL_UART_Receive_IT(&huart3, &uart3.rx, 1);
}
else
{
uart3.rxComplete = 1;
}
}
HAL_UART_Receive_IT(&huart3, &uart3.rx, 1);
}
}
//库函数添加定义及结构体
#define USART3_REC_LEN 20
#define UART_RX_SIZE 20
#define UART_TX_SIZE 20
extern UART_TypeDef uart3;
typedef struct
{
volatile uint8_t rxComplete; //接收完成标志位1=完成
volatile uint8_t txComplete; //发送完成标志位1=完成
volatile uint16_t rxPoint; //接收指针
volatile uint8_t rxinterval; //最后一个接收字符的间隔时间
uint8_t rx; //当前接收内容
uint8_t rxBuffer[UART_RX_SIZE]; //接收buffer
uint8_t txBuffer[UART_TX_SIZE]; //发送buffer
}UART_TypeDef;
//字符串比较
uint8_t String_Compare(uint8_t *buffer1,const char *buffer2,uint8_t count)
{
uint8_t B1 = 0;
uint8_t B2 = 0;
while(count--)
{
B1 = tolower(*buffer1);
B2 = tolower(*buffer2);
if(B1==B2)
{
buffer1++;
buffer2++;
}
else break;
}
return (B1-B2);
}
//处理接收数据
void receive_command(void)
{
if(uart3.rxComplete == 1)
{
uart3.rxBuffer[uart3.rxPoint] = 0;
printf("uart3.rxBuffer[0]=%02X\r\n",uart3.rxBuffer[0]);
printf("uart3.rxBuffer[1]=%02X\r\n",uart3.rxBuffer[1]);
printf("uart3.rxBuffer[2]=%02X\r\n",uart3.rxBuffer[2]);
printf("uart3.rxBuffer[3]=%02X\r\n",uart3.rxBuffer[3]);
printf("uart3.rxBuffer[4]=%02X\r\n",uart3.rxBuffer[4]);
printf("uart3.rxBuffer[5]=%02X\r\n",uart3.rxBuffer[5]);
if(String_Compare(uart3.rxBuffer,"on",strlen("on"))==0) //字符串对比
LED_Switch(0);
else if(String_Compare(uart3.rxBuffer,"off",strlen("off"))==0) //字符串对比
LED_Switch(1);
uart3.rxComplete = 0;
uart3.rxPoint = 0;
}
}
3.调试问题
cubeIDE中出现中文乱码或者使用printf函数输出中文时,串口调试助手接收到乱码,可在Project -> Properties -> Resource -> Text file encoding中选择Other选项,并在下拉框中输入GBK(下拉选项中可能没有该选项,可直接输入):