STM32——DMA接收和发送的实现

最近写程序,需要一段一段数据的接收,再通过其他串口发送出去。

老司机们建议用DMA通信,以节约CPU资源。然后,我听了,发现挺好用的。特此,把自己写的代码贴上了。

DMA发送接收的步骤如下:

1.初始化。

a.IO时钟+串口时钟+DMA时钟使能。

b.IO初始化

c.串口初始化

d.DMA初始化

e.中断向量设置

2.串口中断服务函数

3.DMA中断服务函数

具体实现如下:

一。初始化

1 //串口1的初始化2 //bound:波特率
3 /************************************************/
4 void uart1_init(u32 bound)
5 {
6     GPIO_InitTypeDef GPIO_InitStructure;
7     USART_InitTypeDef USART_InitStructure;
8     NVIC_InitTypeDef NVIC_InitStructure;
9     DMA_InitTypeDef DMA_InitStructure;

1。IO时钟+串口时钟+DMA时钟使能。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);    //串口1时钟初始化+GPIOA时钟初始化
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);   //DMA1初始化

2.IO初始化

 1     USART_DeInit(USART1);  //¸´Î»´®¿Ú1
 2     //USART1_TX   PA.9
 3   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
 4   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 5   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //¸´ÓÃÍÆÍìÊä³ö
 6   GPIO_Init(GPIOA, &GPIO_InitStructure); //³õʼ»¯PA9
 7   //USART1_RX      PA.10
 8   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
 9   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//¸¡¿ÕÊäÈë
10   GPIO_Init(GPIOA, &GPIO_InitStructure);  //³õʼ»¯PA10

3.串口初始化

 1     USART_InitStructure.USART_BaudRate = bound;//Ò»°ãÉèÖÃΪ9600;
 2     USART_InitStructure.USART_WordLength = USART_WordLength_8b;//×Ö³¤Îª8λÊý¾Ý¸ñʽ
 3     USART_InitStructure.USART_StopBits = USART_StopBits_1;//Ò»¸öֹͣλ
 4     USART_InitStructure.USART_Parity = USART_Parity_No;//ÎÞÆæżУÑéλ
 5     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//ÎÞÓ²¼þÊý¾ÝÁ÷¿ØÖÆ
 6     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //ÊÕ·¢Ä£Ê½
 7   USART_Init(USART1, &USART_InitStructure); //³õʼ»¯´®¿
 8
 9     USART_ITConfig(USART1, USART_IT_IDLE , ENABLE);//¿ªÆôÖжÏ
10     USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);//串口发送DMA使能
11     USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);//串口接收DMA使能
12   USART_Cmd(USART1, ENABLE);//ʹÄÜ´®¿Ú
13     USART_ClearFlag(USART1,USART_FLAG_TC);//Çå³ý·¢ËÍÍê³É±êÖ¾

4。DMA初始化

 1 //DMA1_Channel5 -> USART1_Rx
 2     DMA_Cmd(DMA1_Channel5,DISABLE);
 3     DMA_DeInit(DMA1_Channel5);
 4     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);//ÍâÉèΪUSART2->DR
 5     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_Receive_Data;//ÄÚ´æ»ùµØÖ·
 6     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//ÍâÉè×÷ΪÊý¾Ý´«ÊäµÄÄ¿µÄµØ£¬½ÓÊÕ
 7     DMA_InitStructure.DMA_BufferSize = 1024;//ÄÚ´æ´óС
 8     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//ÍâÉèµØÖ·¼Ä´æÆ÷²»±ä
 9     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//ÄÚ´æµØÖ·¼Ä´æÆ÷µÝÔö
