STM32TimerEXIT综合实验
实验资源
硬件:
正点原子ALIENTEK 战舰 STM32F103 开发板
软件:
keil5 V5.37.0.0
实验要求:
1)初始状态或按下 KEY0 按键,循环时间为 1S。
2)初始状态或按下 WK_UP 按键,循环时间为 2S。
大致流程:
两个外部中断触发中断后,在对应的中断服务函数中修改标志位led_mode_flag(初始值为0)的值,当其值改变后在主函数执行对应的代码块。使能或失能timer3或timer4,在timer3或timer4的中断服务函数中对led进行操作
主要代码
main.c
int main(void)
{
LED_Init();
BUZZER_Init();
TIM3_Init(7200,10000);//1S
TIM4_Init(7200,5000);//0.5S
EXTIX_Init();
while(1)
{
switch (led_mode_flag)
{
case 0://初始状态
{
TIM_Cmd(TIM3, DISABLE);
TIM_Cmd(TIM4, ENABLE);
break;
}
case 1://PA0按下
{
TIM_Cmd(TIM3, DISABLE);
TIM_Cmd(TIM4, ENABLE);
break;
}
case 2://PE4按下
{
TIM_Cmd(TIM3, ENABLE);
TIM_Cmd(TIM4, DISABLE);
break;
}
default://若故障则两灯全亮
{
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
break;
}
}
}
}
exit.c
#include "exti.h"
#include "key.h"
#include "delay.h"
#include "buzzer.h"
uint8_t led_mode_flag = 0;
/**
* @brief 外部中断初始化
* @param 无
* @retval 无
*/
void EXTIX_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
KEY_Init(); // 按键端口初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟
//GPIOE4 中断线以及中断初始化配置 KEY0
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);
EXTI_InitStructure.EXTI_Line=EXTI_Line4;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
//GPIOA0 中断线以及中断初始化配置 PA0 WK_UP
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
//EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发
//EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键WK_UP所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //使能按键KEY0所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; //子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
/**
* @brief 外部中断0服务程序
* @param 无
* @retval 无
*/
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) == SET)
{
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 1)//判断0引脚的中断,过滤其他信号
{
//消抖
delay_ms(10);
while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 1);
delay_ms(10);
//执行程序
BUZZER_ON();
led_mode_flag=1;
}
EXTI_ClearITPendingBit(EXTI_Line0);//清除标志位,防止一直进入中断函数
}
}
/**
* @brief 外部中断4服务程序
* @param 无
* @retval 无
*/
void EXTI4_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line4) == SET)
{
if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) == 0)//判断0引脚的中断,过滤其他信号
{
//消抖
delay_ms(10);
while (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) == 0);//松开按键才会触发
delay_ms(10);
//执行程序
BUZZER_ON();
led_mode_flag=2;
}
EXTI_ClearITPendingBit(EXTI_Line4);//清除标志位,防止一直进入中断函数
}
}
timer.c
#include "timer.h"
#include "led.h"
/**
* @brief timer3初始化
* @param arr:自动重装载值 psc:预分频值
* @retval 无
*/
void TIM3_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc-1; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级1级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM3, DISABLE); //失能TIM3
}
/**
* @brief timer4初始化
* @param arr:自动重装载值 psc:预分频值
* @retval 无
*/
void TIM4_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能
//定时器TIM4初始化
TIM_TimeBaseStructure.TIM_Period = arr-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc-1; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级1级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM4, DISABLE); //失能TIM4
}
/**
* @brief timer3中断服务函数
* @param 无
* @retval 无
*/
void TIM3_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
//取反
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==RESET)
{
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
}
else
{
GPIO_SetBits(GPIOE,GPIO_Pin_5);
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除TIM3更新中断标志
}
}
/**
* @brief timer3中断服务函数
* @param 无
* @retval 无
*/
void TIM4_IRQHandler(void) //TIM4中断
{
if (TIM_GetITStatus(TIM4,TIM_IT_Update) != RESET) //检查TIM4更新中断发生与否
{
//取反
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==RESET)
{
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
}
else
{
GPIO_SetBits(GPIOE,GPIO_Pin_5);
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
}
TIM_ClearITPendingBit(TIM4,TIM_IT_Update); //清除TIM4更新中断标志
}
}