stm32f103串口实用DMA实现收发

发布者:耿高良最新更新时间:2019-01-07 来源: eefocus关键字:stm32f103  串口  DMA 手机看文章 扫描二维码
随时随地手机看文章

目标环境:


    MCU:stm32f103C8T6


    stm32 library:standard library V3.5.0


    RTOS:FreeRTOS


实现功能:


    a. 接收DMA和串口IDLE中断配合接收不定长数据


    b. 使用DMA发送数据


一. 初始化


#include "stm32f10x.h"

#include "stm32f10x_rcc.h"

#include "stm32f10x_usart.h"

#include "stm32f10x_gpio.h"

#include "stm32f10x_dma.h"

#include "freertos.h"

#include "semphr.h"

 

#define UART_RECV_BUF_SIZE  (128)    /*DMA接收缓存大小*/

#define UART_SEND_BUF_SIZE  (128)    /*DMA发送缓存大小*/

 

#define USART2_RX_IDLE_PRIORITY (0x0b)    /*串口IDLE中断优先级*/

#define USART2_DMA_TX_PRIORITY  (0x0c)    /*DMA发送中断优先级*/

 

static u8 s_Uart_2_Recv_Buf[UART_RECV_BUF_SIZE] = {0};    /*存储DMA接收的数据*/

static u8 s_Uart_2_Send_Buf[UART_SEND_BUF_SIZE] = {0};    /*DMA发送缓存*/

 

static SemaphoreHandle_t s_Uart_2_Send_Lock;      /*串口使用Lock,保证通过串口发送的数据完整性*/

static QueueHandle_t s_Uart_Recv_Queue;    /*与任务通信的消息队列*/

 

/*****************************************************************************

**函 数 名: __Uart_Send_Lock_Init

**输入参数: void  

**输出参数: 无

**返 回 值: 无

**功能描述: 初始化锁和消息队列

**作    者: sdc

*****************************************************************************/

static void __Uart_Send_Lock_Init(void)

{

    s_Uart_2_Send_Lock = xSemaphoreCreateBinary();

    if(NULL == s_Uart_2_Send_Lock)

    {

        printf("lock create fail\n");

    }

    xSemaphoreGive(s_Uart_2_Send_Lock);   /*保证第一次能够发送成功*/

    

    s_Uart_Recv_Queue = xQueueCreate(10, sizeof(UART_DATA *));    /*消息队列,与任务实现通信*/

}

 

/*****************************************************************************

**函 数 名: __Uart_2_Init

**输入参数: u32 baudrate:波特率 

**输出参数: 无

**返 回 值: 无

**功能描述: 初始化串口2和DMA

**作    者: sdc

*****************************************************************************/

static void __Uart_2_Init(u32 baudrate)

{

    GPIO_InitTypeDef     GPIO_InitStruct;

    USART_InitTypeDef    USART_InitStruct;

    DMA_InitTypeDef      DMA_InitStruct;

    

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    

    /*初始化使用USART2使用的引脚, PA2为复用推挽输出,PA3为浮空输入*/

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;

    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_3;

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_Init(GPIOA, &GPIO_InitStruct);

 

    USART_DeInit(USART2);

    USART_InitStruct.USART_BaudRate = baudrate;

    USART_InitStruct.USART_WordLength = USART_WordLength_8b;

    USART_InitStruct.USART_Parity = USART_Parity_No;

    USART_InitStruct.USART_StopBits = USART_StopBits_1;

    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    USART_Init(USART2, &USART_InitStruct);

 

    NVIC_SetPriority(USART2_IRQn, USART2_RX_IDLE_PRIORITY);

    USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);

    NVIC_EnableIRQ(USART2_IRQn);

 

    DMA_DeInit(DMA1_Channel7);

    DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)(&(USART2->DR));

    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;

    DMA_InitStruct.DMA_BufferSize = 1;

    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_Normal;

    DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh;

    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel7, &DMA_InitStruct);

    

    /*使能DMA发送中断*/

    NVIC_SetPriority(DMA1_Channel7_IRQn, USART2_DMA_TX_PRIORITY);

    NVIC_EnableIRQ(DMA1_Channel7_IRQn);

    DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE);

    USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);

 

    /*USART2 recv DMA config*/

    DMA_DeInit(DMA1_Channel6);

    DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)(&(USART2->DR));

    DMA_InitStruct.DMA_MemoryBaseAddr = (u32)s_Uart_2_Recv_Buf;

    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;

    DMA_InitStruct.DMA_BufferSize = UART_RECV_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_Normal;

    DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh;

    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel6, &DMA_InitStruct);

    DMA_Cmd(DMA1_Channel6, ENABLE); 

 

    USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);

 

    USART_Cmd(USART2, ENABLE);

}

二. 串口发送


/*****************************************************************************

**函 数 名: Uart_Send

**输入参数:   u8 *buff:数据缓存  

             u32 len:数据长度

**输出参数: 无

**返 回 值: 

**功能描述: 使用串口发送数据

**作     者: sdc

*****************************************************************************/

void Uart_Send(u8 *buff, u32 len)

{

    xSemaphoreTake(s_Uart_2_Send_Lock, portMAX_DELAY);

    memcpy(s_Uart_2_Send_Buf, buff, len);

    DMA_Cmd(DMA1_Channel7, DISABLE);

    DMA1_Channel7->CMAR = (u32)s_Uart_2_Send_Buf;

    DMA_SetCurrDataCounter(DMA1_Channel7, len);

    DMA_Cmd(DMA1_Channel7, ENABLE);

}

三. DMA中断和串口中断处理


void DMAChannel7_IRQHandler(void)

{

    if(DMA_GetITStatus(DMA1_IT_TC7))

    {

        DMA_ClearITPendingBit(DMA1_IT_TC7);

        xSemaphoreGiveFromISR(s_Uart_2_Send_Lock, &xHigherPriorityTaskWoken);

 

        if(pdFALSE != xHigherPriorityTaskWoken)

        {

            /*can force a contex switch*/

        }

    }    

}

 

void USART2_IRQHandler(void)

{

    if(RESET != USART_GetITStatus(USART2, USART_IT_IDLE))

    {

        USART_ReceiveData(USART2);//读取数据注意:这句必须要,否则不能够清除中断标志位。

        USART_ClearITPendingBit(USART2,USART_IT_IDLE);  

        

        DMA_Cmd(DMA1_Channel6, DISABLE);  

        data_len = UART_RECV_BUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel6);

        DMA_SetCurrDataCounter(DMA1_Channel6, UART_RECV_BUF_SIZE);

        data = pvPortMalloc(data_len + sizeof(UART_DATA)); 

        if(NULL != data)

        {

            data->sender = uart_index;

            data->size = data_len;

            memcpy(data->recv_buf, dma_recv_buff, data_len);

            if(pdPASS != xQueueSendFromISR(s_Uart_Recv_Queue, &data, NULL))

            {

                /*注意错误情况的处理*/

            }

        }

        DMA_Cmd(DMA1_Channel6, ENABLE);  

    }

}

其他:


       如果需要使用3个串口,并且都使用DMA发送和接收,初始化和中断处理函数的重复性太大,应将相同的部分提取出来组成新的函数,以传参的方式进行处理。目前没想到很好的处理方法。


关键字:stm32f103  串口  DMA 引用地址:stm32f103串口实用DMA实现收发

上一篇:stm32f103串口dma配置实例
下一篇:stm32f1串口DMA接收定长数据总结

推荐阅读最新更新时间:2024-03-16 16:22

C51单片机串口通讯注意点
今天在利用C51单片机发数据给PC时,出现了一个小小的问题:如果我要用一个按键来触单片发送5个数据到PC,当单片机复位后,第一次发送的数据总是只有一个数据,而不是5个,当第二次后又正常了。原因是在程序中开了串口中断(ES = 1);大概程序如下: ES = 1; TOMD = 0x20; TR1 = 1; main() {P1.0 = 1; while(P1.0); send(0x00); send(0x01); send(0x02); send(0x03); send(0x04); } 。。。。。。 如果是以上程序,当单片每复位后,按第一次P1.0将只发送00,第二次后会是00,01,02,03,04;
[单片机]
基于stm32f103zet6之使用FSMC驱动TFT的学习
在完成IO驱动彩屏的试验后,就准备着手使用FSMC来驱动彩屏,先了解一下预备知识 一、所谓的FSMC机制 简单介绍FSMC在这篇博文里面很清楚,推荐一下 http://blog.csdn.net/king_bingge/article/details/8718566 然后还有就是这篇学习笔记,也还行 http://www.cnblogs.com/hduxyc/archive/2011/05/17/2048099.html 个人觉得有了这两篇博文再加上我们的参考手册足够搞定FSMC驱动彩屏了 二、FSMC之我见 开始只是谈到别人对FSMC的理解,注意这里只讨论FSMC控制TFT,也就是在FSMC的NOR\PSRAM模式控制LCD
[单片机]
基于<font color='red'>stm32f103</font>zet6之使用FSMC驱动TFT的学习
proteus和labview模拟串口功能
利用proteus和labview模拟串口功能。所需软件有proteus;keil;labview;Virtual Serial Ports Driver。 软件功能介绍:Virtual Serial Ports Driver可以虚拟出一对逻辑上互相连接的串口,假设是com3和com4,则com3和com4在逻辑上是连接在一起的;proteus作为单片机的仿真软件,通过模拟串口com3与上位机通讯;keil是用来编写单片机的代码的,在proteus仿真中,加载keil生成的HEX文件,进行仿真;labview作为上位机的仿真软件,通过串口com4与下位机通讯。 第一步:安装Virtual Serial Ports D
[单片机]
proteus和labview模拟<font color='red'>串口</font>功能
STM32—串口通信
1.串口的基本概念 在STM32的参考手册中,串口被描述成通用同步异步收发器(USART),它提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。USART利用分数波特率发生器提供宽范围的波特率选择。它支持同步单向通信和半双工单线通信,也支持LIN(局部互联网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理器通信。还可以使用DMA方式,实现高速数据通信。 USART通过3个引脚与其他设备连接在一起,任何USART双向通信至少需要2个引脚:接受数据输入(RX)和发送数据输出(TX)。 RX: 接受数据串行输入。通过过采样技术来区
[单片机]
stm32应用-简单的串口接收与发送程序
与上位机的串口通信是一个很常用的程序。碧海蓝天在刚刚接触stm32芯片时写的第一个简单程序就是串口通信,现在把程序代码甩出来与大家分享。完整的程序哦~一般人我不告诉他 库版本 :ST3.0.0 文件:mian.c //功能:串口初始化、打开定时器中断,然后一直接收数据状态就好了。发送在中断中实现 #include stm32f10x.h #include usart.h u8 USART_rx_data; int main(void) { RCC_Configuration(); //系统时钟配置 GPIO_Configuration(); //端口初始化 NVIC_Config
[单片机]
51 单片机串口的扩充方法
基本的 51 单片机有四个并行口,其中还包含了一个串行口。 当接口不够用的时候,大家就会想到,使用什么外接芯片来扩充。 但是,各种教材、参考书、网络文章,介绍扩充并行口的花样不少,扩充串行口的方法,几乎无人问津。 偶尔见到一个,也是使用 8250、8251 等“巨型”芯片来扩充的。 使用这些芯片,就要占用单片机很多的更为紧缺的并行口,基本上就是得不偿失。更别说还要设置复杂的控制字了。 做而论道使用简单的三态门,即可为单片机扩充串行口,仅仅占用单片机的一、二个引脚作为控制引线而已。 这个方法,在以前的各种书籍、杂志、网文中,都没有见到过,可以说是做而论道的独创。 呵呵,小小的自豪一下,请不要拍砖。 实际上
[单片机]
51 单片机<font color='red'>串口</font>的扩充方法
STM32F103标准库开发:Keil5新建STM32工程
新建STM32工程 步骤一:创建工程模板文件 新建一个文件夹 template 在文件夹template里面新建四个文件 (1)CMSIS: 存放内核驱动程序和启动引导文件 (2)FWLIB:存放库函数文件 (3)Project:存放工程文件 (4)User: 存放用户程序(主函数) 具体效果图如下: 步骤二:导入stm32固件库 STM32固件库的下载链接 1. 打开STM32F10x固件库文件 其中需要用到的两个文件:Libraries和Project。 2. 导入文件到 CMSIS 文件 (1)导入内核驱动程序 STM32F10x_StdPeriph_Lib_V3.6.0LibrariesCMSISCM3
[单片机]
<font color='red'>STM32F103</font>标准库开发:Keil5新建STM32工程
DMA基本概念及linux2440下DMA驱动程序编写与测试
1、基本概念 DMA即Direct Memory Access(直接存储器存取),那么为什么要引入这么个东东呢?它的作用又是什么呢?我们通过一个例子来说明: 比 如当我们要往内存里面拷贝一块很大的数据时,由于CPU同一时间只能做一件事情,这样在一段很长的时间里就不能再处理其它事情了,这样就造成了浪费。于是 引入了DMA的概念,所谓DMA就是直接存储器访问,可以不通过CPU而在DMA控制器的控制下,高速地与I/O设备和存储器交换数据。CPU除了在数据 传输开始和结束时做一些处理外,在传输过程中,CPU可以进行其它工作。这样,在大部分的时间里,CPU和输入/输出都处于并行操作状态,大大提高了效 率。 我们需要做的就是将源、目的
[单片机]
<font color='red'>DMA</font>基本概念及linux2440下<font color='red'>DMA</font>驱动程序编写与测试
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved