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

欢迎入群共同学习交流
时间记录:2024/5/23

一、概念介绍

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

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

(1)头文件

#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)源文件

#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);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值