首页 > 其他分享 >基于stm32f403zet6游戏摇杆手柄

基于stm32f403zet6游戏摇杆手柄

时间:2024-11-02 09:15:43浏览次数:3  
标签:DMA ENABLE 手柄 stm32f403zet6 摇杆 InitStructure ADC ADC1 GPIO

 一、硬件准备

        (1)stm32f403zet6

      (2)游戏摇杆扩展板

                

(3)oled模块

        

(4)hc-05蓝牙模块

(5)电动小马达

(6)其它模块

温湿度模块,led灯和其它按键都集成在stm32f403zet6上了。

如果有需要,也可以单独购买。

二、设计思路

        1.    Cortex-M内核的STM32F407zet6为主控,使用DMA内存搬运, 双通道ADC外设,实现                      ADC实时对两个摇杆的数据快速采集。
        2. 使用ADC采集数据通过USART串口,使用蓝牙模块实时进行数据通信。
        3. 使用HC-05蓝牙进行主从配置,可以支持板子与板子之间的无线通信。
        4. 模拟控制通过内部中断方式进行采集数据。
        5. 多个外部中断来实现按键的控制,并加了震动模块和蜂鸣器响应模拟攻击响应。
        6. 采用定时器实现看门狗功能,对蓝牙和摇杆的检测,实现休眠模式和未连接状态

三、主要代码实现

(1)主代码

#include "stm32f4xx.h"
#include "adc.h"
#include "delay.h"
#include "usart.h"
#include "oled.h"
#include "tim.h"
#include "led.h"
#include "exti.h"
#include "dht11.h"

//用于存储PA2 PA3的ADC值
extern __IO uint16_t aADCDualConvertedValue[4];
unsigned int adcVal,adcVal01,adcVal02,adcVal03,adcVal04;
char msgstr[64];

u8 g_data = 0;
u8 num=0;

//
int ret;
u8 data1,data2, data3, data4;

void USART3_IRQHandler(void)
{
//	uint32_t ulReturn;
//	//中断临界段代码保护
//	ulReturn = taskENTER_CRITICAL_FROM_ISR();
	
	//判断接受标志位是否置1
	if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
	{
		USART_ClearITPendingBit(USART3, USART_IT_RXNE);
		
		//接受数据
		g_data = USART_ReceiveData(USART3);
	
		g_flag = 1;  //表示接受到数据
		num=0;
//			OLED_ShowStr(0,4,"warning!!",2);				//测试8*16字符
		
//			OLED_ShowStr(0,2,"欢迎",2);				//测试8*16字符
		
		if(g_data == '1')
		{
			//	5、使失能定时器4。
			TIM_Cmd(TIM4, ENABLE);
			OLED_CLS();//清屏
			for(int i=5;i<9;i++)
			{
				OLED_ShowCN(-48+i*16,0,i);//测试显示中文"欢迎使用"
			}
			GPIO_ResetBits(GPIOF, GPIO_Pin_8);

			delay_s(2);
			g_flag = 1;  //表示接受到数据
			OLED_CLS();//清屏
		}
		
		if(g_data == '2')
		{
			//	5、使失能定时器4。
			TIM_Cmd(TIM4, DISABLE);
			g_flag=2;
			
			OLED_CLS();//清屏
			for(int i=19;i<23;i++)
			{
				OLED_ShowCN(-16+i*16,2,i);//测试显示中文"温度过高"
			}
			GPIO_SetBits(GPIOF, GPIO_Pin_8);
			delay_s(2);
			g_flag=2;
		}
		
		
		
		
			

	}

//	//退出中断临界区保护
//	taskEXIT_CRITICAL_FROM_ISR(ulReturn);
	
}


void lianjie(void)
{
	for(int i=0;i<3;i++)
	{
		OLED_ShowCN(20+i*16,3,i);//测试显示中文
	}

}
void lianjiedian(void)
{
	OLED_ShowStr(70,3,"*",2);				//测试8*16字符
	delay_ms(300);
	OLED_ShowStr(76,3,"*",2);				//测试8*16字符
	delay_ms(300);
	OLED_ShowStr(82,3,"*",2);				//测试8*16字符
	delay_ms(300);
	OLED_CLS();//清屏
}


