Bootstrap

STM32H743串口同时收发问题总结

        先是只使用串口中断接收,接收时我的接收逻辑遇到一次问题,就是HAL_UART_Receive();与HAL_UART_Receive_IT();函数的使用问题,可以参考我第一篇文章,已经解决。

        这次是使用同一个串口进行发送和接收:就是通过串口给舵机发特定字节采集舵机的相关参数。涉及串口同时收发,出现问题:串口要么不进入接收中断,要么不发送,要么卡死都不进行~

        通过csdn知道了大概的问题:

HAL_UART_Receive_IT(&Uart2_Handle,(uint8_t *)ces, 1);

HAL_UART_Transmit( &Uart3_Handle, &data ,1,1000);

HAL_UART_Transmit_IT();

HAL_UART_Receive();

        以上函数在调用时会对串口进行上锁,是导致问题出现的原因;

        于是有了第一种解决方案:将以上函数里的自锁函数全部注释掉,很不幸这个方法对我不起作用,具体做法参考如下文章:

​​​​​​(3条消息) STM32 F103串口同时收发出现死锁问题解决办法_弄潮儿的博客-CSDN博客_stm32串口同时收发出现丢包

        以上函数定义在 stm32h7xx_hal_uart.c 文件里。

       

         第二种解决方案是在接收或者发送时不使用hal库的相关函数而是像stm32f103一样直接对寄存器进行操作,当然寄存器看起来很麻烦,我们只需要找到与中断接收和发送相关的两个寄存器即可,很幸运我在博客上查到一篇文章,博主遇到了相同的问题并且解决思路也和我的一致,甚至博主将寄存器找出来了还找到了需要清除的标志位:

(3条消息) STM32H743 解决串口同时收发遇到的问题_ShineRoyal-CSDN博客_stm32h743 串口中断接收

        总结思路:重新定义串口字节发送函数,不采用hal库原来的函数,采用寄存器的操作方法;中断接收也不采用库的接收函数而通过判断标志位,直接对寄存器进行读取然后清空标志位,再重新使能中断。

        相关配置:bsp_usart.c文件:

#include "bsp_usart.h"
UART_HandleTypeDef Uart6_Handle;
void UART6_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;

	RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;
			
	UART6_RX_GPIO_CLK_ENABLE();
	UART6_TX_GPIO_CLK_ENABLE();
	
	/* 配置串口6时钟源*/
	RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART6;
	RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2;
	HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);
	/* 使能 UART6 时钟 */
	UART6_CLK_ENABLE();

	/**USART6 GPIO Configuration    
    PC6    ------> USART6_TX
    PC7    ------> USART6_RX 
	*/
	/* 配置Tx引脚为复用功能  */
	GPIO_InitStruct.Pin = UART6_TX_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStruct.Alternate = UART6_TX_AF;
	HAL_GPIO_Init(UART6_TX_GPIO_PORT, &GPIO_InitStruct);
	
	/* 配置Rx引脚为复用功能 */
	GPIO_InitStruct.Pin = UART6_RX_PIN;
	GPIO_InitStruct.Alternate = UART6_RX_AF;
	HAL_GPIO_Init(UART6_RX_GPIO_PORT, &GPIO_InitStruct); 
	
	/* 配置串USART6 模式 */
	Uart6_Handle.Instance = UART6;
	Uart6_Handle.Init.BaudRate=115200;
	Uart6_Handle.Init.WordLength = UART_WORDLENGTH_8B;
	Uart6_Handle.Init.StopBits = UART_STOPBITS_1;
	Uart6_Handle.Init.Parity = UART_PARITY_NONE;
	Uart6_Handle.Init.Mode = UART_MODE_TX_RX;
/*
    Uart6_Handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    Uart6_Handle.Init.OverSampling = UART_OVERSAMPLING_16;
    Uart6_Handle.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
    Uart6_Handle.AdvancedInit.AdvFeatureInit=UART_ADVFEATURE_NO_INIT;
   */

	HAL_UART_Init(&Uart6_Handle);
	//__HAL_UART_ENABLE(&UartHandle);
	/*串口6中断初始化 */
    HAL_NVIC_SetPriority(UART6_IRQ, 0, 1);
    HAL_NVIC_EnableIRQ(UART6_IRQ);
    /*配置串口接收中断 */
    __HAL_UART_ENABLE_IT(&Uart6_Handle,UART_IT_RXNE); //关键

}


//定义发送函数:

unsigned char UART6_Putc(unsigned char data)		
{
	Uart6_Handle.Instance->TDR = data;
		while (__HAL_UART_GET_FLAG(&Uart6_Handle, UART_FLAG_TC) == RESET);
//	HAL_UART_Transmit(&Uart6_Handle, &data ,1,100);
	return data;
}

