先是只使用串口中断接收,接收时我的接收逻辑遇到一次问题,就是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;
}