void caozuo(void)
{
	if(((adcVal01/4095.0)*3.3) >=3.0)
		{
			
			printf("向右\r\n");
			for(int i=29;i<31;i++)
			{
				OLED_ShowCN(-96+i*16,2,i);//测试显示中文"向右"
			}
			delay_ms(100);
			OLED_CLS();//清屏
		}
		if(((adcVal01/4095.0)*3.3) <=0.5)
		{
			printf("向左\r\n");
			for(int i=27;i<29;i++)
			{
				OLED_ShowCN(-64+i*16,2,i);//测试显示中文"向左"
			}
			delay_ms(100);
			OLED_CLS();//清屏
		}
		if(((adcVal02/4095.0)*3.3) >=3.0)
		{
			
			printf("前进\r\n");
			
			for(int i=31;i<33;i++)
			{
				OLED_ShowCN(-128+i*16,2,i);//测试显示中文"前进"
			}
			delay_ms(100);
			OLED_CLS();//清屏
		}
		if(((adcVal02/4095.0)*3.3) <=0.5)
		{
			
			printf("后退\r\n");
			for(int i=33;i<35;i++)
			{
				OLED_ShowCN(-160+i*16,2,i);//测试显示中文"后退"
			}
			delay_ms(100);
			OLED_CLS();//清屏
		}
		
		if(((adcVal03/4095.0)*3.3) >=3.0)
		{
			printf("右转\r\n");
			for(int i=37;i<39;i++)
			{
				OLED_ShowCN(-224+i*16,2,i);//测试显示中文"右转"
			}
			delay_ms(100);
			OLED_CLS();//清屏
		}
		if(((adcVal03/4095.0)*3.3) <=0.5)
		{
			printf("左转\r\n");
			for(int i=35;i<37;i++)
			{
				OLED_ShowCN(-192+i*16,2,i);//测试显示中文"左转"
			}
			delay_ms(100);
			OLED_CLS();//清屏
		}
		
		
		if(((adcVal04/4095.0)*3.3) >=3.0)
		{
			printf("抬头\r\n");
			for(int i=39;i<41;i++)
			{
				OLED_ShowCN(-256+i*16,2,i);//测试显示中文"抬头"
			}
			delay_ms(100);
			OLED_CLS();//清屏
		}
		if(((adcVal04/4095.0)*3.3) <=0.5)
		{
			printf("低头\r\n");
			for(int i=41;i<43;i++)
			{
				OLED_ShowCN(-288+i*16,2,i);//测试显示中文"低头"
			}
			delay_ms(100);
			OLED_CLS();//清屏
		}

}


void wenduwarning(void)
{

	if(g_data == '2')
	{
		//	5、使失能定时器4。
		TIM_Cmd(TIM4, DISABLE);
		g_flag=2;
		
		OLED_CLS();//清屏
		for(int i=19;i<23;i++)
		{
			OLED_ShowCN(-16+i*16,2,i);//测试显示中文
		}
		delay_s(2);
		g_flag=2;
	}
}


int main(void)
{
	
//	g_flag = 0;
	//设置系统中断优先级分组2
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	

	Delay_Init();
//	Usart1_Init(115200);
	Usart3_Init(9600);
	ADC_PA2_PA3_Init();
	DMA_Config();	

	Led_Init();
	Exti_PA0_Init();	
	
	I2C_Configuration();
	OLED_Init();
	//1S产生一次中断,在中断获取ADC数据
	Tim3_Init();
	//开始 adc 转换,软件触发
	ADC_SoftwareStartConv(ADC1);
		Dht11_Init();

	
	
	
//	
		OLED_Fill(0xFF);//全屏点亮
		delay_s(2);
		OLED_Fill(0x00);//全屏灭
		delay_s(2);
		
		
	while(1)
	{
//		wenduwarning();//温度报警
		if(g_flag==0)
		{
			lianjie();//显示连接
			lianjiedian();//显示连接动画
		}
		
		
		if(g_flag==1)
		{
			caozuo();//操作模块
		}
		

		delay_ms(100);//延时200ms

	};
	
	return 0;
}


