目录

 

​前言:代码包下载​

​一、串口与DMA部分知识讲解​

​二、串口空闲IDEL中断​

​三、串口配置、串口空闲中断配置、DMA配置、中断服务函数​

​1、串口的GPIO配置​

​2、串口配置​

​3、串口空闲中断配置​

​4、DMA直接存储器访问配置​

​5、使能空闲中断​

​6、stm32f4xx_it.c 的配置​

​7、main.c​

​8、注意:要清空数组!​

​9、效果展示​


前言:代码包下载

下载方式二:微信公众号:暂不提供

一、串口与DMA部分知识讲解

如果大家有什么问题,欢迎在下面评论交流!

串口部分的详解​梳理STM32F429之通信传输部分---NO.1 串口通讯​

DMA直接存储器访问:​梳理STM32F429之通信传输部分---NO.2 DMA—直接存储区访问​

这里补充一下:串口空闲IDEL中断的一些注意事项:

二、串口空闲IDEL中断

1、串口空闲IDEL中断的作用:

       现在有很多数据处理都要用到不定长数据,而单片机串口的RXNE中断一次只能接收一个字节的数据,没有缓冲区,无法接收一帧多个数据,利用串口IDLE空闲中断的方式接收一帧数据,方法如下:

单片机接收到一个字节的时候并不会产生串口中断,而是DMA在后台把数据默默地搬运到你指定的缓冲区里面。当整帧数据发送完毕之后串口才会产生一次中断,此时可以利用DMA_GetCurrDataCounter();函数计算出本次的数据接受长度,从而进行数据处理

2、注意事项:避免一直进入空闲中断!

先读取USART_SR,再读取USART_DR。需要注意的是,不能采用库函数USART_ClearFlag()或者USART_ClearItPending()来清除IDEL标志位。

USART_ReceiveData(USART1);    清除标志位

三、串口配置、串口空闲中断配置、DMA配置、中断服务函数

1、串口的GPIO配置

GPIO_InitTypeDef  GPIO_InitStructure;  

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
/* 使能 GPIOC 时钟 */

/* GPIO初始化 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//输出推挽
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHZ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

GPIO_Init(GPIOC, &GPIO_InitStructure);

2、串口配置

USART_InitTypeDef USART_InitStructure;


/* 连接 PXx 到 USARTx_Tx*/
GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_USART6);
/* 连接 PXx 到 USARTx_Rx*/
GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_USART6);


USART_InitStructure.USART_BaudRate = 115200; //串口波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; /* 硬件流控制:不使用硬件流 */
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx ; /* 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(USART6, &USART_InitStructure);

3、串口空闲中断配置

NVIC_InitTypeDef  NVIC_InitStructure;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); /* 嵌套向量中断控制器组选择 */
NVIC_InitStructure.NVIC_IRQChannel = USART6_IRQn; /* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; /* 抢断优先级为1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; /* 子优先级为1 */

NVIC_Init(&NVIC_InitStructure);

4、DMA直接存储器访问配置

(1)开启DMA时钟、复位DMA(根据下图选择DMA?、数据流和通道)

梳理STM32F429之通信传输部分---NO.10 串口空闲IDEL中断+DMA(可接受任意长度的字符)_串口空闲IDEL中断

梳理STM32F429之通信传输部分---NO.10 串口空闲IDEL中断+DMA(可接受任意长度的字符)_串口_02

(2)DMA的结构体配置

说明:

  • (uint32_t) 是强制转换的意思,因为DMA结构体需要的是32位无符号类型数据;
  • &USART6->DR:串口数据寄存器地址(此处需要填数据传来的地址即下图的寄存器,USART_DR寄存器相对于USART6偏移了0x04)

梳理STM32F429之通信传输部分---NO.10 串口空闲IDEL中断+DMA(可接受任意长度的字符)_串口_03

