串口关键参数
波特率:每秒钟传输的符号数或信号变化的速率。波特率并不等同于数据速率。数据速率是指每秒钟传输的比特数,而波特率则是指每秒钟传输的符号数或信号变化的次数。在某些情况下,一个符号可能携带多个比特的信息,因此波特率和数据速率可能不相等。
常用模式:8N1(8个数据位长度、无校验方式和1个停止位)。
STM32F103系列微控制器USART的中断事件及其使能标志位
中断事件 | 使能标志位 | 描述 |
---|---|---|
USART发送寄存器空中断 | USART_IT_TXE | 当发送寄存器为空时触发,表示可以发送新的数据。 |
CTS状态改变中断 | USART_IT_CTS | 当CTS信号的状态发生变化时触发。 |
数据传输完成中断 | USART_IT_TC | 当最后一个数据传输完成时触发。 |
USART接收寄存器非空中断 | USART_IT_RXNE | 当接收寄存器非空时触发,表示有数据可读取。 |
USART溢出/帧错误/空闲中断 | USART_IT_ORE_RXNE_IDLE | 当接收缓冲区溢出、帧错误或空闲线路检测到时触发。 |
串口空闲中断 | USART_IT_IDLE | 当检测到接收线路处于空闲状态时触发。 |
奇偶校验错误中断 | USART_IT_PE | 当接收到的数据的奇偶校验错误时触发。 |
奇偶校验错误中断 | USART_IT_LBD | 当检测到奇偶校验错误时触发(仅用于LIN模式)。 |
奇偶校验错误中断 | USART_IT_NE | 当检测到噪声错误时触发。 |
使用库函数创建工程发送和接受数据
代码
Serial.c
#include "stm32f10x.h"
void Serial_Init(unsigned int baud)
{
// 使能USART1和GPIOA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // USART1的TX引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // USART1的RX引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = baud; // 波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 支持发送和接收
USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 1个停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 8位数据位
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE); // 使能USART1
}
void Serial_Sendchar(unsigned char ch)
{
USART_SendData(USART1, ch); // 发送一个字符
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); // 等待发送完成
}
unsigned char USART1_RxIsNotEmpty()
{
if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)//接收数据寄存器非空标志位
return 1; // 接收缓冲区非空
else
return 0; // 接收缓冲区空
}
unsigned char USART1_RecvChar()
{
return USART_ReceiveData(USART1); // 从接收缓冲区读取一个字符
}
Serial.h
#ifndef __SERIAL_H
#define __SERIAL_H
void Serial_Init(unsigned int baud);
void Serial_Sendchar(unsigned char ch);
unsigned char USART1_RxIsNotEmpty(void);
unsigned char USART1_RecvChar(void);
#endif
main.c
#include "stm32f10x.h"
#include "Serial.h"
int main(void)
{
Serial_Init(9600); // 初始化串口,波特率为9600
while(1)
{
if(USART1_RxIsNotEmpty()) // 如果串口接收到数据
Serial_Sendchar(USART1_RecvChar()); // 将接收到的数据发送出去
}
}
实验结果
阻塞轮询式收发数据
串口通讯时,通讯双方TX(发送)和RX(接受)交叉连接。
从此处开始下边都是HAL库
什么是阻塞轮询式收发数据
阻塞轮询式收发数据是一种常见的串口通信方式,它的工作原理如下:
-
阻塞(Blocking): 在阻塞轮询模式下,当程序调用串口接收函数时,如果没有接收到数据,程序将会一直阻塞(即暂停执行),直到有数据到达并被接收。
-
轮询(Polling): 在轮询模式下,程序会周期性地检查串口接收缓冲区是否有数据到达。如果有数据到达,程序会立即进行接收处理,如果没有数据,程序继续执行其他任务或者等待。
综合起来,阻塞轮询式收发数据的流程如下:
-
发送数据时,程序调用串口发送函数,如果发送缓冲区有足够的空间,数据将被放入发送缓冲区并立即发送;如果发送缓冲区已满,程序将会被阻塞,直到发送缓冲区有足够的空间。
-
接收数据时,程序调用串口接收函数,如果接收缓冲区有数据,数据将被立即接收并返回给程序;如果接收缓冲区没有数据,程序将会被阻塞,直到接收到数据。
阻塞轮询式收发数据的优点是实现简单,易于理解和调试。但它的缺点是在串口通信过程中可能会造成程序的阻塞,降低系统的实时性。
代码
uart.c
#include "stm32f1xx_hal.h"
UART_HandleTypeDef uart1;//参数结构体被包含在总控结构体中,故使用参数结构体
// UART1 初始化函数
void U1_Init(uint32_t bandrate)
{
// UART1 初始化结构体
uart1.Instance = USART1; // 指定使用的串口实例为 USART1
uart1.Init.BaudRate = bandrate; // 设置波特率为传入的参数 bandrate
uart1.Init.WordLength = UART_WORDLENGTH_8B; // 设置数据位长度为 8 位
uart1.Init.StopBits = UART_STOPBITS_1; // 设置停止位为 1 位
uart1.Init.Parity = UART_PARITY_NONE; // 设置校验位为无校验
uart1.Init.Mode = UART_MODE_TX_RX; // 设置工作模式为同时发送和接收
uart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 设置硬件流控为无流控
HAL_UART_Init(&uart1); // 使用 HAL 库初始化 UART1
}
// UART 外设初始化回调函数
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef GPIO_InitStruct;
// 检查初始化的 UART 实例是否为 USART1
if (huart->Instance == USART1)
{
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能 GPIOA 时钟
__HAL_RCC_USART1_CLK_ENABLE(); // 使能 USART1 时钟
// 配置 USART1 的引脚
// 配置 TX 引脚(PA9)为复用推挽输出
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置 RX 引脚(PA10)为浮空输入
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL; // 设置为无上拉/下拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}
uart.h
#ifndef __UART_H
#define __UART_H
void U1_Init(uint32_t bandrate);
extern UART_HandleTypeDef uart1;
#endif
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "uart.h"
#define RX_SIZE 200 // 接收缓冲区大小
uint8_t buff[256]; // 接收缓冲区数组
int main(void)
{
HAL_Init();
RccClock_Init();
U1_Init(115200);
while(1)
{
// 使用 HAL_UART_Receive 函数从 UART1 接收数据
switch(HAL_UART_Receive(&uart1, buff, RX_SIZE, 200))
{
case HAL_OK : // 如果接收成功
// 使用 HAL_UART_Transmit 函数将接收到的数据发送回去
HAL_UART_Transmit(&uart1, buff, RX_SIZE, 200);
break;
case HAL_TIMEOUT: // 如果超时
// 检查是否接收到部分数据,如果是,则将部分数据发送回去
if(uart1.RxXferCount != RX_SIZE-1)
{
HAL_UART_Transmit(&uart1, buff, (RX_SIZE - 1 - uart1.RxXferCount), 200);//将接受的那一部分数据发送回去
}
break;
}
}
}
实验结果
未发送数据时
点击调试,全速运行,调出参数窗口,把uart1复制到参数名称框,点开查看uart参数,发现RX_SIZE:0x00C8=200,RxXferCount:0x00c7=199。因此代码中RxXferCount需要减去1才可以判断。
发送10个数据时,接受10个数据
此时RxXferCount位BD=189,程序运行time_out分支,200-1-189=10,证明确实发了十个数据,实验结果正确。
发送200个数据时,接受200个数据
此时RxXferCount无变化,程序运行HAL_OK分支,因为发送了200个数据,实验结果无误。
串口1重映射
什么是重映射
在嵌入式系统中,特别是在一些芯片或微控制器中,重映射是指将一个或多个外设的引脚映射到不同的GPIO引脚上,以实现外设的功能扩展或灵活性增强。重映射通常用于芯片设计中为了适应不同的应用需求,允许开发者重新定义特定外设的引脚分配,使得硬件可以更灵活地应对不同的接口需求。
在STM32系列微控制器中,重映射通常用于重新定义一些特定的功能引脚,如USART、SPI、I2C等外设的引脚,以满足特定的应用需求或连接不同的外部设备。通过重映射,可以在一定程度上实现硬件资源的共享和复用,从而节约系统资源并提高系统的可扩展性。
重映射通常由芯片厂商提供的引脚复用功能支持,通过设置相关的寄存器位来实现。在配置重映射时,需要注意引脚复用的限制以及可能引起的功能冲突,确保系统的稳定性和可靠性。
代码
uart.c
#include "stm32f1xx_hal.h"
UART_HandleTypeDef uart1;//参数结构体被包含在总控结构体中,故使用参数结构体
UART_HandleTypeDef uart2;
UART_HandleTypeDef uart3;
// UART1 初始化函数
void U1_Init(uint32_t bandrate)
{
// UART1 初始化结构体
uart1.Instance = USART1; // 指定使用的串口实例为 USART1
uart1.Init.BaudRate = bandrate; // 设置波特率为传入的参数 bandrate
uart1.Init.WordLength = UART_WORDLENGTH_8B; // 设置数据位长度为 8 位
uart1.Init.StopBits = UART_STOPBITS_1; // 设置停止位为 1 位
uart1.Init.Parity = UART_PARITY_NONE; // 设置校验位为无校验
uart1.Init.Mode = UART_MODE_TX_RX; // 设置工作模式为同时发送和接收
uart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 设置硬件流控为无流控
HAL_UART_Init(&uart1);// 使用 HAL 库初始化 UART1
}
void U2_Init(uint32_t bandrate)
{
uart2.Instance = USART2; // 指定使用的串口实例为 USART2
uart2.Init.BaudRate = bandrate; // 设置波特率为传入的参数 bandrate
uart2.Init.WordLength = UART_WORDLENGTH_8B; // 设置数据位长度为 8 位
uart2.Init.StopBits = UART_STOPBITS_1; // 设置停止位为 1 位
uart2.Init.Parity = UART_PARITY_NONE; // 设置校验位为无校验
uart2.Init.Mode = UART_MODE_TX_RX; // 设置工作模式为同时发送和接收
uart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 设置硬件流控为无流控
HAL_UART_Init(&uart2);
}
void U3_Init(uint32_t bandrate)
{
uart3.Instance = USART3; // 指定使用的串口实例为 USART3
uart3.Init.BaudRate = bandrate; // 设置波特率为传入的参数 bandrate
uart3.Init.WordLength = UART_WORDLENGTH_8B; // 设置数据位长度为 8 位
uart3.Init.StopBits = UART_STOPBITS_1; // 设置停止位为 1 位
uart3.Init.Parity = UART_PARITY_NONE; // 设置校验位为无校验
uart3.Init.Mode = UART_MODE_TX_RX; // 设置工作模式为同时发送和接收
uart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 设置硬件流控为无流控
HAL_UART_Init(&uart3);
}
// UART 外设初始化回调函数
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef GPIO_InitStruct;
// 检查初始化的 UART 实例是否为 USART1
if (huart->Instance == USART1)
{
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();//注意映射到GPIOB
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_AFIO_REMAP_USART1_ENABLE();//重映射usart1
// 配置 TX 引脚(PA9)为复用推挽输出
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// 配置 RX 引脚(PA10)为浮空输入
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL; // 设置为无上拉/下拉
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
else if (huart->Instance == USART2)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART2_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL; // 设置为无上拉/下拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
else if (huart->Instance == USART3)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL; // 设置为无上拉/下拉
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
}
uart.h
#ifndef __UART_H
#define __UART_H
void U1_Init(uint32_t bandrate);
void U2_Init(uint32_t bandrate);
void U3_Init(uint32_t bandrate);
extern UART_HandleTypeDef uart1;
extern UART_HandleTypeDef uart2;
extern UART_HandleTypeDef uart3;
#endif
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "uart.h"
#define RX_SIZE 200 // 接收缓冲区大小
uint8_t buff[256]; // 接收缓冲区数组
int main(void)
{
HAL_Init();
RccClock_Init();
U1_Init(115200);
U2_Init(115200);
U3_Init(115200);
while(1)//想用哪一个串口直接把里边的串口号手动改变了即可
{
// 使用 HAL_UART_Receive 函数从 UART1 接收数据
switch(HAL_UART_Receive(&uart1, buff, RX_SIZE, 200))//HAL_UART_Receive可能有感叹号,可以不用管,也可以把程序补充完整,加上HAL_ERROR和HAL_BUSY
{
case HAL_OK : // 如果接收成功
// 使用 HAL_UART_Transmit 函数将接收到的数据发送回去
HAL_UART_Transmit(&uart1, buff, RX_SIZE, 200);
break;
case HAL_TIMEOUT: // 如果超时
// 检查是否接收到部分数据,如果是,则将部分数据发送回去
if(uart1.RxXferCount != RX_SIZE)
{
HAL_UART_Transmit(&uart1, buff, (RX_SIZE - 1 - uart1.RxXferCount), 200);
}
break;
case HAL_ERROR:
break;
case HAL_BUSY:
break;
}
}
}
实验结果
改变UART1连接的实物引脚,重复上节实验即可。
多指针定位+收发循环使用缓冲区设计
缓冲区为一个一维数组,循环使用,要注意缓冲区不要出现回卷覆盖,接收的数据要及时处理。
思维图
用三个指针 IN ,OUT, END 来判断此一维数组数据情况。
接受区
发送区
官方串口中断处理函数
代码
urat.c
#include "stm32f1xx_hal.h"
UART_HandleTypeDef uart1;//参数结构体被包含在总控结构体中,故使用参数结构体
UART_HandleTypeDef uart2;
UART_HandleTypeDef uart3;
uint8_t txbuff[64], rxbuff[64];
uint8_t rxstate;
// UART1 初始化函数
void U1_Init(uint32_t bandrate)
{
// UART1 初始化结构体
uart1.Instance = USART1; // 指定使用的串口实例为 USART1
uart1.Init.BaudRate = bandrate; // 设置波特率为传入的参数 bandrate
uart1.Init.WordLength = UART_WORDLENGTH_8B; // 设置数据位长度为 8 位
uart1.Init.StopBits = UART_STOPBITS_1; // 设置停止位为 1 位
uart1.Init.Parity = UART_PARITY_NONE; // 设置校验位为无校验
uart1.Init.Mode = UART_MODE_TX_RX; // 设置工作模式为同时发送和接收
uart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 设置硬件流控为无流控
HAL_UART_Init(&uart1);// 使用 HAL 库初始化 UART1
HAL_UART_Receive_IT(&uart1,rxbuff,20);// 使用HAL库的UART接收中断模式函数
}
void U2_Init(uint32_t bandrate)
{
uart2.Instance = USART2; // 指定使用的串口实例为 USART2
uart2.Init.BaudRate = bandrate; // 设置波特率为传入的参数 bandrate
uart2.Init.WordLength = UART_WORDLENGTH_8B; // 设置数据位长度为 8 位
uart2.Init.StopBits = UART_STOPBITS_1; // 设置停止位为 1 位
uart2.Init.Parity = UART_PARITY_NONE; // 设置校验位为无校验
uart2.Init.Mode = UART_MODE_TX_RX; // 设置工作模式为同时发送和接收
uart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 设置硬件流控为无流控
HAL_UART_Init(&uart2);
}
void U3_Init(uint32_t bandrate)
{
uart3.Instance = USART3; // 指定使用的串口实例为 USART3
uart3.Init.BaudRate = bandrate; // 设置波特率为传入的参数 bandrate
uart3.Init.WordLength = UART_WORDLENGTH_8B; // 设置数据位长度为 8 位
uart3.Init.StopBits = UART_STOPBITS_1; // 设置停止位为 1 位
uart3.Init.Parity = UART_PARITY_NONE; // 设置校验位为无校验
uart3.Init.Mode = UART_MODE_TX_RX; // 设置工作模式为同时发送和接收
uart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 设置硬件流控为无流控
HAL_UART_Init(&uart3);
}
// UART 外设初始化回调函数
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef GPIO_InitStruct;
// 检查初始化的 UART 实例是否为 USART1
if (huart->Instance == USART1)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART1_CLK_ENABLE();
// 配置 TX 引脚(PA9)为复用推挽输出
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置 RX 引脚(PA10)为浮空输入
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL; // 设置为无上拉/下拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_NVIC_SetPriority(USART1_IRQn, 3, 0);// 设置USART1中断的优先级为3,子优先级为0
HAL_NVIC_EnableIRQ(USART3_IRQn);// 使能USART3中断
}
else if (huart->Instance == USART2)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART2_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL; // 设置为无上拉/下拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
else if (huart->Instance == USART3)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL; // 设置为无上拉/下拉
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
}
// UART 接收完成回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
// 将接收缓冲区的内容复制到发送缓冲区
memcpy(txbuff, rxbuff, 20);
rxstate = 1; // 设置接收状态为已完成
HAL_UART_Receive_IT(&uart1, rxbuff, 20); // 启动下一次接收中断
}
}
// UART 错误回调函数
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
// 在此处处理 UART1 的错误情况,可以根据具体需求进行相应的处理
// 可以在此添加相关的错误处理代码
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
}
}
uart.h
#ifndef __UART_H
#define __UART_H
#include "string.h"
#include "stdint.h"
#include "stm32f1xx_hal_uart.h"
void U1_Init(uint32_t bandrate);
void U2_Init(uint32_t bandrate);
void U3_Init(uint32_t bandrate);
extern UART_HandleTypeDef uart1;
extern UART_HandleTypeDef uart2;
extern UART_HandleTypeDef uart3;
extern uint8_t txbuff[64], rxbuff[64];
extern uint8_t rxstate;
#endif
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "uart.h"
#define RX_SIZE 200 // 接收缓冲区大小
uint8_t buff[256]; // 接收缓冲区数组
int main(void)
{
HAL_Init();
RccClock_Init();
U1_Init(9600);
while(1)
{
// 持续检查接收状态
if(rxstate == 1)
{
rxstate = 0; // 重置接收状态为0,表示接收处理已完成
HAL_UART_Transmit_IT(&uart1, txbuff, 20);// 使用 UART1 发送接收到的数据
}
}
}
stm32f1xx_it.c中添加中断函数
#include "uart.h"
/ UART1_IRQHandler: USART1中断的中断处理函数
// 当USART1接收到数据或发送数据时,调用 HAL_UART_IRQHandler() 处理函数处理USART1的中断
void UART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1);
}
实验结果
发送20个字节数据接受20个,当少于20个时不会触发。