历史上的今天
返回首页

历史上的今天

今天是:2025年05月24日(星期六)

2019年05月24日 | STM32 USART 使用DMA 详解

2019-05-24 来源:eefocus

前言(绕开吧):

       这段时间由于我们的项目Manibus板卡需要融入 WIFI, BLT, 网口,CAN,串口的多位一体通讯,互不干扰,而且可以相互调用彼此进行数据通讯,这里为了节省MCU资源,所以就使用DMA的方式来进行串口 和 ESP8266的通讯,接下来就介绍一下具体的操作内容!

        DMA具体的不介绍,总的来说,他就是一个中转站,数据给DMA,他帮你传递或接受,你只要读就行了!!

接下来看代码!

        

void localUsartDMAConfig(void){

 

    DMA_InitTypeDef DMA_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

  DMA_DeInit(DMA1_Channel4);

   

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

    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_Send_Branch_Buffer;

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

  DMA_InitStructure.DMA_BufferSize = USART1_BUR_MAX;

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

  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

  DMA_InitStructure.DMA_Priority =DMA_Priority_High;

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  DMA_Init(DMA1_Channel4,&DMA_InitStructure);

  

  DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);

  DMA_ITConfig(DMA1_Channel4,DMA_IT_TE,ENABLE);

USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);

DMA_Cmd(DMA1_Channel4,DISABLE);

  DMA_DeInit(DMA1_Channel5); 

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

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_Rev_Branch_Buffer;

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

DMA_InitStructure.DMA_BufferSize = USART1_BUR_MAX;

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

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

DMA_InitStructure.DMA_Priority =DMA_Priority_High;

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel5,&DMA_InitStructure);

DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);

  DMA_ITConfig(DMA1_Channel5,DMA_IT_TE,ENABLE);

    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);

DMA_Cmd(DMA1_Channel5,ENABLE);

}  

这里我们使用的是 USART1, 其对应的DMA 是 TX ->DMA1_Channel4,RX0->DMA1_Channel5, 这里我们还是使用DMA中断,就是DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);

  DMA_ITConfig(DMA1_Channel4,DMA_IT_TE,ENABLE);这样的好处就是,当数据接收满 或者发送完成后,他能自动重新的让其不使能,或者重新更新!



static void NVIC_Configuration(void)

{

NVIC_InitTypeDef NVIC_InitStructure;

 

//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

 

NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

 

NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

}

这里我们配置NVIC的中断,这里有让DMA有更高的权限,这是为了让他能及时更新!


void localUsartConfig(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

USART_InitTypeDef USART_InitStructure;

 

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

 

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

 

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

 

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(GPIOA, &GPIO_InitStructure);

 

 

USART_InitStructure.USART_BaudRate = 115200;

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_Init(USART1, &USART_InitStructure);

 

USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);

USART_Cmd(USART1, ENABLE);

USART_ClearFlag(USART1,USART_FLAG_TC);

 

localUsartDMAConfig();    //Set DMA 

    NVIC_Configuration();     //Set NVIC

 

USART1_BASE_HAS_BEEN_INIT_FLAG =1;

}

这里配置 USART1,都是常规操作,这里我们使用的是IDLE空闲中断,就是发送一段字节后,串口空闲 没接受下一个数据了就会中断,也就是一个数据包,(以后都为废话)这样也适合我们的项目要求有关,分总线的通讯方式(分线向执行总线传递数据包)这里就要求不能分线数据交错!


void Usart_ReadArray_(uint8_t *array,u16 length)

{

   if(length){  

length =  length > USART1_BUR_MAX ? 1024: length; 

}else{  

return;

}  

     while(USART1_SendFlag_End ==0);

  

   if(array)memcpy(USART1_Send_Branch_Buffer,array,length);

 

DMA_ClearITPendingBit(DMA1_IT_TC4);

   DMA_Cmd(DMA1_Channel4, DISABLE);

   DMA1_Channel4->CNDTR= length;

DMA_Cmd(DMA1_Channel4, ENABLE);

USART1_SendFlag_End = 0;  

 

}