(3)清除DMA所有标志
  DMA_ClearFlag(DMA2_Stream1,DMA_FLAG_TCIF5);       DMA2 通道5 数据流1
  DMA_ITConfig(DMA2_Stream1, DMA_IT_TE, ENABLE);   DMA2 数据流1 传输错误使能中断

梳理STM32F429之通信传输部分---NO.10 串口空闲IDEL中断+DMA(可接受任意长度的字符)_串口_04


(4)开启串口DMA接收

    USART_DMACmd(USART6, USART_DMAReq_Rx,     ENABLE); 

(5)使能DMA

  DMA_Cmd (DMA2_Stream1,ENABLE);

DMA_InitTypeDef   DMA_InitStructure;

// 开启DMA时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
// DMA复位
DMA_DeInit(DMA2_Stream1);
// 设置DMA通道

DMA_InitStructure.DMA_Channel = DMA_Channel_5;
/*设置DMA源:串口数据寄存器地址*/
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART6->DR);
// 内存地址(要传输的变量的指针)
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)RevBuff;
// 方向:从外设到内存
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
// 传输大小
DMA_InitStructure.DMA_BufferSize = (uint32_t)5000;
// 外设地址不增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
// 内存地址自增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
// 外设数据单位
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
// 内存数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
// DMA模式,一次或者循环模式
//DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
// 优先级:中
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
// 禁止内存到内存的传输
/*禁用FIFO*/
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
/*存储器突发传输 1个节拍*/
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
/*外设突发传输 1个节拍*/
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;



/*配置DMA2的数据流7*/
DMA_Init(DMA2_Stream1, &DMA_InitStructure);


// 清除DMA所有标志
DMA_ClearFlag(DMA2_Stream1,DMA_FLAG_TCIF2);
DMA_ITConfig(DMA2_Stream1, DMA_IT_TE, ENABLE);
// 开启串口DMA接收
USART_DMACmd(USART6, USART_DMAReq_Rx, ENABLE);
// 使能DMA
DMA_Cmd (DMA2_Stream1,ENABLE);

5、使能空闲中断

USART_IT_IDLE和USART_IT_RXNE区别 
当接收到1个字节,会产生USART_IT_RXNE中断 
当接收到一帧数据,就会产生USART_IT_IDLE中断

// 开启 串口空闲 IDEL 中断
USART_ITConfig(USART6, USART_IT_IDLE, ENABLE);
// 使能串口
USART_Cmd(USART6, ENABLE);

6、stm32f4xx_it.c 的配置

#include "stm32f4xx_it.h"
#include "bsp_usart_dma.h"
int Flag=0;

void USART6_IRQHandler(void)
{
if(USART_GetITStatus(USART6,USART_IT_IDLE)!=RESET)
{
USART_ReceiveData(USART6); /* 清除标志位 */
Uart_DMA_Rx_Data();
Flag=1;
}
}

7、main.c

/**
******************************************************************************
* @file main.c
* @author Sumjes
* @version V1.0
* @date 2020-02-02
* @brief 串口接发测试,串口接收到数据后马上回传。
******************************************************************************
* @attention
*
* 实验平台: STM32 F429 开发板
* 公众号 : Tech云
*
******************************************************************************
*/

#include "stm32f4xx.h"
#include "bsp_usart_dma.h"

/* 标准库头文件 */
#include <string.h>

extern int Flag;
extern char RevBuff[5000];


int main(void)
{
/*初始化USART6 配置模式为 115200 8-N-1,中断接收*/
usart6_init();

/* 发送一个字符串 */
printf("这是一个串口DMA空闲中断接收回显实验\r\n");

while(1)
{
if(Flag)
{
printf("接收到数据,回发==|%s|==\r\n",RevBuff);
memset(RevBuff,0,5000);/* 清零 */
Flag=0;
}
}
}



/*********************************************END OF FILE***************************************/

8、注意:要清空数组!

memset(RevBuff,0,5000);/* 清零 */

9、效果展示

梳理STM32F429之通信传输部分---NO.10 串口空闲IDEL中断+DMA(可接受任意长度的字符)_串口_05