bsp_usart.h文件:

        我直接将串口1~6的引脚以及相关模式都在里面配置好了,之后移植时直接对串口6的配置进行复制然后修改数字就好。

#ifndef __USARTx_H
#define	__USARTx_H

#include "stm32h7xx.h"
#include <stdio.h>

//引脚定义
///*******************************************************/
USART1:PA9  PA10
//#define UARTx                             USART1
//#define UARTx_CLK_ENABLE()                __USART1_CLK_ENABLE();

//#define RCC_PERIPHCLK_UARTx               RCC_PERIPHCLK_USART1
//#define RCC_UARTxCLKSOURCE_SYSCLK         RCC_USART1CLKSOURCE_SYSCLK

//#define UARTx_RX_GPIO_PORT                GPIOA
//#define UARTx_RX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOA_CLK_ENABLE()
//#define UARTx_RX_PIN                      GPIO_PIN_9
//#define UARTx_RX_AF                       GPIO_AF7_USART1


//#define UARTx_TX_GPIO_PORT                GPIOA
//#define UARTx_TX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOA_CLK_ENABLE()
//#define UARTx_TX_PIN                      GPIO_PIN_10
//#define UARTx_TX_AF                       GPIO_AF7_USART1

//#define UARTx_IRQHandler                  USART1_IRQHandler
//#define UARTx_IRQ                 		    USART1_IRQn
///************************************************************/

/*******************************************************/
//USART1:TX:PA9  RX:PA10
#define UART1                             USART1
#define UART1_CLK_ENABLE()                __USART1_CLK_ENABLE();

#define RCC_PERIPHCLK_UART1               RCC_PERIPHCLK_USART1
#define RCC_UART1CLKSOURCE_SYSCLK         RCC_USART1CLKSOURCE_SYSCLK

#define UART1_RX_GPIO_PORT                GPIOA
#define UART1_RX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOA_CLK_ENABLE()
#define UART1_RX_PIN                      GPIO_PIN_9
#define UART1_RX_AF                       GPIO_AF7_USART1


#define UART1_TX_GPIO_PORT                GPIOA
#define UART1_TX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOA_CLK_ENABLE()
#define UART1_TX_PIN                      GPIO_PIN_10
#define UART1_TX_AF                       GPIO_AF7_USART1

#define UART1_IRQHandler                  USART1_IRQHandler
#define UART1_IRQ                 		    USART1_IRQn
/************************************************************/
/*******************************************************/
//USART2:TX:PA2  RX:PA3
#define UART2                             USART2
#define UART2_CLK_ENABLE()                __USART2_CLK_ENABLE();

#define RCC_PERIPHCLK_UART2               RCC_PERIPHCLK_USART2
#define RCC_UART2CLKSOURCE_SYSCLK         RCC_USART2CLKSOURCE_SYSCLK

#define UART2_RX_GPIO_PORT                GPIOA
#define UART2_RX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOA_CLK_ENABLE()
#define UART2_RX_PIN                      GPIO_PIN_3
#define UART2_RX_AF                       GPIO_AF7_USART2


#define UART2_TX_GPIO_PORT                GPIOA
#define UART2_TX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOA_CLK_ENABLE()
#define UART2_TX_PIN                      GPIO_PIN_2
#define UART2_TX_AF                       GPIO_AF7_USART2

#define UART2_IRQHandler                  USART2_IRQHandler
#define UART2_IRQ                 		    USART2_IRQn
/************************************************************/
/*******************************************************/
//USART3:TX:PC10  RX:PC11
#define UART3                             USART3
#define UART3_CLK_ENABLE()                __USART3_CLK_ENABLE();

#define RCC_PERIPHCLK_UART3               RCC_PERIPHCLK_USART3
#define RCC_UART3CLKSOURCE_SYSCLK         RCC_USART3CLKSOURCE_SYSCLK

#define UART3_RX_GPIO_PORT                GPIOC
#define UART3_RX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOC_CLK_ENABLE()
#define UART3_RX_PIN                      GPIO_PIN_11
#define UART3_RX_AF                       GPIO_AF7_USART3


#define UART3_TX_GPIO_PORT                GPIOC
#define UART3_TX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOC_CLK_ENABLE()
#define UART3_TX_PIN                      GPIO_PIN_10
#define UART3_TX_AF                       GPIO_AF7_USART3

#define UART3_IRQHandler                  USART3_IRQHandler
#define UART3_IRQ                 		    USART3_IRQn
/************************************************************/


