STM32使用DMA+空闲中断方式实现串口数据接收

欢迎入群共同学习交流

时间记录:2024/5/23

一、概念介绍

(1)DMA:直接存储器存取(DMA)(Direct Memory Access)也是一个挂载在AHB总线上的外设,用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。两个DMA控制器有12个通道(DMA1有7个通道,DMA2(只存在于大容量和互联网产品中)有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权

(2)STM32F103C8T6单片机通道介绍

二、串口接收数据代码示例

(1)头文件

c 复制代码
#ifndef __UART_H__
#define __UART_H__
#include "stm32f10x.h"

/**
 * DMA+空闲中断实现UART接收数据
*/

void vUart1Init(int baudrate);
void vUart1Send(u8 *data,int dataLen);
extern void (*vUart1Callback)(u8 *data,int dataLen);

#endif

(2)源文件

c 复制代码
#include "uart.h"
#include "string.h"

#define RX_BUF_SIZE 64
static u8 rx_buf[RX_BUF_SIZE];
void (*vUart1Callback)(u8 *data,int dataLen);

void vUart1Init(int baudrate)
{
    //1.初始化串口1GPIO口
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStruct);
    
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStruct);

    //2.初始化串口1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    
    USART_InitTypeDef USART_InitStruct;
    USART_InitStruct.USART_BaudRate = baudrate;
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_Init(USART1,&USART_InitStruct);

    //3.初始化接收DMA通道
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
    
    DMA_InitTypeDef DMA_InitStruct;
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); //外设地址
    DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)rx_buf; //接收数据的内存地址
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //DMA方向,外设到内存
    DMA_InitStruct.DMA_BufferSize = RX_BUF_SIZE; //缓冲区大小
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不自增
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 移动数据的大小
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; //模式,循环模式
    DMA_InitStruct.DMA_Priority = DMA_Priority_Medium; //DMA优先级
    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; // 禁用内存到内存
    DMA_Init(DMA1_Channel5,&DMA_InitStruct);

    //4.初始化NVIC
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    //5.使能串口、空闲中断、DMA接收
    USART_Cmd(USART1,ENABLE);
    USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
    DMA_Cmd(DMA1_Channel5,ENABLE);
}

void vUart1Send(u8 *data,int dataLen)
{
    for(int i=0;i<dataLen;i++)
    {
        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
        USART_SendData(USART1,data[i]);
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
    }
}

//中断服务函数
void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(USART1,USART_IT_IDLE)!=RESET)
    {
        USART_ClearITPendingBit(USART1,USART_IT_IDLE);
        u8 temp = (u8)USART_ReceiveData(USART1);
        
        //处理接收数据
        DMA_Cmd(DMA1_Channel5,DISABLE);
        int recvLen = RX_BUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);
        vUart1Callback(rx_buf,recvLen);
        memset(rx_buf,0,sizeof(rx_buf));
        DMA_SetCurrDataCounter(DMA1_Channel5,RX_BUF_SIZE);
        DMA_Cmd(DMA1_Channel5,ENABLE);
    }
}
相关推荐
网易独家音乐人Mike Zhou5 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
PegasusYu8 小时前
STM32CUBEIDE FreeRTOS操作教程(九):eventgroup事件标志组
stm32·教程·rtos·stm32cubeide·free-rtos·eventgroup·时间标志组
lantiandianzi12 小时前
基于单片机的多功能跑步机控制系统
单片机·嵌入式硬件
文弱书生65612 小时前
输出比较简介
stm32
哔哥哔特商务网12 小时前
高集成的MCU方案已成电机应用趋势?
单片机·嵌入式硬件
跟着杰哥学嵌入式12 小时前
单片机进阶硬件部分_day2_项目实践
单片机·嵌入式硬件
东芝、铠侠总代1361006839314 小时前
浅谈TLP184小型平面光耦
单片机·嵌入式硬件·物联网·平面
lantiandianzi14 小时前
基于单片机中医药柜管理系统的设计
单片机·嵌入式硬件
嵌入式知识大讲堂14 小时前
HDMI数据传输三种使用场景
单片机
黑客呀15 小时前
[系统安全]Rootkit基础
stm32·单片机·系统安全