环境:


主机:WIN8


开发环境:MDK5.13


mcu: stm32f407VGT6




说明:


之前用STM32F103实现DMA收发串口数据,现在项目中采用STM32F407,所以将此机制移植到F4上。


STM32F103上用DMA收发串口数据文章:


STM32的串口采用DMA方式发送数据测试


STM32的串口采用DMA方式接收数据测试




源代码:


串口初始化代码:


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

* 初始化串口

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

 

static void init_uart(void)

{

//定义中断结构体

NVIC_InitTypeDef NVIC_InitStructure ;

//定义IO初始化结构体

  GPIO_InitTypeDef GPIO_InitStructure;

//定义串口结构体  

USART_InitTypeDef USART_InitStructure;

//定义DMA结构体

DMA_InitTypeDef DMA_InitStructure;

 

//打开串口对应的外设时钟  

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

 

//串口发DMA配置  

//启动DMA时钟

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

//DMA发送中断设置

NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

//DMA通道配置

DMA_DeInit(DMA1_Stream6);

DMA_InitStructure.DMA_Channel = DMA_Channel_4; 

//外设地址

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART2->DR);

//内存地址

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Tx_Buf_Gsm;

//dma传输方向

DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

//设置DMA在传输时缓冲区的长度

DMA_InitStructure.DMA_BufferSize = TX_LEN_GSM;

//设置DMA的外设递增模式,一个外设

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

//设置DMA的内存递增模式

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

//外设数据字长

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

//内存数据字长

DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;

//设置DMA的传输模式

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

//设置DMA的优先级别

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

//指定如果FIFO模式或直接模式将用于指定的流 : 不使能FIFO模式  

DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;    

//指定了FIFO阈值水平

DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;        

//指定的Burst转移配置内存传输 

DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;       

//指定的Burst转移配置外围转移 */  

DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; 

 

//配置DMA1的通道         

DMA_Init(DMA1_Stream6, &DMA_InitStructure);  

//使能中断

DMA_ITConfig(DMA1_Stream6,DMA_IT_TC,ENABLE);   

 

//串口收DMA配置  

//启动DMA时钟

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

//DMA通道配置

DMA_DeInit(DMA1_Stream5);

DMA_InitStructure.DMA_Channel = DMA_Channel_4;

//外设地址

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART2->DR);

//内存地址

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Rx_Buf_Gsm;

//dma传输方向

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

//设置DMA在传输时缓冲区的长度

DMA_InitStructure.DMA_BufferSize = RX_LEN_GSM;

//设置DMA的外设递增模式,一个外设

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

//设置DMA的内存递增模式

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

//外设数据字长

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

//内存数据字长

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

//设置DMA的传输模式

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

//设置DMA的优先级别

DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

//指定如果FIFO模式或直接模式将用于指定的流 : 不使能FIFO模式  

DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;    

//指定了FIFO阈值水平

DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;        

//指定的Burst转移配置内存传输 

DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;       

//指定的Burst转移配置外围转移 */  

DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; 

//配置DMA1的通道         

DMA_Init(DMA1_Stream5, &DMA_InitStructure);  

//使能通道

DMA_Cmd(DMA1_Stream5,ENABLE);

    //初始化串口参数  

    USART_InitStructure.USART_WordLength = USART_WordLength_8b;  

    USART_InitStructure.USART_StopBits = USART_StopBits_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;    

    USART_InitStructure.USART_BaudRate = DEFAULT_BAUD_GSM; 

//初始化串口 

    USART_Init(USART2,&USART_InitStructure);  

//中断配置

USART_ITConfig(USART2,USART_IT_TC,DISABLE);

USART_ITConfig(USART2,USART_IT_RXNE,DISABLE);

USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);  

 

//配置中断  

//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);

    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;               //通道设置为串口中断  

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;       //中断占先等级

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;              //中断响应优先级 

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //打开中断  

    NVIC_Init(&NVIC_InitStructure);   

        

//采用DMA方式发送

USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE);

//采用DMA方式接收

USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);

 

//中断配置

USART_ITConfig(USART2,USART_IT_TC,DISABLE);

USART_ITConfig(USART2,USART_IT_RXNE,DISABLE);

USART_ITConfig(USART2,USART_IT_TXE,DISABLE);

USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);  

    //启动串口  

    USART_Cmd(USART2, ENABLE);    

 

    //设置IO口时钟      

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 

GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2);  

GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2);

 

    //管脚模式:输出口

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

    //类型:推挽模式

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

    //上拉下拉设置

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

//IO口速度

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

    //管脚指定

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;

    //初始化

GPIO_Init(GPIOA, &GPIO_InitStructure);

    //管脚模式:输入口

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

    //上拉下拉设置

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

    //管脚指定

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;

    //初始化

GPIO_Init(GPIOA, &GPIO_InitStructure);      

}



发送数据:


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

* 接口函数:向gsm模块发送数据

*参数:data:发送数据存放地址

*   size:发送数据字节数

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

 

void drv_gsm_tx(uint8_t *data,uint16_t size)

{

//等待空闲

while (Flag_Tx_Gsm_Busy);

Flag_Tx_Gsm_Busy = 1;

//复制数据

memcpy(Tx_Buf_Gsm,data,size);

//设置传输数据长度

DMA_SetCurrDataCounter(DMA1_Stream6,size);

//打开DMA,开始发送

  DMA_Cmd(DMA1_Stream6,ENABLE);

}




中断处理函数:


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

* 接口函数:DMA发送中断处理函数

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

 

void drv_gsm_deal_irq_dma_tx(void)

{

if(DMA_GetITStatus(DMA1_Stream6,DMA_IT_TCIF6) != RESET) 

{

//清除标志位

DMA_ClearFlag(DMA1_Stream6,DMA_FLAG_TCIF6);

//关闭DMA

DMA_Cmd(DMA1_Stream6,DISABLE);

//打开发送完成中断,发送最后两个字节

USART_ITConfig(USART2,USART_IT_TC,ENABLE);

}

}

 

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

* 处理发送完成中断

*返回:0:未产生,1:已经产生

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

 

uint8_t drv_gsm_deal_irq_tx_end(void)

{

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

    {

//关闭发送完成中断

USART_ITConfig(USART2,USART_IT_TC,DISABLE);

//发送完成

        Flag_Tx_Gsm_Busy = 0;

return 1;

    } 

return 0;

}

 

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

* 处理接收完成中断

*参数:buf:接收的数据

*     len:接收的数据长度

*返回:0:未产生,其他:已经产生,此值为接收的数据长度

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

 

uint8_t drv_gsm_deal_irq_rx_end(uint8_t *buf)

{

uint16_t len = 0;

//接收完成中断

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

    {

    USART2->SR;

    USART2->DR; //清USART_IT_IDLE标志

//关闭DMA

    DMA_Cmd(DMA1_Stream5,DISABLE);

//清除标志位

DMA_ClearFlag(DMA1_Stream5,DMA_FLAG_TCIF5);

//获得接收帧帧长

len = RX_LEN_GSM - DMA_GetCurrDataCounter(DMA1_Stream5);

memcpy(buf,Rx_Buf_Gsm,len);

//设置传输数据长度

DMA_SetCurrDataCounter(DMA1_Stream5,RX_LEN_GSM);

    //打开DMA

DMA_Cmd(DMA1_Stream5,ENABLE);

 

return len;

    } 

return 0;

}



中断函数:


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

* GSM模块:DMA发送中断处理函数

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

 

void DMA1_Stream6_IRQHandler(void)

{

    gsm_dma_tx_irq_handler();

}

   

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

* GSM模块:串口中断处理函数

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

 

void USART2_IRQHandler(void) 

{

gsm_irq_handler();

}

注意:


接收完成中断中必须要清除标志位


//清除标志位

DMA_ClearFlag(DMA1_Stream5,DMA_FLAG_TCIF5);

并且必须在关闭DMA之后,这个语句在F103中并非必须的


中断处理函数:


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

* 接口函数:DMA发送中断处理函数

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

 

void gsm_dma_tx_irq_handler(void)

{

inf_gsm_deal_irq_dma_tx();

}

   

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

* 接口函数:串口中断处理函数

*参数:data:接收数据存放地址

*返回:接收数据长度

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

[1] [2]
关键字:STM32F407  串口  DMA  收发数据 引用地址:STM32F407的串口采用DMA收发数据

上一篇:stm32F4各个库文件的作用分析
下一篇:STM32F407上移植emwin

推荐阅读

