打印
[RISC-V MCU 应用开发]

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

[复制链接]
5000|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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_InitTypeDef  GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    //使能开启GPIOB和USART3时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

    //串口3对应GPIO引脚初始化
    /* USART3 TX-->B.10  RX-->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_InitTypeDef  NVIC_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闪烁。

101、USART-DMA-TC中断.rar

392.91 KB

使用特权

评论回复

相关帖子

沙发
burgessmaggie| | 2022-11-3 21:16 | 只看该作者
怎么判断一帧数据结束了呢              

使用特权

评论回复
板凳
bestwell| | 2022-11-3 21:32 | 只看该作者
USART-DMA需要分配内部的空间吗?

使用特权

评论回复
地板
minzisc| | 2022-11-3 21:51 | 只看该作者
如果启用DMA中断,会不会一个字符就会触发中断呢?

使用特权

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

本版积分规则

132

主题

293

帖子

41

粉丝