10     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//Êý¾Ý¿í¶ÈΪ8λ
11     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//Êý¾Ý¿í¶ÈΪ8λ
12     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//¹¤×÷ÔÚÕý³£»º´æģʽ
13     DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMAͨµÀ5¾ßÓиßÓÅÏȼ¶
14     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//DMAͨµÀ6ûÓÐÉèÖÃΪÄÚ´æµ½ÄÚ´æ´«Êä
15     DMA_Init(DMA1_Channel5,&DMA_InitStructure);
16     DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);//ʹÄÜ´«ÊäÍê³ÉÖжÏ
17     DMA_Cmd(DMA1_Channel5,ENABLE);
18     //DMA1_Channel4 -> USART1_Tx
19     DMA_Cmd(DMA1_Channel4,DISABLE);
20     DMA_DeInit(DMA1_Channel4);
21     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);//ÍâÉèΪUSART2->DR
22     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART_Send.USART1_Send_Data;//ÄÚ´æ»ùµØÖ·
23     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//ÍâÉè×÷ΪÊý¾Ý´«ÊäµÄÀ´Ô´£¬·¢ËÍ
24     DMA_InitStructure.DMA_BufferSize = 1024;//ÄÚ´æ´óС
25     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//ÍâÉèµØÖ·¼Ä´æÆ÷²»±ä
26     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//ÄÚ´æµØÖ·¼Ä´æÆ÷µÝÔö
27     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//Êý¾Ý¿í¶ÈΪ8λ
28     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//Êý¾Ý¿í¶ÈΪ8λ
29     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//¹¤×÷ÔÚÕý³£»º´æģʽ
30     DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//DMAͨµÀ5¾ßÓиßÓÅÏȼ¶
31     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//DMAͨµÀ6ûÓÐÉèÖÃΪÄÚ´æµ½ÄÚ´æ´«Êä
32     DMA_Init(DMA1_Channel4,&DMA_InitStructure);
33     DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);//ʹÄÜ´«ÊäÍê³ÉÖжÏ
34     DMA_Cmd(DMA1_Channel4,ENABLE);

5.中断向量设置

 1     //USART1_NVIC
 2   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
 3     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//ÇÀÕ¼ÓÅÏȼ¶1
 4     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //×ÓÓÅÏȼ¶0
 5     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQͨµÀʹÄÜ
 6     NVIC_Init(&NVIC_InitStructure);    //¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯VIC¼Ä´æÆ
 7     //DMA_Channel5 NVIC -> USART1_Rx
 8     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
 9     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
10     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
11     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
12     NVIC_Init(&NVIC_InitStructure);
13     //DMA_Channel4 NVIC -> USART1_Tx
14     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
15     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
16     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
17     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
18     NVIC_Init(&NVIC_InitStructure);
}

//以上的话,初始化就完成了~~~~~,下面是USART中断服务函数

二。串口中断函数

 1 #if EN_USART1_RX   //Èç¹ûʹÄÜÁ˽ÓÊÕ
 2 void USART1_IRQHandler(void)                    //´®¿Ú1ÖжϷþÎñ³ÌÐò
 3 {
 4     u16 DATA_LEN;
 5     u16 i = 0;
 6     u8 Res;
 7     if(USART_GetITStatus(USART1, USART_IT_IDLE ) != RESET)  //¿ÕÏÐÖжÏ
 8     {
 9         Res = USART1->SR;
10         Res = USART1->DR;//Çå³ý¿ÕÏÐÖжϱêÖ¾
11
12         DMA_Cmd(DMA1_Channel5,DISABLE);//¹Ø±ÕDMA,·ÀÖ¹´¦ÀíÆä¼äÓÐÊý¾Ý
13         DATA_LEN = 1024 - DMA_GetCurrDataCounter(DMA1_Channel5);//»ñÈ¡Êý¾Ý³¤¶È
14         //±£´æ½ÓÊÕµ½µÄÊý¾Ý,·ÅÖõ½USART2_SendData
15         USART_Send.USART1_Len_R = DATA_LEN; //±£´æÊý¾Ý³¤¶È
16         for(i=0;i<DATA_LEN;i++)
17         {
18             USART_Send.USART1_Receive_Data[i] = USART1_Receive_Data[i];//±£´æÊý¾Ý
19         }
20         USART_Send.USART1_Rx_Finish = 1;//±êÖ¾ÖÃ1£¬±íʾÊý¾Ý±£´æÍê±Ï
21
22         DMA1_Channel5->CNDTR = 1024;//ÖØÐÂÉèÖÃDMA1_Channel5µÄÊý¾Ý´«ÊäÊýÁ¿
23         DMA_Cmd(DMA1_Channel5,ENABLE);//¿ªÆôDMA1_Channel5
24     }
25
26 } 