//	编写中断服务函数。
void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
	{
//		printf("While Run...\r\n");
	
		adcVal01= aADCDualConvertedValue[0];			
		adcVal02= aADCDualConvertedValue[1];	
		
		adcVal03= aADCDualConvertedValue[2];			
		adcVal04= aADCDualConvertedValue[3];
//		printf("X轴电压:%f, Y轴电压:%f\r\n", (adcVal01/4095.0)*3.3 , (adcVal02/4095.0)*3.3);
		
//		printf("X轴电压:%f, Y轴电压:%f\r\n", (adcVal03/4095.0)*3.3 , (adcVal04/4095.0)*3.3);
//		sprintf(msgstr,"PA2 ch2=%d PA3 ch3=%d\r\n",adcVal01,adcVal02);		
//		printf(msgstr);		  
//		
//		printf("\r\n");
		

	
	}
	//清除中断线3标志位
    TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}



//	编写中断服务函数。
void TIM4_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM4, TIM_IT_Update) == SET)
	{
		num++;
		if(num >= 3)
		{
//			g_flag=0;
			num=0;
		}
	}
	//清除中断线4标志位
    TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
}


//	编写中断服务函数。
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		ret = Dht11_Start();
		if(ret == 0)
		{
			data1 = Dht11_Read_Byte();
			data2 = Dht11_Read_Byte();
			
			data3 = Dht11_Read_Byte();
			data4 = Dht11_Read_Byte();
//			printf("湿度:%d.%d\r\n", data1, data2);
//			printf("温度:%d\r\n", data3);		
		}
		delay_s(1);
		
			if(data3>=30)
			{
				//	5、使失能定时器4。
				TIM_Cmd(TIM4, DISABLE);
				g_flag=2;
				
				OLED_CLS();//清屏
				for(int i=17;i<23;i++)
				{
					OLED_ShowCN(0+i*16,2,i);//测试显示中文
				}
				delay_s(2);
				g_flag=2;
			
			}
	
	}
	//清除中断线2标志位
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}

(2)adc双通道

#include "adc.h"

//用于存储PA2 PA3的ADC值
__IO uint16_t aADCDualConvertedValue[4];



