STM32F4寄存器串口DMA汇总

1.初始化

//RCC
  RCC->APB1ENR|=1<<20;  	//使能串口5时钟 
  RCC->APB1ENR|=1<<19;  	//使能串口4时钟 
  RCC->APB1ENR|=1<<18;  	//使能串口3时钟 
  RCC->APB1ENR|=1<<17;  	//使能串口2时钟 
  RCC->APB2ENR|=1<<4;           //使能串口1时钟
  RCC->APB2ENR|=1<<5;           //使能串口6时钟
  RCC->AHB1ENR|=1<<21;//DMA1时钟使能  
  RCC->AHB1ENR|=1<<22;//DMA2时钟使能

//GPIO
//串口6
  GPIO_AF_Set(GPIOG,9,8);	
  GPIO_AF_Set(GPIOG,14,8);	
  GPIO_Set(GPIOG,PIN9|PIN14,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PD);//复用功能

//UART4
    DMA1_Stream2->PAR=(uint32_t)&(UART4->DR);        //DMA外设地址           多重ADC->CDR
    DMA1_Stream2->CR=0;        //先全部复位CR寄存器值
    DMA1_Stream2->NDTR=50;       //传输数据项个数
    DMA1_Stream2->M0AR= (uint32_t)_rece_data1;            //DMA 存储器0地址
    DMA1_Stream2->CR|=4<<25;     //通道选择4
    DMA1_Stream2->CR|=0<<23;     //存储器单次传输
    DMA1_Stream2->CR|=0<<21;     //外设单次传输
    DMA1_Stream2->CR|=1<<16;     //中等优先级        2:高  3:非常高
    DMA1_Stream2->CR|=0<<13;     //存储器数据大小为8位     0:8位    1:16位  2:32位
    DMA1_Stream2->CR|=0<<11;     //外设数据大小为8位       0:8位    1:16位  2:32位
    DMA1_Stream2->CR|=1<<10;     //存储器地址递增
    DMA1_Stream2->CR|=0<<9;      //外设地址固定
    DMA1_Stream2->CR|=0<<8;     //普通模式
    DMA1_Stream2->CR|=0<<6;     //0:外设到存储器   1:存储器到外设   2:存储器到存储器
    DMA1_Stream2->CR|=1<<4;      //开启传输完成中断 	
    DMA1_Stream2->CR|=1<<0;      //开启DMA传输    
    
    MY_NVIC_Init(3,0,DMA1_Stream2_IRQn,4);	//抢占1,子优先级3,组2	
    MY_NVIC_Init(2,0,UART4_IRQn,4);	//抢占1,子优先级3,组2	
    //波特率为
    temp=(float)(42000000)/(_baud*16);//得到USARTDIV@OVER8=0
    mantissa=(u16)(temp);                 //得到整数部分
    fraction=(u16)((temp-mantissa)*16); //得到小数部分@OVER8=0
    mantissa<<=4;
    mantissa+=fraction;  
    
    UART4->CR1 = 0;
    UART4->CR3 = 0;
    //波特率设置
    UART4->BRR=mantissa;     //波特率设置
    UART4->CR1&=~(1<<15);     //设置OVER8=0
    UART4->CR1|=1<<4;      //空闲中断
    UART4->CR1|=1<<3;      //串口发送使能
    UART4->CR1|=1<<2;      //串口接收使能        
    UART4->CR3|=1<<6;      //开启DMA输出
    //使能
    UART4->CR1|=1<<13;      //串口使能

