一、硬件准备
(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