/*************************************
硬件说明
PA2 -- ADC123_IN2
PA3 -- ADC123_IN3


选用ADC1

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

void ADC_PA2_PA3_Init(void)
{

	GPIO_InitTypeDef  		GPIO_InitStructure;
	ADC_CommonInitTypeDef 	ADC_CommonInitStructure;
	ADC_InitTypeDef       	ADC_InitStructure;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1时钟	
	
	
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_2|GPIO_Pin_3; 	//引脚2 3
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_AN;				//模拟模式
	GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_NOPULL ;		//浮空
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_0|GPIO_Pin_1; 	//引脚2 3
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_AN;				//模拟模式
	GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_NOPULL ;		//浮空
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	//复位ADC寄存器
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);	  	//reset adc
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);	//end reset adc


	ADC_CommonInitStructure.ADC_Mode 				= ADC_Mode_Independent;				//独立模式
	ADC_CommonInitStructure.ADC_TwoSamplingDelay 	= ADC_TwoSamplingDelay_20Cycles;
	ADC_CommonInitStructure.ADC_DMAAccessMode 		= ADC_DMAAccessMode_Disabled; 		//这是混合ADC才使用的模式,这里由于是独立模式,选择参数ADC_DMAAccessMode_Disabled
	ADC_CommonInitStructure.ADC_Prescaler 			= ADC_Prescaler_Div4;//预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz 
	ADC_CommonInit(&ADC_CommonInitStructure);//初始化

	ADC_InitStructure.ADC_Resolution 			= ADC_Resolution_12b;	//12位模式
	ADC_InitStructure.ADC_ScanConvMode 			= ENABLE;				//扫描模式	多通道采集需要
	ADC_InitStructure.ADC_ContinuousConvMode 	= ENABLE;				//连续转换
	ADC_InitStructure.ADC_ExternalTrigConvEdge 	= ADC_ExternalTrigConvEdge_None;//禁止触发检测,使用软件触发
//	ADC_InitStructure.ADC_ExternalTrigConv		= ADC_ExternalTrigConv_T3_CC1;	//禁止硬件触发,些值可以不用填写
	ADC_InitStructure.ADC_DataAlign 			= ADC_DataAlign_Right;//右对齐	
	ADC_InitStructure.ADC_NbrOfConversion 		= 4;//4个转换在规则序列中

	ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化

	// 配置 ADC 通道转换顺序和采样时间周期
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_15Cycles );	//ADC1,ADC通道,480个周期,提高采样时间可以提高精确度		
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_28Cycles );	//ADC1,ADC通道,480个周期,提高采样时间可以提高精确度			    
	ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 3, ADC_SampleTime_15Cycles );	//ADC1,ADC通道,480个周期,提高采样时间可以提高精确度		
	ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 4, ADC_SampleTime_28Cycles );	//ADC1,ADC通道,480个周期,提高采样时间可以提高精确度	

	// 使能 DMA 请求 after last transfer (Single-ADC mode)
	ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

	//使能 ADC DMA
	ADC_DMACmd(ADC1, ENABLE);

	//ADC_ExternalTrigConvCmd(ADC1, ENABLE); 
	ADC_Cmd(ADC1, ENABLE);//开启AD转换器	

}



void DMA_Config(void)
{
	DMA_InitTypeDef DMA_InitStructure;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

	DMA_InitStructure.DMA_Channel 				= DMA_Channel_0;				//选择 DMA 通道,通道存在于流中0中
	DMA_InitStructure.DMA_PeripheralBaseAddr 	= (uint32_t)&(ADC1->DR);		//数据源在ADC1->DR中
	DMA_InitStructure.DMA_Memory0BaseAddr 		= (uint32_t)aADCDualConvertedValue;//数据目的地在aADCDualConvertedValue数组
	DMA_InitStructure.DMA_DIR 					= DMA_DIR_PeripheralToMemory;//数据传输方向为外设到存储器
	DMA_InitStructure.DMA_BufferSize 			= 4;    						//与通道数设置一致
	DMA_InitStructure.DMA_PeripheralInc 		= DMA_PeripheralInc_Disable;	// 外设寄存器只有一个,地址不用递增
	DMA_InitStructure.DMA_MemoryInc 			= DMA_MemoryInc_Enable;			// 存储器地址固定
	DMA_InitStructure.DMA_PeripheralDataSize 	= DMA_PeripheralDataSize_HalfWord;	// 外设数据大小为半字,即两个字节
	DMA_InitStructure.DMA_MemoryDataSize	 	= DMA_PeripheralDataSize_HalfWord;	// 存储器数据大小也为半字,跟外设数据大小相同
	DMA_InitStructure.DMA_Mode 					= DMA_Mode_Circular;				// 循环传输模式
	DMA_InitStructure.DMA_Priority 				= DMA_Priority_High;				// DMA 传输通道优先级为高,当使用一个 DMA 通道时,优先级设置不影响
	DMA_InitStructure.DMA_FIFOMode 				= DMA_FIFOMode_Disable;            // 禁止 DMA FIFO ,使用直连模式
	// FIFO 大小, FIFO 模式禁止时,这个不用配置
	DMA_InitStructure.DMA_FIFOThreshold 		= DMA_FIFOThreshold_HalfFull;
	DMA_InitStructure.DMA_MemoryBurst 			= DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_PeripheralBurst 		= DMA_PeripheralBurst_Single;
	DMA_Init(DMA2_Stream0, &DMA_InitStructure);
	
	//使能 DMA 流
	DMA_Cmd(DMA2_Stream0, ENABLE);
	
}

(3)中断代码

#include "exti.h"
#include "usart.h"

u8 g_flag = 0;
u8 KeyNum = 1;
void delay1(int n)
{
	int i, j;
	
	for(i=0; i<n; i++)
		for(j=0; j<30000; j++);
}

/************************************
引脚说明:

KEY0 连接PA0,选择下降沿触发

PA0 -- EXTI0
*************************************/
void Exti_PA0_Init(void)
{
	EXTI_InitTypeDef   EXTI_InitStructure;
	GPIO_InitTypeDef   GPIO_InitStructure;
	NVIC_InitTypeDef   NVIC_InitStructure;
	
	
//	//使能GPIOA组时钟
//	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	//使能GPIOA组时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
//	//使能GPIOA组时钟
//	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	//使能SYSCFG组时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
	
//	//配置PA0为输入模式
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_4 |GPIO_Pin_0 |GPIO_Pin_9 |GPIO_Pin_10;   //引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;  //输入
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //浮空
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	
		//配置PA0为输入模式
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_2|GPIO_Pin_3;   //引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;  //输入
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //浮空
	GPIO_Init(GPIOE, &GPIO_InitStructure);
	
	
		//选择PA0挂在EXTI0
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2);
		/* Configure EXTI Line2 */
	EXTI_InitStructure.EXTI_Line = EXTI_Line2;				//中断线0
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 	//中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  //中断触发 -- 下降沿
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;  //中断线使能
	EXTI_Init(&EXTI_InitStructure);
	
		//选择PA0挂在EXTI0
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3);
	/* Configure EXTI Line3 */
	EXTI_InitStructure.EXTI_Line = EXTI_Line3;				//中断线0
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 	//中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  //中断触发 -- 下降沿
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;  //中断线使能
	EXTI_Init(&EXTI_InitStructure);
	
	
	//选择PA0挂在EXTI0
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOD, EXTI_PinSource4);
	
	/* Configure EXTI Line0 */
	EXTI_InitStructure.EXTI_Line = EXTI_Line4;				//中断线0
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 	//中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  //中断触发 -- 下降沿
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;  //中断线使能
	EXTI_Init(&EXTI_InitStructure);
	
	
		//选择PA0挂在EXTI0
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOD, EXTI_PinSource9);
	
	/* Configure EXTI Line0 */
	EXTI_InitStructure.EXTI_Line = EXTI_Line9;				//中断线0
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 	//中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  //中断触发 -- 下降沿
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;  //中断线使能
	EXTI_Init(&EXTI_InitStructure);
	
	
		//选择PA0挂在EXTI0
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOD, EXTI_PinSource10);
	
	/* Configure EXTI Line0 */
	EXTI_InitStructure.EXTI_Line = EXTI_Line10;				//中断线0
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 	//中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  //中断触发 -- 下降沿
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;  //中断线使能
	EXTI_Init(&EXTI_InitStructure);
	
		//选择PA0挂在EXTI0
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOD, EXTI_PinSource0);
		/* Configure EXTI Line2 */
	EXTI_InitStructure.EXTI_Line = EXTI_Line0;				//中断线0
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 	//中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  //中断触发 -- 下降沿
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;  //中断线使能
	EXTI_Init(&EXTI_InitStructure);

	
	//配置NVIC
	NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;    		//中断通道,只能在stm32f4xx.h 查阅
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  	//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; 			//响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//通道使能
	NVIC_Init(&NVIC_InitStructure);
	
	//配置NVIC
	NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;    		//中断通道,只能在stm32f4xx.h 查阅
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  	//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; 			//响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//通道使能
	NVIC_Init(&NVIC_InitStructure);
	
	
	//配置NVIC
	NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;    		//中断通道,只能在stm32f4xx.h 查阅
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  	//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 			//响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//通道使能
	NVIC_Init(&NVIC_InitStructure);
	
		//配置NVIC
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;    		//中断通道,只能在stm32f4xx.h 查阅
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  	//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; 			//响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//通道使能
	NVIC_Init(&NVIC_InitStructure);
	
	//配置NVIC
	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;    		//中断通道,只能在stm32f4xx.h 查阅
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  	//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; 			//响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//通道使能
	NVIC_Init(&NVIC_InitStructure);
	
	//配置NVIC
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;    		//中断通道,只能在stm32f4xx.h 查阅
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  	//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4; 			//响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//通道使能
	NVIC_Init(&NVIC_InitStructure);


}


