打印
[ARM入门]

USART+DMA+完成中断

[复制链接]
470|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 鸡蛋鸭蛋荷包蛋 于 2023-2-1 13:40 编辑

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

    NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器
}
配置DMA
  • 定义句柄
DMA_InitTypeDef DMA_InitStructure;
  • 开启DMA1时钟
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通道。
DMA_DeInit(DMA1_Channel4);  //重置DMA1 4通道  USART1 TX
/********************************传输方向*****************************/   
    DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&USART1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr=(u32) usart_txbuf;  //自定义数组
    DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;
   
/********************************数据大小及模式*****************************/        
    DMA_InitStructure.DMA_BufferSize=USART1_MAX_TX_LEN;   //数组大小
    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;
   
/********************************传输模式*****************************/   
    DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;
   
    DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
   
    DMA_Init(DMA1_Channel4,&DMA_InitStructure);
    DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);        //DMA通道4传输完成中断
    DMA_Cmd(DMA1_Channel4,ENABLE);
  • 配置4通道中断函数
//DMA1通道4中断,判断上次数据串口是否已经发送完成
void DMA1_Channel4_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA1_IT_TC4)!= RESET)    //DMA接收完成标志
    {
        LED1=!LED1;
        DMA_ClearITPendingBit(DMA1_IT_TC4);     //清除中断标志
    }
}
到此,DMA1 4通道配置完成。
主函数
u16 t;
int main(void)
{
    u16 i=0;
    delay_init();             //延时函数初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
    uart_init(115200);         //串口初始化为9600
    LED_Init();                  //初始化与LED连接的硬件接口     
    DMA_init();
     for(i=0;i<USART1_MAX_RX_LEN;i++)
     {
     usart_txbuf[i]=i;
     }
     
    while(1)
    {   
        delay_ms(1000);
        t++;
        if(t%5==0){
        dma1_channel4();
        }
    }
}

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

DMA定长+USART+完成中断.zip

3.17 MB

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

12

主题

85

帖子

1

粉丝