找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4129|回复: 4
打印 上一主题 下一主题
收起左侧

STM32 串口DMA收发

[复制链接]
跳转到指定楼层
楼主
ID:351938 发表于 2018-6-14 16:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 mmik 于 2018-6-14 16:51 编辑

最近在做一个STM32单片机的项目,用到串口通信功能。但是目前网上的帖子比较零碎现在整理一份完整的代码发到论坛中。希望能帮到用到的朋友。

关键步骤:

1、初始化串口。
2、初始化DMA通道。
3、配置串口中断,当发生IDLE中断时处理一次DMA数据。
4、配置DMA中断,当发生DMA接收完成时处理一次DMA数据。

上代码:
初始化串口:
  // 通用端口初始化参数
  GPIO_InitTypeDef GPIO_InitStructure;
  // 串口初始化参数
  USART_InitTypeDef USART_InitStructure;
  // 中断向量初始化参数
  NVIC_InitTypeDef NVIC_InitStructure;

  // 启用GPIO总线时钟
  // STM32F1系列GPIO时钟都在APB2总线
  RCC_APB2PeriphClockCmd(uartDef->portAPBxParam, ENABLE);

  // 启用串口总线时钟
  // uart1 在APB2总线,uart2~5 在APB1总线
  if (APB1 == uartDef->uartAPBx)
  {
    RCC_APB1PeriphClockCmd(uartDef->uartAPBxParam, ENABLE);
  }

  else if (APB2 == uartDef->uartAPBx)
  {
    RCC_APB2PeriphClockCmd(uartDef->uartAPBxParam, ENABLE);
  }

  // 设置串口TX发送口
  GPIO_InitStructure.GPIO_Pin   = uartDef->txPin;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;                                //推挽输出
  GPIO_Init(uartDef->txGPIO, &GPIO_InitStructure);                                //初始化GPIOA.9

  // 设置串口RX接收口
  GPIO_InitStructure.GPIO_Pin   = uartDef->rxPin;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;                          //浮空输入
  GPIO_Init(uartDef->rxGPIO, &GPIO_InitStructure);  

  //USART 初始化设置
  USART_InitStructure.USART_BaudRate            = uartDef->uartDcb.baudrate;      //串口波特率,一般设置为9600;
  USART_InitStructure.USART_WordLength          = USART_WordLength_8b;            //字长为8位数据格式
  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(uartDef->port, &USART_InitStructure);                                //初始化串口

  USART_ITConfig(uartDef->port, USART_IT_RXNE, ENABLE);                           //开启接收中断
  USART_ITConfig(uartDef->port, USART_IT_IDLE, ENABLE);                           //开启空闲中断

  //USART NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel                   = uartDef->NVIC_IRQ;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;                       //抢占优先级3
  NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 3;                       //子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;                  //IRQ通道使能
  NVIC_Init(&NVIC_InitStructure);                                                 //根据指定的参数初始化VIC寄存器

  USART_Cmd(uartDef->port, ENABLE);                                               //使能串口

  // 配置DMA收发
DMA_Configuration(port);



//// 配置DMA
  DMA_InitTypeDef DMA_InitStructure;

  //使能DMA传输
  //
  if((0x0400 & (u32)DMA_CHx))
  {
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
  }
  else
  {
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  }
  DMA_Cmd(DMA_CHx, DISABLE);

  DMA_DeInit(DMA_CHx);                                                            //将DMA的通道寄存器重设为缺省值

  DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;                                //DMA外设ADC基地址
  DMA_InitStructure.DMA_MemoryBaseAddr     = cmar;                                //DMA内存基地址
  DMA_InitStructure.DMA_DIR                = dmaDir;                              //数据传输方向,从内存读取发送到外设
  DMA_InitStructure.DMA_BufferSize         = bufferSize;                          //DMA通道的DMA缓存的大小
  DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;           //外设地址寄存器不变
  DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;                //内存地址寄存器递增
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;         //数据宽度为8位
  DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;             //数据宽度为8位
  DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;                     //工作在正常缓存模式
  DMA_InitStructure.DMA_Priority           = DMA_Priority_Medium;                 //DMA通道 x拥有高优先级
  DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;                     //DMA通道x没有设置为内存到内存传输

  DMA_Init(DMA_CHx,&DMA_InitStructure);                                          //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器  
  DMA_ITConfig(DMA_CHx, DMA_IT_TC, ENABLE);
  DMA_Cmd(DMA_CHx, ENABLE);



  // 根据端口选择DMA监听
  switch(port)
  {
    case UART_PORT1:
      NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
    break;
    case UART_PORT2:
      NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;
    break;
    case UART_PORT3:
      NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;
    break;
    case UART_PORT4:
      NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel3_IRQn;
    break;
    default:
      break;
  }

  // 串口5 不支持DMA
  switch(port)
  {
    case UART1:
    case UART2:
    case UART3:
    case UART4:
      // 开启DMA 发送
      USART_DMACmd(uartDef->port,USART_DMAReq_Tx,ENABLE);
      USART_DMA_Config(uartDef->txChannel,
                       0,DMA_DIR_PeripheralDST,
                       (u32)&uartDef->port->DR,(u32)(uartDef->txBuffer));
      // 开启DMA 接收
      USART_DMACmd(uartDef->port,USART_DMAReq_Rx,ENABLE);
      USART_DMA_Config(uartDef->rxChannel,
                       uartDef->rxMaxLen,DMA_DIR_PeripheralSRC,
                       (u32)&uartDef->port->DR,(u32)(uartDef->rxBuffer));

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         
      NVIC_Init(&NVIC_InitStructure);
      break;
    default:
      break;
  }


DMA 中断处理(DMA1_IT_TC6 是指通道6的中断标志)
  if( DMA_GetITStatus(DMA1_IT_TC6)==SET)
  {
    DMA_ClearITPendingBit(DMA1_IT_GL6);

    DMA_Cmd(uartDef->rxChannel,DISABLE);
    uartDef->rxLen = uartDef->rxMaxLen - DMA_GetCurrDataCounter(uartDef->rxChannel);
    if (NULL != uartDef->callback)
    {
      uartDef->callback(UART_PORT2,EVENT_UART_READY_TO_READ,uartDef->customizePara);
    }

    DMA_SetCurrDataCounter(uartDef->rxChannel,uartDef->rxMaxLen);
    DMA_Cmd(uartDef->rxChannel,ENABLE);
  }


USART 中断处理
if(USART_GetITStatus(uartDef->port, USART_IT_IDLE) != RESET)
  {
    res = uartDef->port->SR;
    res = uartDef->port->DR;

    DMA_Cmd(uartDef->rxChannel,DISABLE);
    uartDef->rxLen = uartDef->rxMaxLen - DMA_GetCurrDataCounter(uartDef->rxChannel);

    if (NULL != uartDef->callback)
    {
      uartDef->callback(port,EVENT_UART_READY_TO_READ,uartDef->customizePara);
    }

    DMA_SetCurrDataCounter(uartDef->rxChannel,uartDef->rxMaxLen);
    DMA_Cmd(uartDef->rxChannel,ENABLE);
  }



评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:140371 发表于 2018-6-15 04:57 | 只看该作者
下來學習,謝謝分想
回复

使用道具 举报

板凳
ID:163795 发表于 2018-12-13 10:25 | 只看该作者
厉害厉害,赞一个
回复

使用道具 举报

地板
ID:383374 发表于 2019-1-23 01:40 来自手机 | 只看该作者
下载文件怎么没有
回复

使用道具 举报

5#
ID:397922 发表于 2019-10-17 10:43 | 只看该作者
谢谢分享
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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