首先感谢各位朋友们的帮助,白天在论坛里问的关于UART中断发送数据丢失问题的帖子。晚上有查了代码,看了HAL库代码和帮助文档,还有串口工具等问题,最终把问题解决了,把心得给大家分享一下。
关于问题,详细描述,可以看我的帖子:
【Nucleo-F303RE开发】关于UART中断发送丢失数据问题请教
------------------------------------------------------------------
今天写了一个UART的HAL库中断发送数据的程序,本来要发送两个字符串,但是串口发送时只输出了1个字符串,请问大家程序出了什么问题,请高手帮助解答。
如图主程序:
每2秒循环发送2个字符串:
但是串口接收的数据只有一个字符串:
主函数我把CUBEMX自动生成的注释给删掉,看着短一些:
#include "stm32f3xx_hal.h"
UART_HandleTypeDef huart2;
#define TXBUFFERSIZE1 COUNTOF(TxBuffer1)
#define TXBUFFERSIZE2 COUNTOF(TxBuffer2)
#define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__)))
static __IO ITStatus UartReady = RESET;
uint8_t TxBuffer1[] = "第一个字符串";
uint8_t TxBuffer2[] = “第二个字符串";
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART2_UART_Init();
while (1)
{
HAL_UART_Transmit_IT(&huart2, (uint8_t *)TxBuffer1, TXBUFFERSIZE1);
while (UartReady != SET)
{
;
}
UartReady = RESET;
HAL_UART_Transmit_IT(&huart2, (uint8_t *)TxBuffer2, TXBUFFERSIZE2);
while (UartReady != SET)
{
;
}
UartReady = RESET;
HAL_Delay(2000);
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInit;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
__SYSCFG_CLK_ENABLE();
}
void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED ;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
HAL_UART_Init(&huart2);
}
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PA5 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
UartReady = SET;
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
UartReady = SET;
}
---------------------------------------------------
一、解决:
其实我写的代码本身没有太大问题,问题出现在我用的串口工具。
1、白天描述的UART连续发2个字符串,但只显示1个字符串。
其实2个字符串都已经发送,但是串口没有显示出来而已,我把显示方式切换到十六进制数时,就可以看到数据要比显示的多,是第一个和第二个字符串都有。
应该问题出现在那个00上,每一个字符串结束标示符,我程序中发送时,是吧整个字符串,连同结束标识一块都发送出去了,而这个串口调试助手在这里可能显示有问题。
我把程序改成这样,每次发送字符串时,串口中断发送字符串长度为原来长度减1.
结果重新运行,就可以显示2个字符串了。
2、其实换一个串口调试助手也可以看到此类问题:
结论,看来一个好的调试工具非常重要。
二、总结
接下来总结一下HAL库中串口UART中断发送数据的编程方法,给朋友们一起共享一下:
第一步:填充串口结构体变量huart2,使用HAL_UART_Init()函数初始化串口- huart2.Instance = USART2;
- huart2.Init.BaudRate = 115200;
- huart2.Init.WordLength = UART_WORDLENGTH_8B;
- huart2.Init.StopBits = UART_STOPBITS_1;
- huart2.Init.Parity = UART_PARITY_NONE;
- huart2.Init.Mode = UART_MODE_TX;
- huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
- huart2.Init.OverSampling = UART_OVERSAMPLING_16;
- huart2.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED ;
- huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
- HAL_UART_Init(&huart2);
复制代码 第二步:在需要发送数据时调用HAL_UART_Transmit_IT()函数启动发送数据。
HAL_UART_Transmit_IT(&huart2, (uint8_t *)TxBuffer1, TXBUFFERSIZE1 - 1);
第三步:串口自动启动发送中断,当每次中断时,自动进入中断USART2_IRQHandler()函数,调用库中的HAL_UART_IRQHandler()函数,这个函数不用大家编写,由库已经写好。
- void USART2_IRQHandler(void)
- {
- HAL_UART_IRQHandler(&huart2);
- }
复制代码 第四步:当串口中断发送完所有需要发送的数据时,自动调用HAL_UART_TxCpltCallback()这个串口发送完成的回调函数。在这里大家写上自己的串口发送完毕的处理事件,当然我这里将自定义的标志置位。
- void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
- {
- UartReady = SET;
- }
复制代码 第五步:在主函数中,启动发送数据HAL_UART_Transmit_IT()函数后,要判断数据是否发送完成,即UartReady标志,当发现置1即知道数据发送完毕,之后清标志位,就可以进行下一次发送了。- while (UartReady != SET)
- {
- ;
- }
- UartReady = RESET;
复制代码
最后把我修改后的程序上传上来:
UART_LED.rar
(6.74 MB, 下载次数: 24)
|