草帽王子 发表于 2021-7-31 19:04:25

第一百零二章:CH32V103应用教程——USART-DMA-TC中断

本章主要实现以下功能:在DMA中处理串口通信,通过DMA实现数据从内存(数组)到外设(串口)的转移,并在DMA数据发送完成之后进入中断并执行中断函数相关程序。

1、DMA简介

每个DMA通道都可以在DMA传输过半、传输完成和传输错误时产生中断。为应用的灵活性考虑,可通过设置寄存器的不同位来打开这些中断,具体如下:

(1)传输过半:对应DMA_INTFR寄存器中的HTIFx位硬件置位。当DMA的传输数目减至初始设定值一半以下将会产生DMA传输过半标志,如果在 DMA_CCRx寄存器中置位了HTIE,则将产生中断。硬件通过此标志提醒应用程序,可以为新一轮数据传输做准备。

(2)传输完成:对应DMA_INTFR寄存器中的TCIFx位硬件置位。当DMA的传输数目减至0将会产生DMA传输完成标志,如果在DMA_CCRx寄存器中置位了TCIE,则将产生中断。

(3)传输错误:对应DMA_INTFR寄存器中的TEIFx位硬件置位。读写一个保留的地址区域,将会产生DMA传输错误。同时模块硬件会自动清0发生错误的通道所对应的DMA_CCRx寄存器的EN位,该通道被关闭。如果在DMA_CCRx寄存器中置位了TEIE,则将产生中断。
应用程序在查询DMA通道状态时,可以先访问DMA_INTFR寄存器的GIFx 位,判断出当前哪个通道发生了DMA事件,进而处理该通道的具体DAM事件内容。

本章主要进行DMA传输完成中断,关于DMA具体介绍,可参考CH32V103应用手册。

2、硬件设计本章教程主要使用DMA进行串口数据传输,所用资源均为CH32V103开发板内部资源,无需进行其他硬件连接,只需进行程序配置即可。可通过串口3与串口调试助手连接查看发送数据。若要通过LED灯看现象,可将PA0与LED1连接,PA1与LED2连接。

3、软件设计

本章教程主要进行DMA传输完成中断实验,具体程序如下:
usart.h文件
#ifndef __USART_H

#define __USART_H



#include "ch32v10x.h"



void LED_GPIO_Config(void);

void USARTx_CFG(void);

void DMA_INIT(void);



#endif
usart.h文件主要进行相关定义和函数声明;
usart.c文件


#include "usart.h"

#include "debug.h"



void DMA1_Channel2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));



//定义SRC_BUF数组作为DMA传输数据源,并将数据存储在内部FLASH中

u8 TxBuffer1[ ]="DMA test: from memory to peripheral";



#define TxSize1   (sizeof(TxBuffer1))



//LED灯初始化配置

void LED_GPIO_Config(void)

{

      /*定义一个GPIO_InitTypeDef类型的结构体*/

      GPIO_InitTypeDef GPIO_InitStructure;

      /*开启LED对应GPIO引脚的外设时钟*/

      RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);

      /*选择要控制的GPIOA引脚*/

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;

      /*设置引脚模式为通用推挽输出*/

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

      /*设置引脚速率为50MHz */

      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

      /*调用库函数,初始化GPIOA*/

      GPIO_Init(GPIOA, &GPIO_InitStructure);

      /*PA0引脚设置低电平 */

      GPIO_SetBits(GPIOA, GPIO_Pin_0|GPIO_Pin_1);

}



/*******************************************************************************

* Function Name: USARTx_CFG

* Description    : Initializes the USART2 & USART3 peripheral.

* Input          : None

* Return         : None

*******************************************************************************/

void USARTx_CFG(void)

{



    GPIO_InitTypeDefGPIO_InitStructure;

    USART_InitTypeDef USART_InitStructure;



    //使能开启GPIOB和USART3时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);



    //串口3对应GPIO引脚初始化

    /* USART3 TX-->B.10RX-->B.11 */

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_Init(GPIOB, &GPIO_InitStructure);



    //串口3初始化配置

    USART_InitStructure.USART_BaudRate = 115200;

    USART_InitStructure.USART_WordLength = USART_WordLength_8b;

    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_Tx | USART_Mode_Rx;

    USART_Init(USART3, &USART_InitStructure);



    USART_Cmd(USART3, ENABLE);//使能串口3

}



/*******************************************************************************

* Function Name: DMA_INIT

* Description    : Configures the DMA for USART3.

* Input          : None

* Return         : None

*******************************************************************************/

void DMA_INIT(void)

{

    DMA_InitTypeDef   DMA_InitStructure;

    NVIC_InitTypeDefNVIC_InitStructure;



    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                     //使能开启DMA时钟



    DMA_DeInit(DMA1_Channel2);

    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART3->DATAR);      /*设置DMA源:串口3数据寄存器地址*/

    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)TxBuffer1;                   /*内存地址(要传输的变量的指针)*/

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                     /*方向:从内存到外设*/

    DMA_InitStructure.DMA_BufferSize = TxSize1;                              /*传输大小DMA_BufferSize=TxSize1*/

    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模式:正常模式,只传输一次。注意:在AD采集之类时要配置成循环模式*/

    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;                  /*优先级:非常高*/

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                           /*禁止内存到内存的传输*/

    DMA_Init(DMA1_Channel2, &DMA_InitStructure);                           /*配置DMA1的2通道*/



    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);



    DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);//使能DMA传输完成中断



    DMA_Cmd (DMA1_Channel2,ENABLE);//使能DMA

}



void DMA1_Channel2_IRQHandler(void)

{

    if(DMA_GetITStatus(DMA1_IT_TC2))

    {

      printf("USART DMA complete\r\n");

      //Delay_Ms(500);

      GPIO_ResetBits(GPIOA, GPIO_Pin_0);

      DMA_ClearITPendingBit(DMA1_IT_TC2); //清除全部中断标志

    }

}
usart.c文件主要对相关外设进行初始化配置和中断服务函数配置。
main.c文件
/********************************** (C) COPYRIGHT *******************************

* File Name          : main.c

* Author             : WCH

* Version            : V1.0.0

* Date               : 2019/10/15

* Description      : Main program body.

*******************************************************************************/



#include "debug.h"

#include "usart.h"



/*******************************************************************************

* Function Name: main

* Description    : Main program.

* Input          : None

* Return         : None

*******************************************************************************/

int main(void)

{



    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    Delay_Init();

    USART_Printf_Init(115200);

    printf("SystemClk:%d\r\n",SystemCoreClock);

    printf("USART DMA TEST\r\n");



    LED_GPIO_Config();

    USARTx_CFG();

    DMA_INIT();



    /*串口3向DMA发出TX请求,此时CPU是空闲的,可以干其他的事情,例如同时控制LED */

    USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);



    Delay_Ms(10);



    while(1)

    {

      //Delay_Ms(500);

      GPIO_ResetBits(GPIOA, GPIO_Pin_1);

      Delay_Ms(500);

      GPIO_SetBits(GPIOA, GPIO_Pin_1);

      Delay_Ms(500);

    }

}main.c文件主要函数初始化以及使能串口3向DMA发出TX请求。

4、下载验证

将编译好的程序下载到开发板并复位,通过串口3与串口调试助手接好之后串口打印如下:

同时可以看到测试板LED1常亮说明进入DMA发送完成中断,同时主函数while(1)循环中LED2闪烁。






页: [1]
查看完整版本: 第一百零二章:CH32V103应用教程——USART-DMA-TC中断