STM32
直播中

HTSX

9年用户 780经验值
擅长:可编程逻辑
私信 关注
[问答]

STM32F103ZE该如何去使用串口TX-DMA功能呢

串口TX-DMA功能有何优势?
STM32F103ZE该如何去使用串口TX-DMA功能呢?




回帖(1)

文汝寒

2021-12-14 09:53:09
                                           STM32F103ZE 串口1发送DMA

       最近在使用stm32f103ze-144pin做一个案子,记录一下,毕竟网上有些人也在寻找,或许和我遇到的问题相同,供好学者参考,减少时间。以下程序都基于V3.5.0在野火串口TX-DMA例程基础上进行调整改动,以实现能够软件可控DMA-TX
       案子需要使用串口TX-DMA功能,使用这个的原因在于:不需要用死循环等待发送完成标志位,程序如下:
      (while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);),
       我们都知道,死循环会导致mcu在main函数里面占有很大的无用时间,只能通过中断可以介入触发,而现实中,中断也不是无穷多,并且中断触发过多和中断内容过多,会导致打乱main函数程序,因此在我看来,定时中断函数内容尽可能短,触发时间我一般定为100us,时间长短每个人各不相同,可以根据需要设定。
       进入正题,设定串口DMA程序,我直接贴下:
1,开RCC-DMA时钟,程序:
       RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
2,开NVIC中断,用于在发送一次完成后,DMA触发中断,以此来停止多次循环(DMA_Mode_Circular),程序:
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//组0
      NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;  //DMA1通道4     
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;         //优先级
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;               
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
3,设定DMA相关函数,程序:
     #define USART1_DR_Base  0x40013804  //串口1TX寄存器地址
     #define SENDBUFF_SIZE 10          //10个byte
     uint8_t SendBuff[SENDBUFF_SIZE];//数组存放数据
      DMA_DeInit(DMA1_Channel4);//缺省
      DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;    // 串口1寄存器地址
      DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;//变量指针空间地址
      DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//方向,从内存到外设
      DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//传输大小
      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;    //内存数据单位,8bit
      DMA_InitStructure.DMA_Mode = DMA_Mode_Circular ;    //循环发送,此处如果为normal模式,只会发一次,后面不会再发
      DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级,中
      DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//禁止内存到内存的传输
      DMA_Init(DMA1_Channel4, &DMA_InitStructure);     //  配置DMA1通道 4
      DMA_Cmd (DMA1_Channel4,ENABLE);                    //使能DMA1通道4
      DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);  //DMA发送完后产生中断

     对于为什么串口1发送地址是  0x40013804 ,在《stm32f103数据手册》中有提到,截图如下:





       然后在《stm32f10xxxxx使用手册》中提到了串口发送寄存器USART-DR的相关偏移地址:





       对于选择DMA1通道4的理由在于,32已经规定了DMA1-Channel4是几种外设资源的DMA,而UART1-TX就是其中一种,这一点《stm32f10xxxxx使用手册》也提到了,因此在调用ADC或者是UART2等资源的DMA时候就要注意了。
4,主函数,程序:
    main()
  {
        //初始化;
        while(1)
       {
             //1s定时器标志位,每1s进入一次,使用定时中断,或者delay
             {
                    for(i=0;i<10;i++)//发10个
                   {
                      SendBuff     = i;
                   }
                   USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);//启动发送DMA请求
            }
       }
   }
以上就是将数据i内容压入SendBuff,就可以让DMA发送啦
5,中断函数,程序:
void DMA1_Channel4_IRQHandler(void)
{   
   if(DMA_GetFlagStatus(DMA1_FLAG_TC4)==SET) //判断是否DMA-TX发送完毕
   {  
         USART_DMACmd(USART1, USART_DMAReq_Tx, DISABLE);//失能TX请求,让DMA不再循环发送,没有这句,会一直不断循环发送
       DMA_ClearFlag(DMA1_FLAG_TC4); //清除中断标志位,下次不再进入
     }   
}
        串口相关程序已被我省略,烦请调通串口轮循发送模式后,再看此份文章,谢谢。以上就是我在调试DMA-TX中的设置程序,目前每秒只发送固定10个byte,可通过修改SENDBUFF_SIZE来改变传输数据量。
        如有问题,那也没辙。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分