硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2143|回复: 8
收起左侧

分享一个串口用DMA方式的程序,可以用中断也可以用DMA方式

  [复制链接]

25

主题

100

回帖

180

积分

初级会员

积分
180
发表于 2018-9-27 15:33:57 | 显示全部楼层 |阅读模式
  1. #include "bsp_uart.h"

  2. #if uart1_enable
  3.         uart_par uart1;
  4. #endif
  5. #if uart2_enable
  6.         uart_par uart2;
  7. #endif
  8. #if uart3_enable
  9.         uart_par uart3;
  10. #endif
  11. #if uart4_enable
  12.         uart_par uart4;
  13. #endif
  14. #if uart1_enable   //如果使能了串口1
  15. /*
  16. * 函数名:bsp_init_uart1
  17. * 参  数:输入的波特率
  18. * 解  释:可以启用DMA方式传输
  19. */
  20. void bsp_init_uart1(uint16_t bound)
  21. {
  22.         GPIO_InitTypeDef GPIO_InitStructure;
  23.           USART_InitTypeDef USART_InitStructure;
  24.         NVIC_InitTypeDef NVIC_InitStructure;

  25. #if uart1_dma_enable //启用DMA
  26.         DMA_InitTypeDef  DMA_InitStructure;
  27. #endif

  28.           RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
  29.           RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

  30. #if uart1_dma_enable
  31.           RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
  32. #endif

  33.           GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
  34.           GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);

  35.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  36.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  37.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  38.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

  39.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9  ;
  40.           GPIO_Init(GPIOA, &GPIO_InitStructure);

  41.           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  42.           GPIO_Init(GPIOA, &GPIO_InitStructure);

  43.         USART_OverSampling8Cmd(USART1, ENABLE);

  44.           USART_InitStructure.USART_BaudRate = bound;
  45.           USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  46.           USART_InitStructure.USART_StopBits = USART_StopBits_1;
  47.           USART_InitStructure.USART_Parity = USART_Parity_No;
  48.           USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  49.           USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  50.           USART_Init(USART1, &USART_InitStructure);

  51. #if uart1_dma_enable

  52.         DMA_InitStructure.DMA_BufferSize = 512 ;
  53.         DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable ;
  54.         DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull ;
  55.         DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
  56.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  57.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  58.         DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  59.         DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t) (&(USART1->DR)) ;
  60.         DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  61.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  62.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  63.         DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  64.         /* Configure TX DMA */
  65.         DMA_InitStructure.DMA_Channel = DMA_Channel_4 ;
  66.         DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral ;
  67.         DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)(uart1.txbuf);
  68.         DMA_Init(DMA2_Stream7,&DMA_InitStructure);
  69.         DMA_Cmd(DMA2_Stream7,ENABLE);

  70.         /* Configure RX DMA */
  71.         DMA_InitStructure.DMA_Channel = DMA_Channel_4 ;
  72.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ;
  73.         DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)uart1.rxbuf;
  74.         DMA_Init(DMA2_Stream5,&DMA_InitStructure);
  75.         DMA_Cmd(DMA2_Stream5,ENABLE);

  76.         USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);                    //使能串口空闲中断

  77.         DMA_ITConfig(DMA2_Stream7,DMA_IT_TC,ENABLE);                        //使能DMA发送中断

  78.         NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn;                //配置DMA发送中断
  79.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //抢断优先级为1
  80.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  81.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  82.         NVIC_Init(&NVIC_InitStructure);

  83.         NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;                        //配置USART为中断源
  84.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;   //抢断优先级为1
  85.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  86.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  87.         NVIC_Init(&NVIC_InitStructure);
  88.         //采用DMA方式发送
  89.     USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
  90.     //采用DMA方式接收
  91.     USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
  92. #else           //采用中断方式接收数据
  93.         USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                           //使能接收中断

  94.         NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;                        //配置USART为中断源
  95.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //抢断优先级为1
  96.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  97.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  98.         NVIC_Init(&NVIC_InitStructure);
  99. #endif
  100.           /* 使能串口 */
  101.           USART_Cmd(USART1, ENABLE);
  102. }

  103. /*
  104. * 函数名:uart1_send
  105. * 参  数:发送数据的长度
  106. * 解  释:DMA发送方式要注意填充的字节的长度
  107. */
  108. void uart1_send(uint16_t len)
  109. {
  110. #if uart1_dma_enable
  111.         //关中断   ,如果有485需要进行设置为发送
  112.         DMA_Cmd(DMA2_Stream7, DISABLE );                                  //关闭USART1 TX DMA1 所指示的通道
  113.         DMA_SetCurrDataCounter(DMA2_Stream7,len);        //DMA通道的DMA缓存的大小
  114.         DMA_Cmd(DMA2_Stream7, ENABLE);                                  //使能USART1 TX DMA1 所指示的通道

  115.         //开中断
  116. #else
  117.         uint16_t i = 0;
  118.         for(i=0;i<;en;i++)
  119.         {
  120.                   while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
  121.                 USART_SendData(USART1,uart1.txbuf[i]);
  122.                 while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
  123.         }
  124. #endif

  125. }
  126. #if uart1_dma_enable
  127. /*
  128. * 函数名:DMA2_Stream7_IRQHandler
  129. * 参  数:DMA发送完成中断
  130. * 解  释:
  131. */
  132. void DMA2_Stream7_IRQHandler(void)
  133. {
  134.          //发送数据完成进入中断  ,进行保护操作,如果有485控制收发,在此处进行设置
  135.         if(DMA_GetITStatus(DMA2_Stream7,DMA_IT_TCIF7))
  136.     {
  137.         DMA_ClearFlag(DMA2_Stream7,DMA_IT_TCIF7);
  138.                 DMA_Cmd(DMA2_Stream7,DISABLE);
  139.     }
  140. }
  141. #endif
  142. /*
  143. * 函数名:USART1_IRQHandler
  144. * 参  数:串口中断
  145. * 解  释:
  146. */
  147. void USART1_IRQHandler(void)
  148. {
  149. #if uart1_dma_enable
  150.           uint16_t num = 0;
  151.         /* USART in DMA mode */
  152.         if (USART_GetITStatus(USART1, USART_IT_IDLE) == SET)
  153.         {
  154.                   DMA_Cmd(DMA2_Stream5,DISABLE);
  155.                 num = USART1->SR;
  156.                 num = USART1->DR;
  157.                 num = 512- DMA_GetCurrDataCounter(DMA2_Stream5);
  158.                 uart1.rxcon = num;                                                //记录数组的长度
  159.                 DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_TCIF5 | DMA_FLAG_FEIF5 | DMA_FLAG_DMEIF5 | DMA_FLAG_TEIF5 | DMA_FLAG_HTIF5);//清除DMA2_Steam7传输完成标志
  160.                 DMA_SetCurrDataCounter(DMA2_Stream5, 512);
  161.                 DMA_Cmd(DMA2_Stream5, ENABLE);                     //打开DMA,
  162.                                                                                                 //进行发送信号量等操作
  163.                 uart1.flag = 1;
  164.         }
  165. #else
  166.         /* USART in Transmitter mode */
  167.         if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
  168.         {
  169.                 uart1.rxbuf[uart1.rxcon++] = USART_ReceiveData(USART1);
  170.                 //进行数据的处理
  171.         }
  172. #endif
  173. }
  174. #endif   //uart1 end