三。DMA通道中断服务函数

//DMA1_Channel5-RxÖжϷþÎñº¯Êý,usart1_Rx
void DMA1_Channel5_IRQHandler(void)
{
    DMA_ClearITPendingBit(DMA1_IT_TE5);//Çå³ý´íÎóÖжÏ
    if(DMA_GetITStatus(DMA1_IT_TC5))//·¢ÉúÁË´«ÊäÍê³ÉÖжÏ
    {
        u16 DATA_LEN;
        u16 i = 0;
        u8 Res;
        DMA_ClearITPendingBit(DMA1_IT_TC5);//Çå³ýÖжÏÍê³É±êÖ¾
        DMA_Cmd(DMA1_Channel5,DISABLE);//¹Ø±ÕDMA,·ÀÖ¹´¦ÀíÆÚ¼äÓÐÊý¾Ý

        DATA_LEN = 1024 - DMA_GetCurrDataCounter(DMA1_Channel5);//»ñÈ¡Êý¾Ý³¤¶È
        //±£´æ½ÓÊÕµ½µÄÊý¾Ý,·ÅÖõ½USART2_SendData
        USART_Send.USART1_Len_R = DATA_LEN; //±£´æÊý¾Ý³¤¶È
        for(i=0;i<DATA_LEN;i++)
        {
            USART_Send.USART1_Receive_Data[i] = USART1_Receive_Data[i];//±£´æÊý¾Ý
        }
        USART_Send.USART1_Rx_Finish = 1;//±êÖ¾ÖÃ1£¬±íʾÊý¾Ý±£´æÍê±Ï

        DMA1_Channel5->CNDTR = 1024;//ÖØÐÂÌî×°
        DMA_Cmd(DMA1_Channel5,ENABLE);//´¦ÀíÍê³Éºó£¬ÖØ¿ªDMA
    }
}
//DMA1_Channel4-TxÖжϷþÎñº¯Êý,usart1_Tx
void DMA1_Channel4_IRQHandler(void)
{
    DMA_ClearITPendingBit(DMA1_IT_TE4);//Çå³ý´íÎóÖжϱêÖ¾
    if(DMA_GetITStatus(DMA1_IT_TC4))//·¢Éú´«ÊäÍê³ÉÖжϱêÖ¾
    {
        DMA_ClearITPendingBit(DMA1_IT_TC4);//Çå³ýÖжϱêÖ¾
        DMA_Cmd(DMA1_Channel4,DISABLE);//¹Ø±ÕÖжÏ
        USART_Send.USART1_Tx_Finish = 0;
    }
}

很困,别的+注释这周补上。。。

时间: 2024-12-15 01:02:20

STM32——DMA接收和发送的实现的相关文章

STM32的USART使用DMA接收带校验位的数据

工作中用到了一个数据包里面的数据采用不同的校验方式,一部分为奇校验,一部分为偶校验.这时我的方案为: 1.USART设置9bit数据长度,1个停止位,无校验位,这时确保能接收到带校验位的数据 2.设置DMA接收和发送数据,设置外设地址和内存地址都为halfword(16bit)可以接收到带校验位的数据包. 3.然后通过软件来校验接收到的数据 4.由于设置了无校验位,那么此时用发送的数据必须加上软件计算出的校验位发送

STM32的PWM输入模式设置并用DMA接收数据

