[ARM入门] USART+DMA+完成中断

[复制链接]
687|0
 楼主| 鸡蛋鸭蛋荷包蛋 发表于 2023-2-1 12:21 | 显示全部楼层 |阅读模式
本帖最后由 鸡蛋鸭蛋荷包蛋 于 2023-2-1 13:40 编辑

#技术资源#
STM32 DMA定长发送+完成中断
代码测试完成,可以正常运行。
DMA发送需用到串口,故需配置串口。
串口配置
串口配置很简单,照抄就行,这里用的正点原子的源码。
串口配置主要分为定义句柄、开启时钟、配置IO并写入相关寄存器、配置串口模式、开启中断(本代码没有用到接收,所以无所谓)、
  • 定义相关句柄
  1. GPIO_InitTypeDef GPIO_InitStructure;
  2. USART_InitTypeDef USART_InitStructure;
  • 开启时钟(USART1是APB2时钟,IO口是PA9 PA10,A组IO口时钟也是APB2,故一起设置)
  1. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);    //使能USART1,GPIOA时钟
  • 配置IO
  1. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  2. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  3. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出
  4. GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
  1. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  2. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  3. GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  
  • 配置串口模式
  1. USART_InitStructure.USART_BaudRate = bound;//串口波特率
  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;    //收发模式
  • 根据上述配置,初始化串口
  1. USART_Init(USART1, &USART_InitStructure); //初始化串口1
  2. USART_Cmd(USART1, ENABLE);                    //使能串口1
需使用DMA,故需在串口处使能DMA传输
  • 使能DMA传输
  1. USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
  2. USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
DMA配置
到此处,串口配置完毕,接下来配置DMA。
因为使用的是串口1,根据手册查询到对应的DMA为DMA1 4通道(TX)和DMA1 5通道(RX),只使用了TX串口,只需配置TX即可(即DMA1 4通道)。
根据结构体及成员相关解释,配置DMA1 4通道
先配置NVIC中断。
  1. void DMA1_NVIC_Init(void)
  2. {
  3.     NVIC_InitTypeDef NVIC_InitStructure;
  4.         //DMA1通道4 NVIC 配置
  5.   NVIC_InitStructure.NVIC_IRQChannel =  DMA1_Channel4_IRQn;   
  6.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级3
  7.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //子优先级3
  8.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
  9.    
  10. //        //DMA1通道5 NVIC 配置
  11. //    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;                //NVIC通道设置
  12. //    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0 ;                //抢占优先级
  13. //    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;                        //子优先级
  14. //    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                            //IRQ通道使能

  15.     NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器
  16. }
配置DMA
  • 定义句柄
  1. DMA_InitTypeDef DMA_InitStructure;
  • 开启DMA1时钟
  1. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);    //使能DMA传输
  • 根据DMA结构体 配置DMA1 4通道
先调用函数,清除DMA1 4通道配置,配置完成后调用函数
DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);        //DMA通道4传输完成中断
配置DMA1 4通道传输完成中断,使能DMA1 4通道。
  1. DMA_DeInit(DMA1_Channel4);  //重置DMA1 4通道  USART1 TX
  2. /********************************传输方向*****************************/   
  3.     DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&USART1->DR;
  4.     DMA_InitStructure.DMA_MemoryBaseAddr=(u32) usart_txbuf;  //自定义数组
  5.     DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;
  6.    
  7. /********************************数据大小及模式*****************************/        
  8.     DMA_InitStructure.DMA_BufferSize=USART1_MAX_TX_LEN;   //数组大小
  9.     DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
  10.     DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
  11.     DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
  12.     DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
  13.    
  14. /********************************传输模式*****************************/   
  15.     DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
  16.     DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;
  17.    
  18.     DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
  19.    
  20.     DMA_Init(DMA1_Channel4,&DMA_InitStructure);
  21.     DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);        //DMA通道4传输完成中断
  22.     DMA_Cmd(DMA1_Channel4,ENABLE);
  • 配置4通道中断函数
  1. //DMA1通道4中断,判断上次数据串口是否已经发送完成
  2. void DMA1_Channel4_IRQHandler(void)
  3. {
  4.     if(DMA_GetITStatus(DMA1_IT_TC4)!= RESET)    //DMA接收完成标志
  5.     {
  6.         LED1=!LED1;
  7.         DMA_ClearITPendingBit(DMA1_IT_TC4);     //清除中断标志
  8.     }
  9. }
到此,DMA1 4通道配置完成。
主函数
  1. u16 t;
  2. int main(void)
  3. {
  4.     u16 i=0;
  5.     delay_init();             //延时函数初始化
  6.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
  7.     uart_init(115200);         //串口初始化为9600
  8.     LED_Init();                  //初始化与LED连接的硬件接口     
  9.     DMA_init();
  10.      for(i=0;i<USART1_MAX_RX_LEN;i++)
  11.      {
  12.      usart_txbuf[i]=i;
  13.      }
  14.      
  15.     while(1)
  16.     {   
  17.         delay_ms(1000);
  18.         t++;
  19.         if(t%5==0){
  20.         dma1_channel4();
  21.         }
  22.     }
  23. }

注意事项
  • DMA发送完成一次后,需重新设置发送长度才可以再次使用。
  1. /***********************设置DMA1 4缓存大小***********************/
  2. void dma1_channel4(void)
  3. {
  4.      DMA_Cmd(DMA1_Channel4,DISABLE);   //关闭USART1 TX DMA1 所指示的通道  
  5.      DMA_SetCurrDataCounter(DMA1_Channel4,USART1_MAX_RX_LEN);//DMA通道的DMA缓存的大小
  6.      DMA_Cmd(DMA1_Channel4, ENABLE);     //使能USART1 TX DMA1 所指示的通道        
  7. }
  • 使用DMA中断,需提前使能,才可以进入中断。我把串口DMA使能放在串口的初始化函数里,所以串口初始化需在DMA初始化函数之前。
注意代码执行顺序及代码逻辑,无法进入中断的问题找了好久。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

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

本版积分规则

12

主题

85

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部