复制代码
  1. #ifndef __BSP_UART_H
  2. #define __BSP_UART_H
  3. #include "stm32f4xx.h"

  4. #define        uart1_enable                1        //串口1
  5. #define        uart1_dma_enable        1   //串口1 DMA方式

  6. #define        uart2_enable                0
  7. #define        uart2_dma_enable        0

  8. #define        uart3_enable                0
  9. #define        uart3_dma_enable        0

  10. #define        uart4_enable                0
  11. #define        uart4_dma_enable        0

  12. typedef struct _uart_par{   //串口数据格式
  13.         uint8_t rxbuf[512];     //接收数据缓存
  14.         uint8_t txbuf[512];                //发送数据缓存
  15.         uint16_t rxcon;                        //接收字节数
  16.         uint16_t txcon;                        //发送字节数
  17.         uint8_t flag;                        //标志位
  18. }uart_par;

  19. #if uart1_enable
  20.         extern uart_par uart1;
  21. #endif
  22. #if uart2_enable
  23.         extern uart_par uart2;
  24. #endif
  25. #if uart3_enable
  26.         extern uart_par uart3;
  27. #endif
  28. #if uart4_enable
  29.         extern uart_par uart4;
  30. #endif



  31. void bsp_init_uart1(uint16_t bound);
  32. void uart1_send(uint16_t len);

  33. #endif
复制代码
可以在头文件里通过宏定义进行开启关闭DMA模式

评分

参与人数 1金币 +100 收起 理由
eric2013 + 100 很给力!

查看全部评分

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107101
QQ
发表于 2018-9-28 00:05:21 | 显示全部楼层
非常感谢楼主分享。
回复

使用道具 举报

610

主题

3063

回帖

4913

积分

至尊会员

积分
4913
发表于 2018-10-1 22:01:08 | 显示全部楼层
回复

使用道具 举报

0

主题

30

回帖

30

积分

新手上路

积分
30
发表于 2018-10-2 20:13:09 | 显示全部楼层
很棒,谢谢分享
回复

使用道具 举报

23

主题

211

回帖

280

积分

高级会员

积分
280
发表于 2018-10-2 22:59:49 | 显示全部楼层
试一下,感谢lz分享
回复

使用道具 举报

2

主题

5

回帖

11

积分

新手上路

积分
11
发表于 2019-5-23 17:58:09 | 显示全部楼层
请问这段程序的作用是什么?新手不太懂 微信截图_20190523175635.png
回复

使用道具 举报

335

主题

2040

回帖

3050

积分

版主

Rank: 7Rank: 7Rank: 7

积分
3050
发表于 2019-9-5 13:39:06 | 显示全部楼层
刹那永恒 发表于 2019-5-23 17:58
请问这段程序的作用是什么?新手不太懂

这个是重置串口接收DMA的计数。
当一帧数据完成后,重新开始DMA接收。
回复

使用道具 举报

1

主题

103

回帖

106

积分

初级会员

积分
106
发表于 2019-9-8 00:53:50 | 显示全部楼层
适合那些STM32的MCU 呀
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107101
QQ
发表于 2019-9-8 01:03:32 | 显示全部楼层

他这个是F4系列的,F407,429这些都可以用
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-18 05:41 , Processed in 0.203556 second(s), 32 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表