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闪烁。
|