本次实验目标内容:
条件声明:
本实验的软件开发工具为Keil,基础代码由STM32CubeMX生成。基础代码并没有包括UART的启动初始化代码;
本实验使用的是stm32f103的UART1,对应的引脚为PA9和PA10;
UART1初始化:
115200
,可以根据需求修改。8 位
数据,无奇偶校验。1 位
。GPIO_InitTypeDef GPIO_InitStruct = {0};
// 使能 USART1 和 GPIOA 时钟
USART1_CLK_ENABLE();
USART1_GPIO_CLK_ENABLE();
// 配置 TX 引脚为复用推挽输出
GPIO_InitStruct.Pin = USART1_TX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(USART1_GPIO_PORT, &GPIO_InitStruct);
// 配置 RX 引脚为浮空输入
GPIO_InitStruct.Pin = USART1_RX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(USART1_GPIO_PORT, &GPIO_InitStruct);
// 配置 USART1 参数
huart1.Instance = USART1_INSTANCE;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler_u();
}
由于程序中用的宏定义变量和HAL函数都是在“stm32f1xx_hal_uart.c”中,所以需要包含stm32f1xx_hal_uart.h来启动uart库。
需在“stm32f1xx_hal_conf.h”中将#define HAL_UART_MODULE_ENABLED 的注释取消;
// 串口发送数据
void UART1_Transmit(uint8_t *pData, uint16_t Size)
{
if (HAL_UART_Transmit(&huart1, pData, Size, HAL_MAX_DELAY) != HAL_OK)
{
Error_Handler_u(); // 发送失败,等待
}
}
在UART.c 文件中添加下列程序,可以将uart1的输出映射到printf();
#include <stdio.h>
UART_HandleTypeDef huart1;
// 定义 PUTCHAR_PROTOTYPE 宏,兼容 GCC 和其他编译器
#ifdef __GNUC__
/* GCC 编译器 */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
/* 非 GCC 编译器 */
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
// 重定向 printf 输出到 UART
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
优化建议
在阻塞模式下,程序会等待接收到指定数量的数据后才继续执行。这种方式简单但效率较低,会阻塞 CPU。
实现代码:
void UART_Receive_Blocking(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
if (HAL_UART_Receive(huart, pData, Size, HAL_MAX_DELAY) != HAL_OK)
{
// 接收失败,执行错误处理
Error_Handler();
}
}
使用示例:
uint8_t rxData[10];
UART_Receive_Blocking(&huart1, rxData, sizeof(rxData)); // 接收 10 字节数据
//一个测试的数据处理程序
if (HAL_UART_Receive(&huart1, rxData, sizeof(rxData), HAL_MAX_DELAY) == HAL_OK)
{
str[i]=rxData[0];
if(rxData[0]=='A')
{
j=100;
}
i++;
} // 判断是否接收到字母A
if(j==100)
{
UART1_Transmit(str, i);
GPIO_Toggle_LED();
i=0;
j=0;
}
特点:
中断模式更高效,程序在等待数据时不会阻塞,可以执行其他任务。数据接收完成后触发中断,用户可以在回调函数中处理数据。
实现代码:
串口中断配置:
** **UART.c添加变量:
uint8_t rxBuffer[RX_BUFFER_SIZE]; // 数据接收缓冲区
volatile uint8_t rxComplete = 0; // 标志位,指示接收完成
** **UART.h添加:
// 接收缓冲区
#define RX_BUFFER_SIZE 10
extern uint8_t rxBuffer[RX_BUFFER_SIZE]; // 数据接收缓冲区
// 标志位,指示接收完成
extern volatile uint8_t rxComplete;
** **UART初始化部分添加:
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); // 设置中断优先级
HAL_NVIC_EnableIRQ(USART1_IRQn); // 启用中断
** **在 stm32f1xx_it.c
文件中,将 USART1 的中断处理加入:
// 中断处理函数
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1); // 调用 HAL 库的中断处理函数
}
启动接收中断:
//USART1 中断开启
void UART1_Start_Receive_IT(void)
{
if (HAL_UART_Receive_IT(&huart1, rxBuffer, RX_BUFFER_SIZE) != HAL_OK)
{
// 启动中断失败,处理错误
while (1);
}
}
接收完成回调函数: 当数据接收完成时,HAL 库会调用 HAL_UART_RxCpltCallback()
,用户可以在此函数中处理接收到的数据。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
//进入回调函数后中断会停止,如果想要继续使用需要再次启动
UART1_Start_Receive_IT();
// 处理 USART1 接收到的数据
// 比如将接收到的数据存储到一个全局变量
rxComplete = 1; // 设置接收完成标志位,可以将复杂的函数放在主函数中通过判断标志位调用。
}
}
使用示例:
UART_Receive_IT(); // 启动中断接收
// 在主循环中检查接收完成标志
if (rxComplete)
{
rxComplete = 0; // 清除标志位
// 处理接收到的数据
}
特点:
更多回帖