まず、シリアル ポートは受信を中断するためにのみ使用します。受信時に、受信ロジックで問題が発生しました。つまり、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 シリアル ポートが同時に送受信するデッドロック問題の解決策
上記の関数は stm32h7xx_hal_uart.c ファイルで定義されています。
2つ目の解決策は、送受信時にhalライブラリの関連関数を使わずに、stm32f103のようなレジスタを直接操作する方法です、もちろんレジスタは面倒ですが、割り込み受信と送信に関係するレジスタを2つ見つけるだけで済みます。幸いなことに、私はブログで記事を見つけました。ブロガーも同じ問題に遭遇し、解決策は私と同じでした。ブロガーはレジスタを見つけ出し、クリアする必要があるフラグも見つけました。
アイデアのまとめ:シリアルポートのバイト送信関数を再定義し、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;
}