这里不要被函数名误解,功能就是一个串口通过DMA发送字符串的函数! 接下来就到重点了,在配置DMA发送函数的时候,我们设置DMA1_Channel4 的使能为DISABLE,是为了不让他一直发送,配置了ENABLE,你会发现它一直发送 00 00.。。。。这也是很好理解的,所以我们在需要的时候让他使能发送! 函数中有个while是为了让他把已有的数据发送完成,再进行下一个数据包的发送!


void USART1_IRQHandler(void){

 

u16 data_len;

 

 if(USART_GetITStatus(USART1,USART_IT_IDLE)!= RESET){

data_len  =USART1->SR;

data_len  =USART1->DR;

 

DMA_Cmd(DMA1_Channel5,DISABLE);

data_len = USART1_BUR_MAX - DMA_GetCurrDataCounter(DMA1_Channel5);

 

Usart_ReadArray_(USART1_Rev_Branch_Buffer,data_len);

 

DMA_ClearFlag(DMA1_FLAG_GL5 | DMA1_FLAG_TC5 | DMA1_FLAG_TE5 | DMA1_FLAG_HT5); 

DMA1_Channel5->CNDTR = USART1_BUR_MAX;

  

    DMA_Cmd(DMA1_Channel5,ENABLE);

 

  USART_ClearITPendingBit(USART1, USART_IT_IDLE);

}

}

这里判断时候产生空闲中断!  然后我们需要USART_ReceiveData 这里和先USART1->SR;后USART1->DR; 一样;然后读取数据段长度;这里我进行读取在发送进行验证! 后面清除各种标志位;然后DMA重装Size, 使能接收DMA,让其继续接收;最后清除空闲中断的标志位!



void DMA1_Channel4_IRQHandler(void){

 

    DMA_ClearITPendingBit(DMA1_IT_TC4);

  DMA_ClearITPendingBit(DMA1_IT_TE4);

    DMA_Cmd(DMA1_Channel4, DISABLE);

  USART1_SendFlag_End = 1; 

 

}

 

void DMA1_Channel5_IRQHandler(void){

    

  DMA_ClearITPendingBit(DMA1_IT_TC5);

  DMA_ClearITPendingBit(DMA1_IT_TE5);

    DMA_Cmd(DMA1_Channel5, DISABLE); 

    DMA1_Channel5->CNDTR = USART1_BUR_MAX;

  DMA_Cmd(DMA1_Channel5, ENABLE);

}

这里为DMA中断,发送中断是在发送完成后产生的,重新跟新标志位证明发送完成!  接收中断是在接收字节满了后产生的,重装Size!

以上基本结构就配置完成了,有误希望指正!


推荐阅读

史海拾趣

Edsun Laboratories Inc公司的发展小趣事

ECM Electronics Limited.自创立之初,就注重技术创新。公司投入大量研发资金,专注于开发高效、节能的电子产品。通过不断的技术迭代和产品创新,ECM成功推出了一系列具有竞争力的产品,逐渐在市场上建立了良好的口碑。同时,公司还积极与高校和科研机构合作,引进先进技术,为公司的持续发展提供了强大的技术支撑。

Eurosil Electronics Ltd公司的发展小趣事

随着全球对环保问题的日益关注,Eurosil也积极响应这一趋势。公司注重环保和可持续发展,在生产过程中采取了一系列环保措施,如减少废弃物排放、提高能源利用效率等。同时,Eurosil还积极研发环保型电子产品,为客户提供更加绿色、健康的产品选择。

Accetek公司的发展小趣事

Accetek公司深知人才是企业发展的核心竞争力。因此,公司一直注重人才引进和团队建设工作。公司通过与高校合作、举办招聘会等方式吸引了一批批优秀的人才加入。同时,公司还建立了完善的培训机制和激励机制,为员工的成长和发展提供了良好的平台。这些优秀的人才为公司的技术创新和市场拓展提供了有力的支持。

FCT electronic公司的发展小趣事

随着技术的不断成熟和市场需求的增长,FCT electronic公司开始寻求市场扩张和多元化发展。公司决定将产品线拓展至刚挠结合板和挠性加热器领域,以满足不同客户的需求。同时,FCT electronic公司还积极开拓国际市场,通过参加国际展览、与海外企业合作等方式,逐渐在全球电子行业中树立了品牌形象。

浙江凡华(FANHAR)公司的发展小趣事

在电子行业的初期,FCT electronic公司由一群富有远见和激情的工程师创立。他们看到了挠性电路板在未来电子产品中的巨大潜力,并致力于研发出更高效、更可靠的挠性电路板解决方案。经过数年的不懈努力,FCT electronic公司终于研发出了具有革命性意义的挠性电路板技术,这一技术为公司在行业中树立了良好的口碑,也为公司的后续发展奠定了坚实的基础。

Cygnal Integrated Products Inc公司的发展小趣事

为了加快技术发展和市场拓展的步伐,Cygnal积极寻求与其他公司的战略合作。通过与半导体制造商、软件开发商等公司的合作,Cygnal获得了更多的技术支持和市场资源。这些合作不仅提升了Cygnal的技术实力和市场竞争力,还为其未来的发展奠定了坚实的基础。

问答坊 | AI 解惑

微波磁控管的基本结构、参数及正确使用

微波磁控管的基本结构、参数及正确使用 目录0 概述1 阳极2 阴极及其引线3 能量输出器4 磁路系统5 磁控管的正确使用 0  概述    微波能量是由微波发生器产生的,微波发生器包括微波 ...…

查看全部问答>

一年轻董事长给大学生的18条好建议

本帖最后由 paulhyde 于 2014-9-15 03:54 编辑 一年轻董事长给大学生的18条好建议 1.一定要有独立的人格、独立的思想。一个经过独立思考而坚持错误观点的人比一个不假思索而接受正确观点的人更值得肯定。不要成为灌输教育的牺牲品。   2.仕途 ...…

查看全部问答>

讨论IGBT驱动电路

驱动电路的作用是将单片机输出的脉冲进行功率放大,以驱动IGBT.保证IGBT的可靠工作,驱动电路起着至关重要的作用,对IGBT驱动电路的基本要求如下: (1) 提供适当的正向和反向输出电压,使IGBT可靠的开通和关断. (2) 提供足够大的瞬态功率或瞬时电流, ...…

查看全部问答>

有人做pxa270下的vxWorks bsp 开发吗?

涉及到lcd方面的开发怎么做的?哪里有资料下载? …

查看全部问答>

问个关于EDMA的问题

   我对单元计数不太理解,是不是可以这样说:单元计数只用在一维源到一维目的的传输中,,而对于一维到二维、二维到一维、二维到二维的传输统统单元计数不变化?    是不是说,EDMA的传输只要源维数或者目的维数有一个是二维 ...…

查看全部问答>

看看我的成果

本人长期从事单片机开发应用,积累了一定的经验。本人将毕生研究心得集成了文字,放在我的博客里,希望大家光临指导,并给点意见。我的博客地址;http://blog.mcuol.com/user/Article/500.html…

查看全部问答>

time_limited.sof

用DSP_builder完成的工程,quartus编译时为什么产生的是time_limited.sof文件?该怎样解决?破解都是没问题的…

查看全部问答>

IAR中等优化太恐怖了,把我的条件判断给杀了

#pragma vector=UART0RX_VECTOR __interrupt void usart0_rx (void) { int print_data,temp0,temp1,temp2,temp3,temp4,temp5; clear_wdt(); rx_temp = RXBUF0; TXBUF0 = RXBUF0; snd[uart_temp] = rx_temp; ...…

查看全部问答>

MSP30如何实现掉电保护数据的功能???

我现在想做个系统,用于测量一些数据,测量的数据保存在变量里,每天早八点向FLASH保存一次,但怕中间没电。请问大家MSP430F1XX或其它型号能实现这个功能吗?…

查看全部问答>

求msp430f4784的相关源程序

大神,求msp430f4784的相关源程序。 大神,求msp430f4784的相关源程序。…

查看全部问答>