//UART5
    //接收
    DMA1_Stream0->PAR=(uint32_t)&(UART5->DR);        //DMA外设地址           多重ADC->CDR
    DMA1_Stream0->CR=0;        //先全部复位CR寄存器值
    DMA1_Stream0->M0AR= (uint32_t)_rece_data2;            //DMA 存储器0地址
    DMA1_Stream0->NDTR=50;       //传输数据项个数
    DMA1_Stream0->CR|=4<<25;     //通道选择4
    DMA1_Stream0->CR|=0<<23;     //存储器单次传输
    DMA1_Stream0->CR|=0<<21;     //外设单次传输
    DMA1_Stream0->CR|=1<<16;     //中等优先级        2:高  3:非常高
    DMA1_Stream0->CR|=0<<13;     //存储器数据大小为8位     0:8位    1:16位  2:32位
    DMA1_Stream0->CR|=0<<11;     //外设数据大小为8位       0:8位    1:16位  2:32位
    DMA1_Stream0->CR|=1<<10;     //存储器地址递增
    DMA1_Stream0->CR|=0<<9;      //外设地址固定
    DMA1_Stream0->CR|=0<<8;     //普通模式
    DMA1_Stream0->CR|=0<<6;     //0:外设到存储器   1:存储器到外设   2:存储器到存储器
    DMA1_Stream0->CR|=1<<4;      //开启传输完成中断 
    DMA1_Stream0->CR|=1<<0;      //开启DMA传输 
    MY_NVIC_Init(4,0,DMA1_Stream0_IRQn,4);	//抢占1,子优先级3,组2
    MY_NVIC_Init(3,0,UART5_IRQn,4);	//抢占1,子优先级3,组2

    //发送
  DMA1_Stream7->M0AR= (uint32_t)uart5_send;            //DMA 存储器0地址 
  DMA1_Stream7->NDTR=0;       //传输数据项个数
  DMA1_Stream7->PAR=(uint32_t)&(UART5->DR);        //DMA外设地址           多重ADC->CDR
  DMA1_Stream7->CR=0;        //先全部复位CR寄存器值
  DMA1_Stream7->CR|=4<<25;     //通道选择4
  DMA1_Stream7->CR|=0<<23;     //存储器单次传输
  DMA1_Stream7->CR|=0<<21;     //外设单次传输
  DMA1_Stream7->CR|=3<<16;     //中等优先级        2:高  3:非常高
  DMA1_Stream7->CR|=0<<13;     //存储器数据大小为8位     0:8位    1:16位  2:32位
  DMA1_Stream7->CR|=0<<11;     //外设数据大小为8位       0:8位    1:16位  2:32位
  DMA1_Stream7->CR|=1<<10;     //存储器地址递增
  DMA1_Stream7->CR|=0<<9;      //外设地址固定
  DMA1_Stream7->CR|=0<<8;     //普通模式
  DMA1_Stream7->CR|=1<<6;     //0:外设到存储器   1:存储器到外设   2:存储器到存储器 

    //波特率为
    temp=(float)(42000000)/(_baud*16);//得到USARTDIV@OVER8=0
    mantissa=(u16)(temp);                 //得到整数部分
    fraction=(u16)((temp-mantissa)*16); //得到小数部分@OVER8=0
    mantissa<<=4;
    mantissa+=fraction; 
    UART5->CR1 = 0;
    UART5->CR3 = 0;
    //波特率设置
    UART5->BRR=mantissa;     //波特率设置
    UART5->CR1&=~(1<<15);     //设置OVER8=0
    UART5->CR1|=1<<4;      //空闲中断
    UART5->CR1|=1<<3;      //串口发送使能
    UART5->CR1|=1<<2;      //串口接收使能    
    UART5->CR3|=1<<6;      //开启DMA接收
    UART5->CR3|=1<<7;      //开启DMA发送
    //使能
    UART5->CR1|=1<<13;      //串口使能

//USART6
DMA2_Stream1->PAR=(uint32_t)&(USART6->DR);        //DMA外设地址           多重ADC->CDR
    DMA2_Stream1->CR=0;        //先全部复位CR寄存器值
    DMA2_Stream1->M0AR= (uint32_t)_rece_data3;            //DMA 存储器0地址
    DMA2_Stream1->NDTR=50;       //传输数据项个数
    DMA2_Stream1->CR|=5<<25;     //通道选择5
    DMA2_Stream1->CR|=0<<23;     //存储器单次传输
    DMA2_Stream1->CR|=0<<21;     //外设单次传输
    DMA2_Stream1->CR|=1<<16;     //中等优先级        2:高  3:非常高
    DMA2_Stream1->CR|=0<<13;     //存储器数据大小为8位     0:8位    1:16位  2:32位
    DMA2_Stream1->CR|=0<<11;     //外设数据大小为8位       0:8位    1:16位  2:32位
    DMA2_Stream1->CR|=1<<10;     //存储器地址递增
    DMA2_Stream1->CR|=0<<9;      //外设地址固定
    DMA2_Stream1->CR|=0<<8;     //普通模式
    DMA2_Stream1->CR|=0<<6;     //0:外设到存储器   1:存储器到外设   2:存储器到存储器
    DMA2_Stream1->CR|=1<<4;      //开启传输完成中断 
    DMA2_Stream1->CR|=1<<0;      //开启DMA传输    
    MY_NVIC_Init(5,0,DMA2_Stream1_IRQn,4);	//抢占1,子优先级3,组2
    MY_NVIC_Init(4,0,USART6_IRQn,4);	//抢占1,子优先级3,组2
    //波特率为
    temp=(float)(84000000)/(_baud*16);//得到USARTDIV@OVER8=0
    mantissa=(u16)(temp);                 //得到整数部分
    fraction=(u16)((temp-mantissa)*16); //得到小数部分@OVER8=0
    mantissa<<=4;
    mantissa+=fraction;  
    USART6->CR1 = 0;
    USART6->CR3 = 0;
    //波特率设置
    USART6->BRR=mantissa;     //波特率设置
    USART6->CR1&=~(1<<15);     //设置OVER8=0
    USART6->CR1|=1<<4;      //空闲中断
    USART6->CR1|=1<<3;      //串口发送使能
    USART6->CR1|=1<<2;      //串口接收使能    
    USART6->CR3|=1<<6;      //开启DMA输出
    //使能
    USART6->CR1|=1<<13;      //串口使能