/*******************************************************/
//UART4:TX:PB9  RX:PB8
#define USART4                             UART4
#define UART4_CLK_ENABLE()                __UART4_CLK_ENABLE();

#define RCC_PERIPHCLK_USART4               RCC_PERIPHCLK_UART4
#define RCC_UART4CLKSOURCE_SYSCLK         RCC_UART4CLKSOURCE_SYSCLK

#define UART4_RX_GPIO_PORT                GPIOB
#define UART4_RX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOB_CLK_ENABLE()
#define UART4_RX_PIN                      GPIO_PIN_8
#define UART4_RX_AF                       GPIO_AF8_UART4


#define UART4_TX_GPIO_PORT                GPIOB
#define UART4_TX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOB_CLK_ENABLE()
#define UART4_TX_PIN                      GPIO_PIN_9
#define UART4_TX_AF                       GPIO_AF8_UART4

#define UART4_IRQHandler                  UART4_IRQHandler
#define UART4_IRQ                 		    UART4_IRQn
/************************************************************/
/*******************************************************/
//USART6:TX:PC6  RX:PC7
#define UART6                             USART6
#define UART6_CLK_ENABLE()                __USART6_CLK_ENABLE();

#define RCC_PERIPHCLK_UART6               RCC_PERIPHCLK_USART6
#define RCC_UART6CLKSOURCE_SYSCLK         RCC_USART6CLKSOURCE_SYSCLK

#define UART6_RX_GPIO_PORT                GPIOC
#define UART6_RX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOC_CLK_ENABLE()
#define UART6_RX_PIN                      GPIO_PIN_7
#define UART6_RX_AF                       GPIO_AF7_USART6


#define UART6_TX_GPIO_PORT                GPIOC
#define UART6_TX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOC_CLK_ENABLE()
#define UART6_TX_PIN                      GPIO_PIN_6
#define UART6_TX_AF                       GPIO_AF7_USART6

#define UART6_IRQHandler                  USART6_IRQHandler
#define UART6_IRQ                 		    USART6_IRQn
/************************************************************/


extern UART_HandleTypeDef Uart1_Handle;
extern UART_HandleTypeDef Uart2_Handle;
extern UART_HandleTypeDef Uart3_Handle;
extern UART_HandleTypeDef Uart4_Handle;
extern UART_HandleTypeDef Uart5_Handle;
extern UART_HandleTypeDef Uart6_Handle;

void UART1_Config(void);
void UART2_Config(void);
void UART3_Config(void);
void UART4_Config(void);
void UART6_Config(void);

int fputc(int ch, FILE *f);
int fgetc(FILE *f);

void foot_key_config(void);
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);

void Usart_SendArray(UART_HandleTypeDef *pUSARTx, uint8_t *array, uint16_t num);

unsigned char UART1_Putc(unsigned char data);
unsigned char Uart1_Put_Int16(unsigned int DataToSend);
unsigned char UART2_Putc(unsigned char data);		
unsigned char UART4_Putc(unsigned char data);
unsigned char UART3_Putc(unsigned char data);	
unsigned char UART6_Putc(unsigned char data);



#endif /* __USART1_H */

串口中断服务函数:stm32h7xx_hal.c

        直接写在 stm32h7xx_hal.c文件里面;通过中断服务函数进行接收与逻辑处理,不需要调用回调函数。

        关键点1是将接收函数换成了对RDR寄存器的处理:

        Uart6_Handle.Instance->RDR;//寄存器接收一个字节

        接收触发的条件是判断标志位  UART_FLAG_RXNE与UART_IT_RXNE,需要用相关函数(见如下代码)

        关键点2 是清楚标志位,在接收一个字节后全给他置零。

        关键点3是重新使能中断:

        __HAL_UART_ENABLE_IT(&Uart6_Handle, UART_IT_RXNE);    //使能接收中断

#include "stm32h7xx_it.h"
#include "stm32h7xx_hal.h"
#include "bsp.h"
#include "bsp_basic_tim.h"
//-------------------------串口6接收中断--------------------------------------------------//

float PI=3.1415926;  
float YAW=0,ROLL=0,PITCH=0;
unsigned char SHU[41]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};  //接收缓存
//unsigned char SHU[41]={0};  //接收缓存

uint8_t nn1=39; //接收数据长度


typedef union
{
	unsigned char Receive_Val[3];
	float Act_val;
}u8toointt;
u8toointt yaw,roll,pitch;