//中断服务函数
/*********************************************

a.中断函数格式: void  中断服务函数名(void)
b.判断一个函数是否为中断服务函数名,需要查看是否在startup_stm32f40_41xxx.s中
查找的到,能查到,表示它是中断服务函数,否则不是。
c.中断服务函数是不需要调用的,当满足中断条件后,CPU自动去执行的函数。
d.中断是不能执行过长时间

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


void EXTI2_IRQHandler(void)
{
	
		//判断中断标志位是否置1
	if (EXTI_GetITStatus(EXTI_Line2) == SET)
    {
        if (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_2) == 0) 
        {
			delay1(20);    // 短延时去抖动
			if (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_2) == 0) 
			{
				//	5、使失能定时器4。
				TIM_Cmd(TIM4, DISABLE);
           
				OLED_CLS();//清屏
				printf("暂停\r\n");//暂停
				for(int i=23;i<25;i++)
				{
					OLED_ShowCN(0+i*16,2,i);//测试显示中文
				}
				g_flag = 5;
				KeyNum = 0;
				EXTI_ClearITPendingBit(EXTI_Line2);
			}
        }
    }
	
}

void EXTI3_IRQHandler(void)
{
	//判断中断标志位是否置1
	if (EXTI_GetITStatus(EXTI_Line3) == SET)
    {
        if (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3) == 0) 
        {
			delay1(20);    // 短延时去抖动
//			if (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3) == 0) 
//			{
				//	5、使失能定时器4。
				TIM_Cmd(TIM4, ENABLE);
	//           KeyNum = 1;
				OLED_CLS();//清屏
				printf("继续\r\n");//继续
				for(int i=25;i<27;i++)
				{
					OLED_ShowCN(-32+i*16,2,i);//测试显示中文
				}
				delay1(500);
				OLED_CLS();//清屏
				g_flag = 1;
				KeyNum = 1;
				EXTI_ClearITPendingBit(EXTI_Line3);
//			}
        }
    }
	
}





void EXTI4_IRQHandler(void)
{
	
//				GPIO_ToggleBits(GPIOF, GPIO_Pin_9);   	
	//判断中断标志位是否置1
	if (EXTI_GetITStatus(EXTI_Line4) == SET)
    {
     
		if(KeyNum == 1)
		{
			if (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_4) == 0) 
			{
				delay1(20);    // 短延时去抖动
	//			if (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_4) == 0) 
	//			{
			   
		//            delay(20);    // 短延时去抖动
		//            KeyNum = 1;
					GPIO_ToggleBits(GPIOF, GPIO_Pin_9);
					printf("轻击\r\n");
					GPIO_ToggleBits(GPIOF, GPIO_Pin_8);
					delay1(50);
					GPIO_ToggleBits(GPIOF, GPIO_Pin_8);
					GPIO_ToggleBits(GPIOF, GPIO_Pin_9);
				
					EXTI_ClearITPendingBit(EXTI_Line4);
	//				GPIO_ToggleBits(GPIOF, GPIO_Pin_9);   	
	//			}
			}
		}
    }
	
}


void EXTI9_5_IRQHandler(void)
{
	
		//判断中断标志位是否置1
	if (EXTI_GetITStatus(EXTI_Line9) == SET)
    {
//		GPIO_ToggleBits(GPIOF, GPIO_Pin_10);	
		if(KeyNum == 1)
		{
        if (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_9) == 0) 
        {
			delay1(20);    // 短延时去抖动
//			if (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_9) == 0) 
//			{
 				GPIO_ToggleBits(GPIOF, GPIO_Pin_10);
				printf("重击\r\n");
				GPIO_ToggleBits(GPIOF, GPIO_Pin_8);
				delay1(50);
				GPIO_ToggleBits(GPIOF, GPIO_Pin_8);
				GPIO_ToggleBits(GPIOF, GPIO_Pin_10);
	//            delay(20);    // 短延时去抖动
	//            KeyNum = 1;

				EXTI_ClearITPendingBit(EXTI_Line9);
//			}
        }
	}

    }
	
}




void EXTI15_10_IRQHandler(void)
{
	//判断中断标志位是否置1
	if (EXTI_GetITStatus(EXTI_Line10) == SET)
    {
		if(KeyNum == 1)
		{
        if (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_10) == 0) 
        {
			delay1(20);    // 短延时去抖动
			if (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_10) == 0) 
			{
	//            KeyNum = 1;
				GPIO_ToggleBits(GPIOE, GPIO_Pin_13);
				printf("轻踢\r\n");
				GPIO_ToggleBits(GPIOF, GPIO_Pin_8);
				delay1(50);
				GPIO_ToggleBits(GPIOF, GPIO_Pin_8);
				GPIO_ToggleBits(GPIOE, GPIO_Pin_13);
				//等待按键松开
	//			while(EXTI_GetITStatus(EXTI_Line3) == SET);
	//			
	//			delay1(40);    // 短延时去抖动
				
				EXTI_ClearITPendingBit(EXTI_Line10);
			}
        }
		}
    }
	
}

void EXTI0_IRQHandler(void)
{
	//判断中断标志位是否置1
	if (EXTI_GetITStatus(EXTI_Line0) == SET)
    {
		if(KeyNum == 1)
		{
        if (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_0) == 0) 
        {
			delay1(20);    // 短延时去抖动
//			if (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_11) == 0) 
//			{
	//            KeyNum = 1;
				GPIO_ToggleBits(GPIOE, GPIO_Pin_14);
				printf("蓄力一击\r\n");
				GPIO_ToggleBits(GPIOF, GPIO_Pin_8);
				delay1(50);
				GPIO_ToggleBits(GPIOF, GPIO_Pin_8);
				GPIO_ToggleBits(GPIOE, GPIO_Pin_14);
				
	//						//等待按键松开
	//			while(EXTI_GetITStatus(EXTI_Line4) == SET);
				EXTI_ClearITPendingBit(EXTI_Line0);
//			}
        }
		}
    }
	
}






标签:DMA,ENABLE,手柄,stm32f403zet6,摇杆,InitStructure,ADC,ADC1,GPIO
From: https://blog.csdn.net/weixin_66194218/article/details/142768104

相关文章

  • Pygame游戏手柄(Xbox)输入测试工具
    文章目录前言Xbox手柄测试程序说明使用说明完整代码前言在python做机器人控制时,需要加入xbox操控功能,为了直观显示手柄摇杆与变量之间的对应关系,实时调试手柄输入,开发了python手柄测试程序(本文基于xbox)。Xbox手柄测试程序说明测试程序使用pygame库创建了一......
  • 自制一个ps2摇杆无线WIFI控制的小车
    一、硬件1、2个esp8266-01s模块引脚图如下2、代码烧写器3、arduinoUNO开发板4、小车底盘5、ps2摇杆......
  • 莫托曼机器人GP110B操作手柄故障维修全攻略
     莫托曼机器人GP110B操作手柄故障机器人维修全攻略       一、前言       莫托曼机器人GP110B操作手柄是机器人控制系统的重要组成部分,它允许操作人员对机器人进行精确的控制和操作。然而,在使用过程中,操作手柄可能会出现各种故障。本文将为您提供一......
  • unity 摇杆
    /***********************************************EasyTouchControlsCopyright©2016TheHedgehogTeamhttp://www.thehedgehogteam.com/Forum/[email protected]************************************......
  • 【花雕学编程】Arduino动手做(232)---ESP32-S3 CAM使用joystick双轴摇杆模块控制LED灯
    37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)与否,都会记录下来——小小的......
  • Qt精品级项目——手撕信号槽机制的拳皇摇杆demo
    Qt精品级项目——手撕信号槽机制的拳皇摇杆demo1.前言&资源大家好,我是程序员Akgry。几天没见,阿克的Qt能力又是突飞猛进,阿克现在每天从睁眼学到闭眼,没了杂七杂八的东西掣肘,学起东西来非常舒适,虽然假期偷偷内卷很反人类,但是阿克今年就要参加秋招了,技术上的东西又岂敢怠慢。......
  • STEAM游戏无法使用手柄控制
    最近悟空特火,用Win10电脑Steam平台玩游戏想使用以前的手柄,发现无法操作。还以为是游戏或者手柄问题。在系统的硬件设备那里可以看到手柄已连接,也在网页上测试了手柄各个按键都没有问题。下面是测试网址,实在是太棒了,不用下载第三方测试工具。手柄测试(GamepadTester)-在线检测......
  • windows xusb21.sys驱动对虚拟手柄个数限制
    由于windows授权限制,云游戏服务器上的windows版本多数为server2019部分游戏用到了手柄,调研后基于https://github.com/nefarius/ViGEmBus来魔改虚拟出84个手柄(一个容器只跑一个游戏,一个游戏独立使用4个手柄,一台云游戏服务器预开21个容器,所以理论至少需要能创建84个手柄)但是实......
  • 记修复价值2千多的scuf-PS4游戏手柄
    这是也将是一台我修复的单支价值最高的PS4手柄朗读全文Yourbrowserdoesnotsupporttheaudioelement.大背景最近(其实从思维萌芽到实践已经相当一段时间,看似初露冰山一角,实其根基已扎实稳妥)发掘可以用做一些硬件手工,来让自己从软件的虚拟世界中短暂性跳脱,切换思维思......
  • 【解决方案】HTC Vivie 手柄在SteamVR中图标一直闪烁,提示不在定位范围内
    这种情况一般有两种原因:原因一:        手柄的固件和SteamVR版本不匹配。解决方案:        使用线将手柄连接到电脑上,然后在SteamVR手柄图标上右键,更新固件即可。        但是也有情况是,做了并没有用,所以就有第二种可能:原因二:        手......