STM32F4 STD标准库串口接收中断+空闲中断例程
- 🔖工程基于
STM32F446
✨用惯了
STM32CubeMX
傻瓜式配置,突然改用标准库写代码,初始化外设内容,总是丢三落四的。
本文将提供3种串口接收和发送模式:
串口接收中断+空闲中断
、串口空闲中断+DMA接收
、串口DMA接收和发送数据+空闲中断
- 📍DMA发送参考:
https://blog.csdn.net/m0_64354650/article/details/125648186
📗串口接收中断+空闲中断模式例程
📑串口初始化配置
void uart_init(uint32_t bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能USART1,GPIOA时钟
/* Enable GPIO clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* Connect PXx to USARTx_Tx*/
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
/* Connect PXx to USARTx_Rx*/
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
//USART1_TX GPIOA.9
/* Configure USART Tx as alternate function */
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART Rx as alternate function */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ; //抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口空闲中断
USART_Cmd(USART1, ENABLE); //使能串口1
}
📘串口中断函数
void USART1_IRQHandler(void) //串口1中断服务程序
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
// USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清标志位
// USART_RX_BUF[length] = USART_ReceiveData(USART1);//读取接收到的数据
USART_RX_BUF[length] = USART1->DR & 0x0FF;
length++;
} else if(USART_GetFlagStatus(USART1, USART_FLAG_IDLE) != RESET) { //空闲帧中断
USART1->SR; //先读SR.再读DR
USART1->DR; //清空寄存器
length = 0;
USART_RX_STA = 1; //数据接收 标志位
}
}
📑接收数据所需的变量和宏定义
#define USART_REC_LEN 64 //定义最大接收字节数 64
#define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收
uint8_t USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
uint8_t USART_RX_STA = 0; //接收状态标记
static __IO uint16_t length = 0;//接收数据时的下标
📒处理接收数据和释放空间
if(USART_RX_STA) {
USART_RX_STA = 0;//清标志位
printf("Re:%s\n", USART_RX_BUF);
memset(USART_RX_BUF, 0x00, sizeof(USART_RX_BUF));//清空接收数组
}
- 🔬测试效果:
📚串口接收中断+空闲中断
测试工程
链接:https://pan.baidu.com/s/13UxJawYkAkpIb8SzhSnpqg?pwd=8rc0
提取码:8rc0
📘 串口DMA接收和发送数据+空闲中断
模式
- 🌿DMA配置
static void USART_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(USART_TX_DMA_CLK | USART_RX_DMA_CLK, ENABLE);//使能DMA2时钟
/* 配置发送 */
DMA_InitStructure.DMA_BufferSize = 0;//随便配置,因为在接收到数据后我们会重新给这值赋值
DMA_InitStructure.DMA_Channel = USART_TX_DMA_CHANNEL;//串口发送通道
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//DMA搬运方向:存储器到外设
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Rec;//存储器地址
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发模式选择:单次模式
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据宽度:字节
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable ;//使能存储器地址自动递增功能
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//DMA 传输模式选择:一次传输
DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_BASE;//外设地址
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发模式选择:单次模式
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据宽度:字节
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//禁止外设地址自动递增功能
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//软件设置数据流的优先级:中等
/* FIFO不用随便配置 */
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_Init(USART_TX_DMA_STREAM, &DMA_InitStructure);
DMA_Cmd(USART_TX_DMA_STREAM, DISABLE);//发送先失能
/* 配置接收 */
DMA_InitStructure.DMA_BufferSize = RX_MAX_LEN;//接收数据的长度
DMA_InitStructure.DMA_Channel = USART_RX_DMA_CHANNEL;//串口发送通道
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//DMA搬运方向:外设到存储器
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA 传输模式选择:循环接收
/* 其余配置与上面一样 */
DMA_Init(USART_RX_DMA_STREAM, &DMA_InitStructure);
DMA_Cmd(USART_RX_DMA_STREAM, ENABLE);//接收使能
}
- 🌿串口配置
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* 使能时钟 */
RCC_AHB1PeriphClockCmd(USART_TX_GPIO_CLK | USART_RX_GPIO_CLK, ENABLE);
RCC_APB2PeriphClockCmd(USART_CLK, ENABLE);
/* GPIO相关配置 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF ;//复用功能
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP ;//推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//无上拉 无下拉
GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed ;//高速
GPIO_InitStructure.GPIO_Pin = USART_TX_PIN;//配置发送引脚
GPIO_Init(USART_TX_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = USART_RX_PIN;//配置接收引脚
GPIO_Init(USART_RX_GPIO_PORT, &GPIO_InitStructure);
/* 将对应的IO口连接到外设,开始启动复用功能 */
GPIO_PinAFConfig(USART_TX_GPIO_PORT, USART_TX_SOURCE, USART_TX_AF);
GPIO_PinAFConfig(USART_RX_GPIO_PORT, USART_RX_SOURCE, USART_RX_AF);
/* USART1的相关配置 */
USART_InitStructure.USART_BaudRate = USART_BAUDRATE;//波特率115200
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//不使用硬件流
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx ;//USART模式控制:同时使能接收和发送
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(USART, &USART_InitStructure);
USART_NVIC_Config();//中断配置
USART_DMA_Config();//DMA配置
USART_ITConfig(USART, USART_IT_IDLE, ENABLE); //开启空闲中断
USART_DMACmd(USART, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);//使能DMA接收与发送
USART_Cmd(USART, ENABLE); //使能串口
}
- 🌿串口中断
//串口中断服务程序
void USART_IRQHandler(void)
{
uint16_t temp;
if(USART_GetFlagStatus(USART, USART_FLAG_IDLE) != RESET) {
temp = USART1->SR;
temp = USART1->DR;//清除IDLE中断
temp = DMA_GetCurrDataCounter(USART_RX_DMA_STREAM);//获取剩余的接收数据的量
DMA_Cmd(USART_RX_DMA_STREAM, DISABLE);
DMA_SetCurrDataCounter(USART_RX_DMA_STREAM, RX_MAX_LEN);//设置需要接收的量
DMA_Cmd(USART_RX_DMA_STREAM, ENABLE);
DMA_Cmd(USART_TX_DMA_STREAM, DISABLE);
DMA_SetCurrDataCounter(USART_TX_DMA_STREAM, RX_MAX_LEN - temp);//设置需要发送的量
DMA_Cmd(USART_TX_DMA_STREAM, ENABLE);
while(USART_GetFlagStatus(USART, USART_FLAG_TC) == RESET); //必须等待,否则最后一位数据错误
DMA_ClearFlag(USART_TX_DMA_STREAM, DMA_FLAG_TCIF7); //清除DMA传输完成标志
USART_ClearFlag(USART, USART_FLAG_TC); //清除传输完成标志
}
}
📚串口DMA接收和发送数据+空闲中断
模式测试代码
链接:https://pan.baidu.com/s/1aAVqOlT7nBd-ZwNN4ZN09g?pwd=3ci8
提取码:3ci8
📙串口空闲中断+DMA接收
模式
- 🌿DMA配置
static void USART_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(USART_RX_DMA_CLK, ENABLE);//使能DMA2时钟
/* 配置发送 */
// DMA_InitStructure.DMA_BufferSize = 0;//随便配置,因为在接收到数据后我们会重新给这值赋值
// DMA_InitStructure.DMA_Channel = USART_TX_DMA_CHANNEL;//串口发送通道
// DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//DMA搬运方向:存储器到外设
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)USART_RX_BUF;//存储器地址
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发模式选择:单次模式
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据宽度:字节
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable ;//使能存储器地址自动递增功能
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//DMA 传输模式选择:一次传输
DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_BASE;//外设地址
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发模式选择:单次模式
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据宽度:字节
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//禁止外设地址自动递增功能
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//软件设置数据流的优先级:中等
/* FIFO不用随便配置 */
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
// DMA_Init(USART_TX_DMA_STREAM, &DMA_InitStructure);
// DMA_Cmd(USART_TX_DMA_STREAM, DISABLE);//发送先失能
/* 配置接收 */
DMA_InitStructure.DMA_BufferSize = RX_MAX_LEN;//接收数据的长度
DMA_InitStructure.DMA_Channel = USART_RX_DMA_CHANNEL;//串口发送通道
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//DMA搬运方向:外设到存储器
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA 传输模式选择:循环接收
/* 其余配置与上面一样 */
DMA_Init(USART_RX_DMA_STREAM, &DMA_InitStructure);
DMA_Cmd(USART_RX_DMA_STREAM, ENABLE);//接收使能
}
- 🌿串口配置
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* 使能时钟 */
RCC_AHB1PeriphClockCmd(USART_TX_GPIO_CLK | USART_RX_GPIO_CLK, ENABLE);
RCC_APB2PeriphClockCmd(USART_CLK, ENABLE);
/* GPIO相关配置 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF ;//复用功能
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP ;//推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//无上拉 无下拉
GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed ;//高速
GPIO_InitStructure.GPIO_Pin = USART_TX_PIN;//配置发送引脚
GPIO_Init(USART_TX_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = USART_RX_PIN;//配置接收引脚
GPIO_Init(USART_RX_GPIO_PORT, &GPIO_InitStructure);
/* 将对应的IO口连接到外设,开始启动复用功能 */
GPIO_PinAFConfig(USART_TX_GPIO_PORT, USART_TX_SOURCE, USART_TX_AF);
GPIO_PinAFConfig(USART_RX_GPIO_PORT, USART_RX_SOURCE, USART_RX_AF);
/* USART1的相关配置 */
USART_InitStructure.USART_BaudRate = USART_BAUDRATE;//波特率115200
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//不使用硬件流
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx ;//USART模式控制:同时使能接收和发送
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(USART, &USART_InitStructure);
USART_NVIC_Config();//中断配置
USART_DMA_Config();//DMA配置
USART_ITConfig(USART, USART_IT_IDLE, ENABLE); //开启空闲中断
USART_DMACmd(USART, USART_DMAReq_Rx, ENABLE);//使能DMA接收
USART_Cmd(USART, ENABLE); //使能串口
}
-🌿 中断配置
//串口中断服务程序
void USART_IRQHandler(void)
{
uint16_t temp;
if(USART_GetFlagStatus(USART, USART_FLAG_IDLE) != RESET) {
temp = USART1->SR;
temp = USART1->DR;//清除IDLE中断
USART_RX_STA = 1; //数据接收 标志位
temp = DMA_GetCurrDataCounter(USART_RX_DMA_STREAM);//获取剩余的接收数据的量
DMA_Cmd(USART_RX_DMA_STREAM, DISABLE);
DMA_SetCurrDataCounter(USART_RX_DMA_STREAM, RX_MAX_LEN);//设置需要接收的量
DMA_Cmd(USART_RX_DMA_STREAM, ENABLE);
}
}
📚串口空闲中断+DMA接收
模式例程代码
链接:https://pan.baidu.com/s/1R8F0R4KzjVTCR8zd2V-lVA?pwd=j595
提取码:j595