void UART6_IRQHandler(void)
{//static
unsigned char ch;
	static unsigned char i = 0; 	//记录数据个数
	static unsigned char j = 0; 
	static unsigned char conunt=0; // 接收记录
	
//判断是否有中断产生	
    if ((__HAL_UART_GET_FLAG(&Uart6_Handle, UART_FLAG_RXNE) != RESET) &&
            (__HAL_UART_GET_IT_SOURCE(&Uart6_Handle, UART_IT_RXNE) != RESET))
    {

	ch=Uart6_Handle.Instance->RDR;//寄存器接收一个字节
		switch(conunt)
		{
			case 0:
				if(ch == 0xFF) conunt++;
				else conunt=0;    
				break;
			case 1:
				if(ch == 0x02) conunt ++; //角度包			
				else conunt = 0;
				break;
			case 2://角度包
				SHU[i] = ch;
				i++;
				if(i==41)//接收完成了开始验证;
				{
						if((SHU[39] ==(calcCRC(SHU,nn1)>>8))&&(SHU[40] ==(calcCRC(SHU,nn1)&0xFF))) //判断是否满足校验条件
						{
							for(j=0;j<=3;j++) //roll角度换算:弧度换算成角度
							{
								roll.Receive_Val[j]=SHU[3+j] ;
							}
							 ROLL=roll.Act_val*180/PI;
							
							for(j=0;j<=3;j++) //pitch角度换算:弧度换算成角度
							{
								pitch.Receive_Val[j]=SHU[7+j] ;
							}
							PITCH=pitch.Act_val*180/PI;
							
							for(j=0;j<=3;j++)//yaw角度换算,弧度换算成角度
							{
								yaw.Receive_Val[j]=SHU[11+j] ;
							}
							YAW=yaw.Act_val*180/PI;
							conunt ++;
					 } 
					 else conunt = 0;					
					i = 0;
				}
				break;
			case 3:
				if(ch == 0x03) 	
				{
					conunt = 0; //结束	
				}	
				else conunt = 0;
				break;
		}	
	}
		else //标注位清零
    {
        if (__HAL_UART_GET_FLAG(&Uart6_Handle, UART_FLAG_ORE) != RESET)
        {
            __HAL_UART_CLEAR_OREFLAG(&Uart6_Handle);
        }
        if (__HAL_UART_GET_FLAG(&Uart6_Handle, UART_FLAG_NE) != RESET)
        {
            __HAL_UART_CLEAR_NEFLAG(&Uart6_Handle);
        }
        if (__HAL_UART_GET_FLAG(&Uart6_Handle, UART_FLAG_FE) != RESET)
        {
            __HAL_UART_CLEAR_FEFLAG(&Uart6_Handle);
        }
        if (__HAL_UART_GET_FLAG(&Uart6_Handle, UART_FLAG_PE) != RESET)
        {
            __HAL_UART_CLEAR_PEFLAG(&Uart6_Handle);
        }
        if (__HAL_UART_GET_FLAG(&Uart6_Handle, UART_FLAG_CTS) != RESET)
        {
            __HAL_UART_CLEAR_IT(&Uart6_Handle, UART_FLAG_CTS);
        }
        if (__HAL_UART_GET_FLAG(&Uart6_Handle, UART_FLAG_TXE) != RESET)
        {
            __HAL_UART_CLEAR_IT(&Uart6_Handle, UART_FLAG_TXE);
        }
        if (__HAL_UART_GET_FLAG(&Uart6_Handle, UART_FLAG_TC) != RESET)
        {
            __HAL_UART_CLEAR_IT(&Uart6_Handle, UART_FLAG_TC);
        }
        if (__HAL_UART_GET_FLAG(&Uart6_Handle, UART_FLAG_RXNE) != RESET)
        {
            __HAL_UART_CLEAR_IT(&Uart6_Handle, UART_FLAG_RXNE);
        }
    }
		__HAL_UART_ENABLE_IT(&Uart6_Handle, UART_IT_RXNE);	//使能接收中断

}
     

        移植方法:将代码里switch-case语句替换为你的接收处理逻辑即可。

        附中断服务函数里的crc校验代码:

signed short int calcCRC (const unsigned char *pBuffer, signed short int bufferSize);//CRC校验

signed short int calcCRC (const unsigned char *pBuffer, signed short int bufferSize)//CRC校验
{

	uint16_t poly = 0x8408;
	uint16_t crc = 0;
	unsigned char carry;
	unsigned char i_bits;
	static uint16_t j;
	for (j=0; j<bufferSize; j++)
	{
			crc = crc ^ pBuffer[j] ;
			for (i_bits=0; i_bits<8; i_bits++)
			{
					carry = crc & 1;
					crc=crc/2;
					if (carry)
					{
						crc = crc^poly;
					}
			}
	}
	return crc;
}

;