STM32的PWM输入模式设置并用DMA接收数据 项目中需要进行红外学习,如果采用输入捕获的方式,因为定时器只能捕获上升沿或者下降沿, 所以只能获得周期,而不能得到具体的红外波的高低电平的时间. 所以采用PWM输入的方式进行捕获. 采用的是PA8脚,对应TIM1的通道1. /********************************************************************* * 函数 *************************************

串口通信基础,接收,发送数据

通信接口背景知识 设备之间通信的方式 一般情况下,设备之间的通信方式可以分成并行通信和串行通信两种.它们的区别是: 串行通信的分类 1.按照数据传送方向,分为: 单工:数据传输只支持数据在一个方向上传输:    半双工:允许数据在两个方向上传输.但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信:它不需要独立的接收端和发送端,两者可以合并一起使用一个端口.    全双工:允许数据同时在两个方向上传输.因此,全双工通信是两个单工通信方式的结合,需要独立的接收端和发送端.

stm32 DMA数据搬运 [操作寄存器+库函数](转)

源:stm32 DMA数据搬运 [操作寄存器+库函数] DMA(Direct Memory Access)常译为“存储器直接存取”.早在Intel的8086平台上就有了DMA应用了. 一个完整的微控制器通常由CPU.存储器和外设等组件构成.这些组件一般在结构和功能上都是独立的,而各个组件的协调和交互就由CPU完成.如此一来,CPU作为整个芯片的核心,其处理的工作量是很大的.如果CPU先从A外设拿到一个数据送给B外设使用,同时C外设又需要D外设提供一个数据...这样的数据搬运工作将使CPU的负荷显

STM32 DMA

开发平台: STM32Cube + STM32F030R8T6 问题:  STM32 SPI DMA 无法正常发送 解决办法: DMA时钟必须在DMA初始化钱开启,而且DMA中设置自增模式   1. M32Cube 中生成的代码中,有SPI 和DMA的初始化,DMA的时钟初始化在DMA_INIT 中,但是其配置在SPI 中,所以,一定要把DMA_INIT放在SPI_INIT 前面. 2. DMA的配置中,需要设置目标地址和源地址的自增选项   吸取教训: 在使用某个模块之前一定要先去搞懂这个模块

STM32 DMA简述

STM32 DMA简述 DMA (Direct Memory Access) 直接内存存储器,在做数据传输时能够大大减轻CPU的负担. DMA的作用 DMA提供了一个关于数据的高数传输通道,这个通道不占用CPU的资源.换句话说,通过DMA通道,你在传输大规模数据的时候CPU同时也能够去干其他事. 你可以控制DMA通道的接入口,灵活配置传输的数据源和目的地.以下几个是常用的DMA传输路径: 从外设到内存 从内存A区域传到内存B区域 从一个外设传输到另一个外设 从内存传输数据到外设 .... DMA

STM32 DMA使用详解

DMA部分我用到的相对简单,当然,可能这是新东西,我暂时还用不到它的复杂功能吧.下面用问答的形式表达我的思路. DMA有什么用? 直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输.无须CPU的干预,通过DMA数据可以快速地移动.这就节省了CPU的资源来做其他操作. 有多少个DMA资源? 有两个DMA控制器,DMA1有7个通道,DMA2有5个通道. 数据从什么地方送到什么地方? 外设到SRAM(I2C/UART等获取数据并送入SRAM): SRAM的两个区域之间: 外设

STM32串口接收小结

STM32串口接收数据 稍微理一下思路,一个数据从电脑发送到STM32,然后在从STM32返回到电脑显示出来. 如上图所示,发送(1所示的路线)前,STM32的淳口需要初始化的设置.包括:波特率,字长,硬件流,停止位,奇偶校验位,模式(接收,发送,接收和发送),串口的基地址(Instance).在初始化串口的函数里面,需要调用到HAL_UART_MspInit(),这是一个虚函数(_weak),HAL_UART_MspInit()会调用到HAL_GPIO_Init(),把IO口进行配置.(模式,

Android接收和发送短信

每一部手机都具有短信接收和发送功能,下面我们通过代码来实现接收和发送短信功能. 一.接收短信 1.创建内部广播接收器类,接收系统发出的短信广播 2.从获得的内容中解析出短信发送者和短信内容 3.在Activity中注册广播 4.添加接收短信权限 下面放上具体的代码 activity_main.xml文件用于显示短信发送者号码和显示短信内容 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout