历史上的今天
返回首页

历史上的今天

今天是:2024年09月11日(星期三)

正在发生

2018年09月11日 | STM32串口+DMA使用1

2018-09-11 来源:eefocus

        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常用库函数:


推荐阅读

史海拾趣

EA Elektro-Automatik公司的发展小趣事

进入21世纪后,EA Elektro-Automatik加大了对研发的投入,致力于技术突破和产品创新。公司成功开发出一系列具有高精度、高可靠性和高性能的电力测试解决方案,如高速模拟稳压器、直流/交流源、并联操作设备等。这些产品不仅满足了市场对精密测试设备的需求,也进一步巩固了EA Elektro-Automatik在电子测量领域的领先地位。

DELTA公司的发展小趣事

为了更好地服务全球客户,Delta公司积极推进全球布局战略。公司在全球范围内设立了多个研发中心和生产基地,如中国大陆、中国台湾、美国、泰国、日本、墨西哥、印度、巴西以及欧洲等地。这些研发中心和生产基地不仅为Delta提供了强大的技术支持和生产能力,还使其能够更快速地响应市场需求,提供更贴近客户的服务。

申风(everanalog)公司的发展小趣事

随着技术实力的不断提升和产品线的日益丰富,申风(everanalog)公司开始积极拓展市场。公司凭借优质的产品和服务,逐渐在国内市场上树立了良好的品牌形象。同时,公司也积极开展国际合作,与国际知名企业建立了战略合作关系,共同推动集成电路产业的发展。这些合作不仅为公司带来了更多的商业机会,也提升了公司在国际市场上的竞争力。

芯旺微电子(ChipON)公司的发展小趣事

芯旺微电子自2012年成立以来,始终致力于高可靠性MCU器件的研发设计。公司凭借其自主研发的KungFu内核架构处理器,迅速在汽车级和工业级混合信号MCU领域崭露头角。随着技术的不断积累和市场的深入拓展,芯旺微电子逐渐从一家初创公司发展成为国内车规级MCU市场的领军企业。

绿宝石(BERYL)公司的发展小趣事

绿宝石公司始终坚持品质至上的原则,对每一道生产工序都进行严格把控。公司引进了先进的生产设备和检测仪器,确保产品质量的稳定性和可靠性。此外,公司还建立了完善的售后服务体系,及时解决客户在使用过程中遇到的问题。凭借卓越的产品品质和优质的服务,绿宝石公司赢得了客户的广泛信赖和好评。

Aromat Corp公司的发展小趣事

在快速发展的过程中,Aromat Corp始终关注社会责任。公司积极参与公益活动,支持教育事业和环保事业。同时,Aromat Corp还注重员工的成长与发展,提供良好的工作环境和福利待遇,激发员工的创新精神和团队合作精神。这些举措不仅提升了公司的社会形象,也为公司的可持续发展奠定了坚实的基础。

这五个故事只是虚构的Aromat Corp公司的发展概况,并不代表任何真实公司的实际情况。每个公司的发展历程都是独一无二的,受到市场环境、技术趋势、管理决策等多种因素的影响。

问答坊 | AI 解惑

VxWorks内核

1, 基本操作系统现代时实操作系统主要的补充了多任务处理和任务间通讯两个概念。多任务环境意味着允许在一个时实应用程序中构架一组独立的任务。每一个都有自己独立的执行路线和自己的系统资源。任务间通讯的机制(facility)则允许任务间的同步和 ...…

查看全部问答>

c# 发送邮件 完整 ini 文件 demo 可运行

接收没有做,发送没有问题,欢迎讨论。 如果第一次输入密码错误,请删除debug目录中的ini文件后重新输入,输入正确后,以后就不用输入用户名密码了^_^…

查看全部问答>

运算放大器、比较器设计指南 第十四版

本帖最后由 paulhyde 于 2014-9-15 04:25 编辑 介绍的比较详细!!!!!!!!  …

查看全部问答>

基于LPC1343的便携式心电图仪设计

这里可以用来描述一些详细的设计思路和者想法或者上传一些参考资料。…

查看全部问答>

请教PowerPC平台下,vxWorks显卡驱动的大小端问题。

我在我们的PowerPC主板上,使用CT69030显卡。设置为1024x768,RGB565,刷新60hz. 图像能够显示,但颜色对不上,Red,green,blue都对不上, 按helenhf 和frank_zhou 的方法试验了一下,发现是字节大小端的问题。 正常情况: 应该 ...…

查看全部问答>

WINCE5保存桌面文件

问一下 我的WINCE的HIVE注册表可以保存成功了 但是不能将文件放到桌面上.因为重启后桌面上的文件就没了..这是为何呀…

查看全部问答>

程序运行了几个小时,但是突然死了,连中断都进不去。。

程序运行了几个小时,但是突然死了,连中断都进不去。。 我通过网络发送同一个命令,在接受中断中保存命令,然后用程序查询的方式查询保存的命令。 但是有时候一个命令完整的执行完成后,向pc发送一个数据,并且pc返回了一个ack应答。然后程 ...…

查看全部问答>

关于STM8Sschematics电压

                                 STM8S schematics 的高低电势触发电压是多少?在哪个文档中有说明?…

查看全部问答>

zigbee抓包截图

抓包软件弄得信号强度测试…

查看全部问答>

msp430 血糖仪原理图PCB和程序谁有呀

msp430  血糖仪原理图PCB和程序谁有呀…

查看全部问答>