功能:采用DMA进行USART的发送,程序运行时,LED1亮灭交替,表示程序正在运行。

当按下KEY0时,产生一个下降沿触发中断,在中断函数中实现DMA的数据传输到USART1上。


//key.h

#ifndef __KEY_H__
#define __KEY_H__
#include "stm32f10x.h"

void Key_Configuration(void);
void EXTI4_IRQHandler(void); //中断

#endif

//key.c

#include "key.h"
#include "MyTime.h"
#include "bitband.h"
#include "dma.h"


void Key_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	EXTI_InitTypeDef EXTI_InitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO,ENABLE);

	//GPIO_DeInit(GPIOE); //此处绝对不能使用GPIO_DeInit进行默认初始化,因为GPIOE在前的其他地方已经对其某些引脚进行初始化了,这里若使用默认初始化,则会清除之前进行的配置。切记切忌
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU ; //上拉输入
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
	GPIO_Init(GPIOE,&GPIO_InitStruct);
	GPIO_SetBits(GPIOE,GPIO_Pin_4);

	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);//将中断线4与GPIO引脚联系起来
	
	EXTI_DeInit(); //第一次配置中断,可用默认配置,若之前有配置过EXTI,这里最好不要在用默认配置
	EXTI_InitStruct.EXTI_Line = EXTI_Line4;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling ;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组
	NVIC_InitStruct.NVIC_IRQChannel = EXTI4_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);

}

extern u32 DMA1_MEM_LEN; //传输数据长度
void EXTI4_IRQHandler(void)
{
	MyDelay_ms(10);
	if(EXTI_GetITStatus(EXTI_Line4) == SET)
	{
		LED0 = !LED0;
		USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);   //使能串口1的DMA发送
		DMA_Start(DMA1_Channel4,DMA1_MEM_LEN);	       //开始一次DMA传输
		while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET); //传输未结束		 
		
		DMA_ClearFlag(DMA1_FLAG_TC4); 		
		EXTI_ClearITPendingBit(EXTI_Line4);
	}

}

//dma.h

#ifndef __DMA_H__
#define __DMA_H__

#include "stm32f10x.h"

void DMA_Configuration(u32 DMA_PeripheralBaseAddr,u32 DMA_MemoryBaseAddr,u32 DMA_BufferSize);
void DMA_Start(DMA_Channel_TypeDef*DMA_CHx,u32 DMA1_MEM_LEN);

#endif

//dma.c

#include "dma.h"

void DMA_Configuration(u32 DMA_PeripheralBaseAddr,u32 DMA_MemoryBaseAddr,u32 DMA_BufferSize)
{
	DMA_InitTypeDef DMA_InitStruct;
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 ,ENABLE);
	
	DMA_DeInit(DMA1_Channel4);
	DMA_InitStruct.DMA_PeripheralBaseAddr = DMA_PeripheralBaseAddr;
	DMA_InitStruct.DMA_MemoryBaseAddr = DMA_MemoryBaseAddr;
	DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST ;
	DMA_InitStruct.DMA_BufferSize = DMA_BufferSize;
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable ;
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte ;
	DMA_InitStruct.DMA_Mode = DMA_Mode_Normal ;
	DMA_InitStruct.DMA_Priority = DMA_Priority_Medium ;
	DMA_InitStruct.DMA_M2M = DMA_M2M_Disable ;
	DMA_Init(DMA1_Channel4,&DMA_InitStruct);
	
}

void DMA_Start(DMA_Channel_TypeDef*DMA_CHx,u32 DMA1_MEM_LEN)
{	
	DMA_Cmd(DMA_CHx,DISABLE);//关闭 USART1 TX DMA1所指示的通道
	DMA_SetCurrDataCounter(DMA1_Channel4,DMA1_MEM_LEN);//DMA通道的DMA缓存大小
	DMA_Cmd(DMA_CHx,ENABLE);//开启 USART1 TX DMA1所指示的通道
	
}

//main.c

#include "bitband.h"
#include "MyTime.h"
#include "key.h"
#include "gpio.h"
#include "dma.h"
#include "usart.h"

u32 DMA1_MEM_LEN = 0;

int main(void)
{
	const unsigned char buf[]={"dma with usart demo!!\r\n"};
	DMA1_MEM_LEN = sizeof(buf)/sizeof(buf[0]);
	MySysTick_Init();
	GPIO_Configuration();
	Key_Configuration();
	USART_Configuration();
	DMA_Configuration((u32)&USART1->DR,(u32)buf,DMA1_MEM_LEN);
		
	while(1)
	{
		LED1 = !LED1;
		MyDelay_ms(1000);
	}
}

这样,当按下KEY0时,LED0就会翻转之前的状态,串口也能接受到字符串。