//USART1
DMA2_Stream2->PAR=(uint32_t)&(USART1->DR);        //DMA外设地址           多重ADC->CDR
    DMA2_Stream2->CR=0;        //先全部复位CR寄存器值
    DMA2_Stream2->M0AR= (uint32_t)_rece_data4;            //DMA 存储器0地址
    DMA2_Stream2->NDTR=50;       //传输数据项个数
    DMA2_Stream2->CR|=4<<25;     //通道选择4
    DMA2_Stream2->CR|=0<<23;     //存储器单次传输
    DMA2_Stream2->CR|=0<<21;     //外设单次传输
    DMA2_Stream2->CR|=1<<16;     //中等优先级        2:高  3:非常高
    DMA2_Stream2->CR|=0<<13;     //存储器数据大小为8位     0:8位    1:16位  2:32位
    DMA2_Stream2->CR|=0<<11;     //外设数据大小为8位       0:8位    1:16位  2:32位
    DMA2_Stream2->CR|=1<<10;     //存储器地址递增
    DMA2_Stream2->CR|=0<<9;      //外设地址固定
    DMA2_Stream2->CR|=0<<8;     //普通模式
    DMA2_Stream2->CR|=0<<6;     //0:外设到存储器   1:存储器到外设   2:存储器到存储器
    DMA2_Stream2->CR|=1<<4;      //开启传输完成中断 
    DMA2_Stream2->CR|=1<<0;      //开启DMA传输    
    MY_NVIC_Init(6,0,DMA2_Stream2_IRQn,4);	//抢占1,子优先级3,组2
    MY_NVIC_Init(5,0,USART1_IRQn,4);	//抢占1,子优先级3,组2
    //波特率为
    temp=(float)(84000000)/(_baud*16);//得到USARTDIV@OVER8=0
    mantissa=(u16)(temp);                 //得到整数部分
    fraction=(u16)((temp-mantissa)*16); //得到小数部分@OVER8=0
    mantissa<<=4;
    mantissa+=fraction;  
    USART1->CR1 = 0;
    USART1->CR3 = 0;
    //波特率设置
    USART1->BRR=mantissa;     //波特率设置
    USART1->CR1&=~(1<<15);     //设置OVER8=0
    USART1->CR1|=1<<4;      //空闲中断
    USART1->CR1|=1<<3;      //串口发送使能
    USART1->CR1|=1<<2;      //串口接收使能    
    USART1->CR3|=1<<6;      //开启DMA输出
    //使能
    USART1->CR1|=1<<13;      //串口使能

2.串口空闲中断接收

void UART4_IRQHandler(void)
{ 
  if( ( UART4->SR&(1<<4) ) >> 4 == 1  )  //发生空闲中断
  {
    DMA1_Stream2->CR &= ~(1<<0);      //关闭DMA传输  会发生DMA完成中断 
    UART4->CR1 &= ~(1<<2);  //接收关闭   
    UART4->SR;
    UART4->DR;
  }
}
void DMA1_Stream2_IRQHandler(void)
{
  u8 num = 0;
  if( ( DMA1->LISR&(1<<21) ) >> 21 == 1  )  //完成中断
  {
    DMA1_Stream2->CR &= ~(1<<0);      //关闭DMA传输  
      num = 50 - DMA1_Stream2 ->NDTR; //获取读到的字节数
      if( usart1_nux == 0 )    //互斥量,未使用数据,可进行更改
      {
        for( u8 i =0; i<num; i++ )
        {
          _rece_temp1[i] = _rece_data1[i]; 
        }
      }
      usart1_num = num;
      
      DMA1_Stream2->NDTR = 50; //重新填充
    DMA1->LIFCR |= 1<<21;   //清除完成中断标志位
    DMA1_Stream2->CR |= 1<<0;      //开启DMA传输 
    UART4->CR1 |= 1<<2;  //接收开启  
  }
}


void UART5_IRQHandler(void)
{
  
  if( ( UART5->SR&(1<<4) ) >> 4 == 1  )  //发生空闲中断
  {
    DMA1_Stream0->CR &= ~(1<<0);      //关闭DMA传输 
    UART5->CR1 &= ~(1<<2);  //接收关闭    
    UART5->SR;
    UART5->DR;
  }
}
void DMA1_Stream0_IRQHandler(void)
{
  u8 num = 0;
  
  num = 50 - DMA1_Stream0 ->NDTR; //获取读到的字节数
  if( usart2_nux == 0 )
  {
     for( u8 i =0; i<num; i++ )
     {
        _rece_temp2[i] = _rece_data2[i];
     }
  }
  usart2_num = num;
  DMA1_Stream0->NDTR = 50; //重新填充
  DMA1->LIFCR |= 1<<5;
  DMA1_Stream0->CR |= 1<<0;      //开启DMA传输
  UART5->CR1 |= 1<<2;  //接收开启
}

void USART6_IRQHandler(void)
{ 
  if( ( USART6->SR&(1<<4) ) >> 4 == 1  )  //发生空闲中断
  {
    DMA2_Stream1->CR &= ~(1<<0);      //关闭DMA传输 
    USART6->CR1 &= ~(1<<2);  //接收关闭    
    USART6->SR;
    USART6->DR;
  }
}
void DMA2_Stream1_IRQHandler(void)
{
  u8 num = 0;
  
      num = 50 - DMA2_Stream1 ->NDTR; //获取读到的字节数
      if( usart3_nux == 0 )
      {
        for( u8 i =0; i<num; i++ )
        {
          _rece_temp3[i] = _rece_data3[i];
        }
      }
      usart3_num = num;
      
      DMA2_Stream1->NDTR = 50; //重新填充
    DMA2->LIFCR |= 1<<11; 
    DMA2_Stream1->CR |= 1<<0;      //开启DMA传输
    USART6->CR1 |= 1<<2;  //接收开启
  }
}

void USART1_IRQHandler(void)
{  
  if( ( USART1->SR&(1<<4) ) >> 4 == 1  )  //发生空闲中断
  {
    DMA2_Stream2->CR &= ~(1<<0);      //关闭DMA传输,此时会发生DMA完成中断 
    USART1->CR1 &= ~(1<<2);  //接收关闭 
    USART1->SR;
    USART1->DR;
  }
}
void DMA2_Stream2_IRQHandler(void)
{
  u8 num = 0;
      num = 50 - DMA2_Stream2 ->NDTR; //获取读到的字节数
      if( usart4_nux == 0 )
      {
        for( u8 i =0; i<num; i++ )
        {
          _rece_temp4[i] = _rece_data4[i];
        }
      }
      usart4_num = num;
      DMA2_Stream2->NDTR = 50; //重新填充
    DMA2->LIFCR |= 1<<21; 
    DMA2_Stream2->CR |= 1<<0;      //开启DMA传输 
    USART1->CR1 |= 1<<2;  //接收开启
}


//接收函数
u8 USART_RECE(u8 _sum, u8 *_rece)
{
  u8 temp = 0;
    if(_sum >50)
    {
      _sum = 50;
    } 
    if( usart4_num == 0 )
    {
      return 0;
    }
    else
    {
      usart4_nux = 1;  //互斥量,占用数据
      for( u8 i=0; i<_sum; i++ )
      {
        *_rece = _rece_temp4[i];
        if( i+1 > usart4_num ) //请求读数据量超过接收数据量,后面置0
        {
          *_rece = 0;
        }
        _rece++;
      }
      temp = usart4_num;  
      usart4_nux = 0;  //释放互斥量
      usart4_num = 0;
    } 
  return temp;  //返回接收到的数据个数
}

3.串口DMA发送

//发送函数
void UART5_SEND(u8 _sum, const u8 *_send){
  static uint8_t send_flag = 0;
  u8 *pBuf = NULL;
  pBuf = uart5_send;
  if( _sum > 50 )
  {
    _sum = 50;
  }
  for( u8 i=0; i<_sum; i++ )
  {
    *pBuf++ = *_send++;
  }
  if( send_flag == 0 )  //未进行过发送,直接发
  {
    DMA1_Stream7->NDTR=_sum;         //数据传输量      
    DMA1_Stream7->CR|=1<<0;                      //开启DMA传输  
    send_flag = 1;
  }
  else  //等待发送完成后,再进行发送
  {
    if((DMA1->HISR & (1<<27)) >> 27==1)  //DMA1_Steam7传输完成标志
    {  
      DMA1_Stream7->CR&=~(1<<0); //关闭DMA
      while((DMA1_Stream7->CR & (uint32_t)DMA_SxCR_EN) != 0);  //确保DMA可以被设置 
      DMA1->HIFCR|=1<<27;//清除DMA1_Steam7传输完成标志,不清的话第二次不能发送
      DMA1_Stream7->NDTR=_sum;         //数据传输量      
      DMA1_Stream7->CR|=1<<0;                      //开启DMA传输        
    } 
  }
}
原文地址:https://www.cnblogs.com/penuel/p/13225978.html