历史上的今天
返回首页

历史上的今天

今天是:2024年09月24日(星期二)

正在发生

2020年09月24日 | STM32F407的串口采用DMA收发数据

2020-09-24 来源:eefocus

环境:


主机: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:接收数据存放地址

*返回:接收数据长度

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

推荐阅读

史海拾趣

DAESAN公司的发展小趣事

DAESAN公司以其独特的设备回收与再利用技术,在电子行业中崭露头角。起初,公司只是一个小型的设备拆卸公司,但在一次偶然的机会中,他们发现许多被废弃的电子设备中,仍然含有大量可再利用的零部件和材料。于是,DAESAN公司开始专注于电子设备的回收和再利用,通过精细的拆卸和修复技术,将废旧设备转化为新的生产资源。这一举措不仅为公司带来了可观的利润,也为环保事业做出了贡献。

DAYLIGHT公司的发展小趣事

DAYLIGHT公司成立于XX年,由一群富有远见卓识的电子工程师和投资者共同创立。当时,电子行业正经历着快速的技术革新,市场对高效、可靠的电子产品需求日益增加。DAYLIGHT公司凭借其独特的技术优势和创新能力,成功开发出一系列高性能的电子产品,迅速在市场中立足。

Fairchild公司的发展小趣事

随着科技的不断进步和市场环境的变化,Fairchild公司也面临着转型和创新的挑战。为了保持竞争力和市场地位,Fairchild公司不断加大对新技术和新产品的研发投入。同时,公司也积极寻求与其他企业和研究机构的合作,共同推动半导体技术的创新和发展。通过这些努力,Fairchild公司成功实现了从传统半导体制造商向创新型科技企业的转型。

以上五个故事简要概述了Fairchild公司在电子行业发展的历程和成就。作为半导体行业的领军企业之一,Fairchild公司凭借其卓越的技术实力、创新能力和市场洞察力,为电子行业的发展做出了重要贡献。

ANYSOLAR LTD.公司的发展小趣事

ANYSOLAR深知技术创新是企业发展的核心动力。因此,公司不断加大研发投入,引进高端人才,建立完善的研发体系。通过持续的技术创新,ANYSOLAR不断推出性能更优、成本更低的光伏产品,引领着行业的发展潮流。

同时,ANYSOLAR还积极参与行业标准的制定和修订工作,推动整个行业的规范化发展。这些举措不仅提升了ANYSOLAR在行业内的地位,也为公司的长期发展奠定了坚实的基础。

Directed Energy Inc公司的发展小趣事

Directed Energy Inc公司自创立之初,就致力于在电子行业中推动技术创新。公司投入大量研发资源,开发出一系列高性能的脉冲式激光二极管驱动器和高压脉冲模块,这些产品凭借其卓越的性能和稳定性,迅速在市场上获得了认可。随着技术的不断迭代和升级,Directed Energy Inc逐渐在电子行业中树立了技术领先的形象,吸引了众多行业内的设计师和工程师的关注。

DEMMELPRODUCTS公司的发展小趣事

DEMMELPRODUCTS公司自创立之初,就坚持以技术创新为核心竞争力。在公司的早期阶段,研发团队攻克了一项关键技术难题,成功开发出一款具有高性价比和高可靠性的新型电子元件。这款产品凭借其卓越的性能,迅速在市场上脱颖而出,赢得了客户的广泛认可。随着技术的不断迭代和升级,DEMMELPRODUCTS公司逐渐在电子行业中树立了技术领先的形象。

问答坊 | AI 解惑

[资料]基于单片机的四位BCD编码器电路设计

基于单片机的四位BCD编码器电路设计 来源:现代电子技术 作者:刘静波 1 引言 BCD码又称二/十进制码,即二进制编码的十进制码,在设计、测试数字电路硬件过程或是面对带有BCD码接口的集成电路时,常常希望方便、快速地产生BCD码来完成当前的 ...…

查看全部问答>

OK...........................

.............................. [ 本帖最后由 pr8800 于 2009-3-24 17:04 编辑 ]…

查看全部问答>

AD603完整资料!!!

本帖最后由 paulhyde 于 2014-9-15 09:02 编辑 我这里有AD603的完整资料,和大家分享~~~~  …

查看全部问答>

MCF52233_PIT

MCF52233_PIT—Programmable Interrupt Timers   MCF52233有两路的PIT,可以产生精确的定时、延时,用操作系统时用来产生时钟节拍。就三个寄存器PCSR、PMR、PCNTR。很简洁!   PCSR(PIT Control and Status Register),中断标志及控制位、分 ...…

查看全部问答>

示波器与labview的通讯问题

泰克的THS720P, 网上资料说是rs232接口,可示波器上的接口是一个网线类型的(LAN? or LXI?),随机附送的线也是两头都是网线类型的接头,不知该如何与电脑想连?插那里? 谢谢了,…

查看全部问答>

拜求MATLAB仿真与DSP的问题

我做电机控制的仿真,在MATLAB的SINULIN中有电机的模块,可是没有DSP的模块,问能不能在simulik用一个DSP的模块和电机的模块搭建起控制系统的仿真模型? 求解答…

查看全部问答>

很有用,有点不舍的 数控电源

数控电源.rar 数控电源全部资料…

查看全部问答>

基于Windows程序设计的一个小问题

#include LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); //---------以下初始化窗口类------------ int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInst,LPSTR lpszCmdLine,int nCmdShow) {         HWND ...…

查看全部问答>

如何让电动十字滑架移动?

请教各位: 计算机输出信号(偏差量)怎么可以带动电动十字滑架移动?之间需要怎么一个具体的原理,我不懂.需要什么设备,器件请教. 非常感谢! …

查看全部问答>

C51扩展外部RAM,怎么访问?

我用74LS373和74LS138扩展了一片6264 6264的地址是0x6000 用#define XPORT XBYTE[0x6000]定义 要怎样访问6264呢? 用unsinged char xdata temp行吗? 我初学C51,请各位大侠指点一下啊,万分感谢!…

查看全部问答>