STM32串口+DMA使用1

发布者:大酉幽华1最新更新时间:2018-09-11 来源: eefocus关键字:STM32  串口  DMA 手机看文章 扫描二维码
随时随地手机看文章

        STM32有5个串口资源(USART1,USART2,USART3及UART4,UART5)。其中3个USART(通用同步/异步收/发器universalsynchronous asynchronous receiver and transmitter);2个UART(通用异步收/发器universalasynchronous receiver and transmitter);至于USART与UART的区别,如果只是拿来做串口用,没什么区别,在车载项目里,我们拿来做串口用,USART与UART在编程上并没有区别。

        其中USART1,USART2,USART3,UART4支持DMA方式,UART5不支持DMA。(详见数据手册stm32f105&107_datesheet_English的P18/2.3.17)。

        DMA(Derect MemoryAcess直接存储器存取),STM32有2个DMA,DMA1有7个通道,DMA2有5和通道,每个通道对应不同的外设(详见数据手册P272/13.3.7)。


1.时钟RCC配置:

 

串口时钟 + DMA时钟 + IO时钟

 

static void RCC_Configuration(void)

 

{

 

       RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);  //串口时钟       

 

       RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2,ENABLE);  //DMA2时钟 

 

       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC| RCC_APB2Periph_AFIO, ENABLE);//IO时钟

 

 

2.GPIO配置:

 

UART4的TX为PC10脚,发送端配置为复用推挽输出模式(GPIO_Mode_AF_PP)

 

UART4的RX为PC11脚,接收端配置为浮空输入模式(GPIO_Mode_IN_FLOATING)

static void GPIO_Configuration(void)

 

{

 

       GPIO_InitTypeDef GPIO_InitStructure;

              

 

       GPIO_InitStructure.GPIO_Pin =GPIO_Pin_10;              

 

       GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP;  //TX复用推挽输出模式

 

       GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;

 

       GPIO_Init(GPIOC,&GPIO_InitStructure);               

 

       GPIO_InitStructure.GPIO_Pin =GPIO_Pin_11;             

 

       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //RX浮空输入模式

 

       GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;

 

       GPIO_Init(GPIOC,&GPIO_InitStructure);

 

}

 

 

3.中断NVIC配置:

 

配置两个DMA通道中断:

 

UART4的RX的DMA通道为DMA2的通道3;

 

UART4的TX的DMA通道为DMA2的通道5;

 

static void NVIC_Configuration(void)

 

{

 

    NVIC_InitTypeDef NVIC_InitStructure;

 

    NVIC_InitStructure.NVIC_IRQChannel =UART4_IRQn;//串口中断

 

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

 

    NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0;

 

    NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;

 

    NVIC_Init(&NVIC_InitStructure);

 

    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel3_IRQn;

 

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

 

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

 

    NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;

 

    NVIC_Init(&NVIC_InitStructure);

 

    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel5_IRQn;

 

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 

 

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 

 

    NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE; 

 

    NVIC_Init(&NVIC_InitStructure);

 

}

 

 

4.串口配置:

 

即填充串口配置结构体

 

static void UART4_Configuration(void)

 

{

 

       USART_InitTypeDef USART_InitStructure;

 

     

       USART_InitStructure.USART_BaudRate =115200;

 

       USART_InitStructure.USART_WordLength =USART_WordLength_8b;//数据位8位

 

       USART_InitStructure.USART_StopBits =USART_StopBits_1;//停止位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;//TX、RX都开启

 

       USART_Init(UART4,&USART_InitStructure);

 

       USART_Cmd(UART4, ENABLE); //使能UART4外设

 

}

 

 

 

5.DMA配置:

 

DMA可以把数据从外设转移到内存(如串口接收的时候),也可以从内存转移到外设(如串口发送的时候);不同方向的数据转移要各做相应的配置

 

 

 

串口接收:

 

void UART4_Start_DMA_Recv(void * recvBuf, uint32_t bufLen)

 

{

 

    DMA_InitTypeDef DMA_InitStructure;

 

    UART4_Configuration();

 

    /* DMA1 Channel5 (triggered by USART1 Rxevent) Config */

 

    DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)&(UART4->DR);//外设基地址,串口4数据寄存器

 

    DMA_InitStructure.DMA_MemoryBaseAddr =(u32)recvBuf;//内存基地址,数组UART4_DMA_HeadBuf

 

    DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralSRC;//SRC外设到内存

 

    DMA_InitStructure.DMA_BufferSize =bufLen;//DMA数据传输长度

 

    DMA_InitStructure.DMA_PeripheralInc =DMA_PeripheralInc_Disable;//外设地址不自增

 

    DMA_InitStructure.DMA_MemoryInc =DMA_MemoryInc_Enable;//内存地址自增

 

    DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_Byte;//外设数据单位为1字节

 

    DMA_InitStructure.DMA_MemoryDataSize =DMA_MemoryDataSize_Byte;//内存数据单位为1字节

 

    DMA_InitStructure.DMA_Mode =DMA_Mode_Normal;//DMA传输数据模式,正常模式,传一轮

 

    DMA_InitStructure.DMA_Priority =DMA_Priority_High;//DMA通道优先级

 

    DMA_InitStructure.DMA_M2M =DMA_M2M_Disable;//禁止DMA内存到内存传输

 

      

 

    DMA_DeInit(DMA2_Channel3);//UART4的RX为DMA2通道3

 

    DMA_Init(DMA2_Channel3,&DMA_InitStructure);

 

    DMA_ITConfig(DMA2_Channel3, DMA_IT_TC,ENABLE);//配置DMA2发送完成后产生中断

 

    USART_DMACmd(UART4, USART_DMAReq_Rx,ENABLE);//配置串口向DMA发出Tx请求,请求传输数据

 

    DMA_Cmd(DMA2_Channel3, ENABLE);//正式开启DMA

 

}

 

 

 

串口发送:

 

void UART4_Start_DMA_Send(void * sendBuf, uint32_t bufLen)

 

{

 

     DMA_InitTypeDefDMA_InitStructure;

 

    if (bufLen == 0)

 

        return ;

 

        memcpy(UART4_DMA_SendBuf, sendBuf, bufLen);

 

    DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)(&UART4->DR);//外设基地址,串口4数据寄存器

 

    DMA_InitStructure.DMA_MemoryBaseAddr =(uint32_t)UART4_DMA_SendBuf; 

 

    DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralDST;//DST内存到外设 

 

    DMA_InitStructure.DMA_BufferSize =bufLen; 

 

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

 

    DMA_InitStructure.DMA_Mode =DMA_Mode_Normal; 

 

    DMA_InitStructure.DMA_Priority =DMA_Priority_High; 

 

    DMA_InitStructure.DMA_M2M =DMA_M2M_Disable;

 

    DMA_DeInit(DMA2_Channel5); //UART4的TX为DMA2通道5

 

    DMA_Init(DMA2_Channel5,&DMA_InitStructure);          

 

    DMA_ITConfig(DMA2_Channel5, DMA_IT_TC,ENABLE);//配置DMA2发送完成后产生中断

 

    USART_DMACmd(UART4,USART_DMAReq_Tx,ENABLE);//配置串口向DMA发出Tx请求,请求传输数据

 

    DMA_Cmd(DMA2_Channel5, ENABLE);//正式开启DMA

 

    gDMA2Channel5Running = true;

 

}

 

 

 

6.DMA中断函数:

 

串口接收或发送的时候,DMA数据传输完成后会产生中断,在相应中断函数编写代码(注意中断函数名一定要与启动文件中断向量表一致)

 

 

DMA串口接收完成中断:

 

void DMA2_Channel3_IRQHandler(void)//接收完成中断

 

{    

 

    OSIntEnter();//ucos进入中断服务函数

 

    if(DMA_GetITStatus(DMA2_IT_TC3))

 

    {

 

        //获取剩余长度,一般都为0,调试用

 

        DMA_ClearITPendingBit(DMA2_IT_GL3);   //清除全部中断标志  

 

        DMA_Cmd(DMA2_Channel3, DISABLE);

 

        if(0 == DMAReciveState)

 

        {

 

            if(HOST_MSG_START_CODE_FIRST_BYTE== UART4_DMA_HeadBuf[0])//比较读取的第1个字节FF

 

            {

 

                DMAReciveState = 1;

 

                UART4_Start_DMA_Recv((void*)(UART4_DMA_HeadBuf + 1), 3);//再读取后3个字节FFFFFF

 

            }

 

            else

 

            {

 

               UART4_Start_DMA_Recv((void*)UART4_DMA_HeadBuf, 1);

 

            }

 

        }

 

        else if(1 == DMAReciveState)

 

        {

 

            if(HOST_MSG_START_CODE ==*(uint32_t *)UART4_DMA_HeadBuf)//比较整个起始码FFFFFFFF

 

            {

 

                 DMAReciveState = 2;

 

                 UART4_Start_DMA_Recv((void*)(UART4_DMA_HeadBuf + 4), 8);//再读取后8个字节(cmdtype+bodylen)

 

            }

 

            else

 

            {

 

                DMAReciveState = 0;

 

                memset(UART4_DMA_HeadBuf, 0, sizeof(UART4_DMA_HeadBuf));

 

                UART4_Start_DMA_Recv((void*)UART4_DMA_HeadBuf, 1);

 

            }

 

        }

 

        else if(2 == DMAReciveState)

 

        {

 

            HOST_MSG_HEADER_T *pMCUMsgHeader;

 

            DMAReciveState = 3;

 

            pMsgBuffer = (uint8_t*)GetPhoneRecvBuf();//申请一个PhoneRecvBuf接收内存块

 

            if(pMsgBuffer == NULL)

 

            {

 

                DMAReciveState = 0;

 

                memset(UART4_DMA_HeadBuf, 0,sizeof(UART4_DMA_HeadBuf));

 

                UART4_Start_DMA_Recv((void*)UART4_DMA_HeadBuf, 1);

 

                OSIntExit();    //means get out of the inturrept!

 

                return;

 

            }

 

            memcpy(pMsgBuffer,UART4_DMA_HeadBuf, sizeof(HOST_MSG_HEADER_T));//把数组数据(startcode+cmdtype+bodylen)拷贝到内存块

 

            pMCUMsgHeader = (HOST_MSG_HEADER_T*)pMsgBuffer;//指针类型转换

 

           UART4_Start_DMA_Recv((void*)(pMsgBuffer +sizeof(HOST_MSG_HEADER_T)), pMCUMsgHeader->bodyLen + CRC_LEN);//再读取后面数据(data+crc)到内存块

 

        }

 

        else if(3 == DMAReciveState)

 

        {

 

            DMAReciveState = 0;

 

            memset(UART4_DMA_HeadBuf, 0,sizeof(UART4_DMA_HeadBuf));

 

            UART4_Start_DMA_Recv((void*)UART4_DMA_HeadBuf, 1);//此处再读1个字节(起始码第1个字节FF),开始下一轮接收数据

 

            if (pMsgBuffer != NULL)

 

            {

 

                PutMsg2PhoneRecvQueue(pMsgBuffer);//把PhoneRecvBuf接收内存块指针发送到PhoneRecvQ接收消息队列

 

                pMsgBuffer = NULL;

 

            }

 

        }

 

    }

 

 

 

    OSIntExit();//ucos退出中断服务函数

 

}

DMA串口发送完成中断:

 

void DMA2_Channel5_IRQHandler(void)//发送完成中断

{

 

    OSIntEnter();

    if(DMA_GetITStatus(DMA2_IT_TC5)==SET)

 

    {

 

         DMA_ClearFlag(DMA2_IT_GL5);

 

         DMA_Cmd(DMA2_Channel5,DISABLE);

 

         gDMA2Channel5Running = false;

 

    }

    OSIntExit();

 

}

----------------------------------------------------------------------------------------------------------------------------------

附:

DMA常用库函数:


关键字:STM32  串口  DMA 引用地址:STM32串口+DMA使用1

上一篇:STM32串口+DMA的使用2
下一篇:STM32 USART串口DMA 接收和发送的源码详解!

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

串口卡术语详解---总线接口
多用户卡主要有ISA、PCI、USB等几种总线接口。        ISA总线接口        这是早期多用户卡和网卡、显卡等设备使用的一种总线接口, ISA总线多用户卡采用程序请求I/O方式与CPU进行通信,这种方式的网络传输速率低,CPU资源占用较大。        PCI总线接口        PCI总线的英文全称为Peripheral Component Interconnect。即外部设备互联总线,是于1993年推出的PC局部总线标准。PCI总线的主要特点是传输速度高,目前可实现66M的工作频率,在64位总线宽度下可达到突发(Burst)传输速率533MB/s。可以满足大吞吐量的外设的需求。现在主流的多用户卡多为PC
[嵌入式]
使用单片机实现GPRS通信小系统的研究
0 引 言 GPRS(通用分组无线电业务)是利用包交换的概念发展的一套无线传输方式。GPRS网络是基于现有的GSM(全球移动通信系统)网络实现的。在现有的GSM网络中需要增加一些节点,如GGSN(GPRS网关支持节点)和SGSN(GPRS服务支持节点)。SGSN的主要作用是记录移动终端的当前位置信息,并且在移动终端与GGSN之间完成移动分组数据的发送和接收。GGSN主要起网关作用,可以与多种不同的数据网络连接,如ISDN(综合业务数字网)、PSPDN(包交换公用数据网)和LAN(局域网)等。GGSN可以把GSM网中的GPRS分组数据包进行协议转换,从而把这些分组数据包传送到远端的TCP/IP或X.25网络。 GPRS网不但具有
[应用]
基于STM32的printf串口数据输出
该方法适用于STM32,实现了使用printf等标准C流函数输出数据的办法,极大的减少了输出串口数据时所需要做的数据处理。 实现原理 在C库中,printf()等输出流函数都是通过fputc()这个函数实现的,所以我们通过重映射的方式,修改这个函数的定义使它输出在STM32的寄存器中,便可以实现使用printf()函数在STM32串口上输出数据的功能。 Keil环境 重映射 在STM32的Keil开发环境中,C的库函数有两种实现方式 使用标准的C函数库 就是我们平常在PC Window平台上用的C库函数,此库的的优点在于实现的功能全面。但是由于这个库基本上是专为PC设计的,故而如果在嵌入式芯片中调用时将会使得工程文件变
[单片机]
基于<font color='red'>STM32</font>的printf<font color='red'>串口</font>数据输出
如何构建STM32单片机keil的开发环境
新建工程 工程名设为stm32_demo,选择芯片型号为STM32F103B,如图, 因为下载的STM32库中有启动代码,所以这里选择“否”,不拷贝启动代码。 在工程文件下,新建Startup、Headers、User、Libraries、CMSIS、Lists、Output文件夹。 文件夹 用途 Startup 启动文件,Flash在16~32Kb小容量,64~128Kb中容量,256~512Kb大容量 CMSIS Cortex微控制器软件接口标准文件,该目录下文件适用所有Cortex系列 Libraries 存放STM32的驱动库文件 Headers 自定义的全局头文件 User 用户文件,我们把main.c放在该目录
[单片机]
如何构建<font color='red'>STM32</font>单片机keil的开发环境
基于STM32设计的动态密码锁
1. 前言 随着人们生活水平的提高及科学技术的发展,个人信息保护显得至关重要,设计了一款智能电子密码锁,以STM32单片机为主控制器,由触摸矩阵键盘、ESP8266、步进电机等模块组成,具有远程控制、随机密码生成等功能。经软硬件测试,系统响应迅速,灵敏度高,实时性好,系统识别准确率高达99%,该系统运行稳定,安全可靠,功耗低及具有较好的扩展性。 当前支持的开锁方式: (1)手机APP远程开锁。支持手机APP远程开锁。手机APP连接上ESP8266创建的WIFI热点和TCP服务器,可以在手机APP上对设备端的RTC时间进行校准,设备唯一ID获取,生成随机开锁密码。 (2)随机密码开锁。手机APP与本地设备采用时间、作为算
[单片机]
基于<font color='red'>STM32</font>设计的动态密码锁
STM32固件库V3.3.0的CMSIS文件简析
STM32的V3.3.0库,内有CMSIS的文件夹为arm Cortex微控制器软件接口标准,现在将我实际工作中的作一个简要分析: 1.选择启动文件:根据自己所用的芯片的型号,选择正确的启动文件。这个根据数据手册上的划分。例如STM32F101VBT6,就选择startup_stm32f10x_md.s,在这个文件里,首选要定义自已的堆和栈的大小,这个根据自已的需要确定。文件中已经定义好了中断向量的位置及堆和栈的初始化操作。 Reset_Handler PROC EXPORT Reset_Handler IMPORT __main IMPORT SystemInit
[单片机]
STM32 RTOS系统 学习笔记(一)
基本概念 RTOS全称为:Real Time OS,就是实时操作系统,强调的是:实时性。实时操作系统又分为硬实时和软实时。硬实时要求在规定的时间内必须完成操作 ,硬实时系统不允许超时,在软实时里面处理过程超时的后果就没有那么严格。 在实时操作系统中,我们可以把要实现的功能划分为多个任务,每个任务负责实现其中的一部分,每个任务都是一个很简单的程序,通常是一个死循环。
[单片机]
<font color='red'>STM32</font> RTOS系统 学习笔记(一)
STM32 在keil下进行strtol函数的功能测试
STM32 在keil下进行strtol函数的功能测试 源码: void test_str2num_strtol(void) { int a; printf( rnrn0x1234 = %d, ,strtol( 0x1234 ,NULL,0)); printf( rn1234 = %d, ,strtol( 1234 ,NULL,0)); printf( rnHex:1234 = %d, ,strtol( 1234 ,NULL,16)); printf( rn0 = %d, ,strtol( 0 ,NULL,0)); printf( rn01234 = %d, ,strtol( 01234 ,NULL
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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