PART6——DMA、按键、数码管、编码器、LM75A(硬件IIC)、继电器、步进电机、摇杆、ADC+DMA

DMA

步骤一:配置系统时钟
在配置DMA之前,首先需要配置系统时钟,确保所有外设都能正常工作。以下是一个简单的时钟配置示例,假设使用的是STM32F103芯片。
#include "stm32f10x.h"

void RCC_Config(void) {
   
    // 配置系统时钟为72MHz,使用外部晶振HSE为8MHz
    RCC_DeInit(); // 复位RCC寄存器
    RCC_HSEConfig(RCC_HSE_ON); // 启动外部晶振
    RCC_WaitForHSEStartUp(); // 等待外部晶振启动

    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // 配置PLL时钟为8MHz * 9 = 72MHz
    RCC_PLLCmd(ENABLE); // 启动PLL
    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // 等待PLL稳定

    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // 将PLL时钟设置为系统时钟
    while (RCC_GetSYSCLKSource() != 0x08); // 等待PLL成为系统时钟

    RCC_HCLKConfig(RCC_SYSCLK_Div1); // AHB时钟 = 系统时钟
    RCC_PCLK2Config(RCC_HCLK_Div1); // APB2时钟 = 系统时钟
    RCC_PCLK1Config(RCC_HCLK_Div2); // APB1时钟 = 系统时钟 / 2

    // 使能时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
   
}

步骤二:配置DMA控制器6void DMA_Config(void) {
   
    DMA_InitTypeDef DMA_InitStructure;

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

    // DMA初始化
    DMA_DeInit(DMA1_Channel1);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); // 外设地址,比如这里使用USART1的数据寄存器地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer; // 内存地址,比如buffer数组的地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // 数据传输方向:外设到内存
    DMA_InitStructure.DMA_BufferSize = sizeof(buffer); // 数据大小,比如buffer数组的大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 禁止外设地址自增
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 允许内存地址自增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 内存数据大小为字节  半字 字 1 2 4 
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 内存数据大小为字节  半字 字 1 2 4 
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // DMA传输模式:单次模式:传输计数器计到0(字节)时结束,循环模式计数到0自动重装
    DMA_InitStructure.DMA_Priority = DMA_Priority_High; // DMA优先级:高
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 禁止内存到内存模式DMA_M2M_Disable:禁用内存到内存模式。这意味着DMA传输只能在外设和内存之间进行,而不能直接在两个内存区域之间传输数据。
//DMA_M2M_Enable:启用内存到内存模式。这时DMA可以直接在两个内存区域之间传输数据,而不需要通过外设。这种模式适用于需要在内存之间进行数据复制或传输的场景。
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);

    // 使能DMA通道
    DMA_Cmd(DMA1_Channel1, ENABLE);
//DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);
}

步骤三:初始化外设
void USART_Config(void) {
   
    USART_InitTypeDef USART_InitStructure;

    // 使能USART时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    // USART初始化
    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_Mode = USART_Mode_Tx;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_Init(USART1, &USART_InitStructure);

    // 使能USART
    USART_Cmd(USART1, ENABLE);
    //使能外设DMA
    USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
}

步骤四:启动DMA传输
void Start_DMA_Transfer(void) {
   
    // 清除标志位
    DMA_ClearFlag(DMA1_FLAG_TC1);

    // 启动DMA传输
    DMA_Cmd(DMA1_Channel1, ENABLE);
}

步骤五:处理DMA传输完成中断(如果需要)
如果配置了DMA传输完成中断,在中断处理函数中进行相应的处理。
void DMA1_Channel1_IRQHandler(void) {
   
    if (DMA_GetITStatus(DMA1_IT_TC1)) {
   
        // DMA传输完成中断处理
        // 清除中断标志
        DMA_ClearITPendingBit(DMA1_IT_TC1);
    }
}
//若不用中断
void DMAx Enable(DMA Channel TypeDef* DMAy channelx,u16 ndtr)
{
   
DMA Cmd(DMAy Channelx,DISABLE);
DMA SetCurrDataCounter(DMAy Channelx,ndtr);
DMA Cmd(DMAy Channelx,DISABLE):
while(DMA_GetFlagStatus(DMA1_FlAG_TC1)==RESET)DMA_ClearFlag(DMA1_FlAG_TC1);
}

在这里插入图片描述
是否完成传输
传输数据剩余量
设置传输数据剩余量

在这里插入图片描述

按键双击和长按

#define KEYA_SPEED1	100	  //长按的时间长度(单位10mS)
#define KEYA_SPEED2	10	  //双击的时间长度(单位20mS)


int main (void){
   //主程序
	u8 a=0,b,c=0;
	RCC_Configuration(); //系统时钟初始化 
	LED_Init();//LED初始化
	TOUCH_KEY_Init();//按键初始化
	while(1){
   

		if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_A)){
    //检测按键是否按下
			delay_ms(20); //延时去抖动
			if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_A)){
   //判断长短键
				while((!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_A))&&c<KEYA_SPEED1){
    //循环判断长按,到时跳转
					c++;delay_ms(10); //长按判断的计时
				}
				if(c>=KEYA_SPEED1){
    //长键处理
					//长按后执行的程序放到此处
					GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1));//LED控制
					while(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_A));
				}else{
    //单击处理
					for(b=0;b<KEYA_SPEED2;b++){
   //检测双击
						delay_ms(20);
						if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_A)){
   
							a=1;
							//双击后执行的程序放到此处
							GPIO_WriteBit(LEDPORT,LED2,(BitAction)(1));//LED控制

							while(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_A));
						}
					}
					if(a==0){
    //判断单击
						//单击后执行的程序放到此处
						GPIO_WriteBit(LEDPORT,LED1|LED2,(BitAction)(0));//LED控制
						
					}
				}
				a=0;c=0; //参数清0
			}
		} //按键判断在此结束

	}
}

触摸按键滑动程序

#define KEYA_SPEED1	100	  //长按的时间长度(单位10mS)
#define KEYA_SPEED2	10	  //双击的时间长度(单位20mS)



int main (void){
   //主程序
	u16 k=1000;	//用于滑动加减计数
	u8 a=0,b,c=0;
	u8 s=0; //刚刚结束滑动标志
	RCC_Configuration(); //系统时钟初始化 
	USART1_Init(115200); //串口初始化,参数中写波特率
	LED_Init();//LED初始化
	TOUCH_KEY_Init();//按键初始化
	while(1){
   
//A
		if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_A)){
    //检测按键是否按下
			delay_ms(20); //延时去抖动
			if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_A)){
   //判断长短键
				while((!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_A))&&c<KEYA_SPEED1){
    //循环判断长按,到时跳转
					c++;delay_ms(10); //长按判断的计时
				}
				if</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值