随着人们生活水平的不断提高,对产品服务的要求也发生了变化,消费端开始升级并带来新的挑战和机遇。而服务机器人似乎为新的时代而生,逐步开始进入社会,进入家庭,服务于平民大众。在2018世界机器人大会上,北京康力优蓝机器人科技有限公司创始人兼首席执行官刘雪楠认为,服务机器人最大的市场是面向家庭的服务机器人,如果从商业价值的角度来讲,最大的...
根据IT专业调查公司IDC统计,2018年全球可穿戴市场增长了27.5%,手表、手环、智能耳机等的销量达到1.722亿台。在中国市场,预计2022年可穿戴设备将达到1.1亿个的规模。常见的可穿戴类产品有健康类产品,此外还有运动类、定位类产品,以及一些具体场景里的智能设备,能够判断我们的情境和活动。近日TDK集团的专家接受了《电子产品世界》的采访,介绍了TDK的...
今年年初以来,由于受到疫情的影响,世界各地在家远程办公、在线教育需求增多,从而带动平板电脑、笔电电脑等产品的市场需求,对显示驱动IC需求也持续提升;加之第三季度以来,TV面板市场需求反弹,导致显示驱动IC市场整体供应偏紧。业内人士指出,由于上游8寸晶圆代工产能偏紧,致使显示驱动IC供货缺口达15%~20%,预计到2021年中才会有所缓解。目前wafer...
广告摘要声明广告秋高气爽的时节智慧的种子悄然结果海康机器人AMR赋能客户数超1500家在通向智能制造的道路上海康机器人矢志不渝服务遍布30+国家及地区国内办事处覆盖24+城市布局杭州+西安两大研发中心硬科技+软科技,双轮驱动海康机器人赋能千行百业的背后蕴含了哪些发展源动力?又为合作伙伴带来哪些智造力?9月27日14:00 智造大会2021 为您揭晓前方6问...

史海拾趣

问答坊 | AI 解惑

菜鸟向高手

各为前辈 大哥 大姐 有谁有有关PCB排板的精谈资料 发晚辈一份 在此万分感谢…

查看全部问答∨

利用DB SDK短信成功应用于证券行业

证券行业普遍面临的问题: 信息交互问题:信息传递的时间段集中、信息交互量大,交互次数频繁,难以实现数据集中以及实时交互管理; 资讯服务问题:股市行情多变,客户不便随时随地及时准确的了解交易情况和信息; 系统及数据安全; 客户管理; ...…

查看全部问答∨

找工作的看过来

我公司最近狂招人!职位有结构,电子,软件。…

查看全部问答∨

江湖救急啊!

  哪位仁兄或仁姐有SSD1963的驱动程序,麻烦给小弟共享一下啊!跪求跪求啦!感激不尽。。。。 哪怕有中文文档或开发历程也行啊,谢谢谢谢! qq:93401862 Email:bin726@163.com 谢谢!!!!…

查看全部问答∨

C51单片机中P0口和P2口作为拓展片外RAM时是如何工作的?

确切的说,我想知道用C语言如何对P0口P2口赋值以达到对片外RAM中数据的访问。但现在的问题是,我不知道P0口和P2口如何工作的?P0口作为“数据/地址”复用端口时,对片外RAM的数据访问是自动切换的,还是要手动的对P0口P2口赋值呢? ============== ...…

查看全部问答∨

C2000最小系统板你最想DIY哪一种型号的?

大家来说说C2000最小系统板你最想DIY哪一种型号…

查看全部问答∨

EXTI 寄存器中挂起寄存器(EXTI_PR)的问题

本人stm32还未入门者,图中画红线的这句话令我犯晕,既然该位被置’1’ 。为什么在该位中写入’1’可以清除它??各位大神求解释 …

查看全部问答∨

圆点博士微型四轴飞行器第二次裸飞成功

圆点博士微型四轴飞行器第二次裸飞成功圆点博士微型四轴飞行器第二次裸飞成功。所谓裸飞是指还没上陀螺仪的PID控制,加电让它飞。 $(\'flv_H1b\').innerHTML=(mobileplayer() ? \"\" : AC_FL_RunContent(\'width\', \'500\', \'height\', \'375\ ...…

查看全部问答∨

ISE 10.1乘法器IP核调用

ISE10.1的乘法器IP核能调用吗?我的为什么用不了啊?或者是我的方法使用不对,,请各位指导一下啊~~感激不尽!!!…

查看全部问答∨

请各位师兄师姐帮忙想个科研课题 做科研立项

小弟是刚开始学的51单片机,想做个科研立项,没有什么好的想法 ,麻烦各位师兄师姐帮帮忙,想下,最好是新颖些,难度不要太难,我想做一次就做好它,先谢谢大家了…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

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

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

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved