实验二 、中断实验
自律 学习 坚强 ,拒绝迷茫。
作者:行走的皮卡丘
时间:2021/3/23
喜欢就去追,这个红灯等不到,说不定下一个红灯等到了,嘻嘻!!!!!!!
文章目录
一、实验目的
1、 掌握STM32中断程序设计流程。
2、 熟悉STM32固件库的基本使用。
3、 掌握STM32定时器设计流程。
二、实验内容
任务一、LED
(1)按键未按下时,主程序状态如下:LED1、LED2、LED3交替闪烁,每个LED闪烁间隔时间0.2S(一亮一灭共0.2S),持续1S。
(2)K2按键按下,进入中断状态。按1次,亮1个LED,持续1S后退出中断;按2次,亮2个LED,持续2S后退出中断;按3次,亮3个LED,持续3S后退出中断;按4次等同于按1次;
(3)在(2)的基础上继续编程。若键盘K3按下,也进入中断状态:LED1、LED2、LED3反向流水灯功能(即依次顺序点亮,从下到上),LED间隔时间0.2S; 经过3 次循环后,结束中断。要求:键盘K3 中断级别 比 键盘K2 中断级别高。
首先主函数先进行各个模块的初始化,while死循环则使3个灯循环点亮。
KEY2对应的外部中断的服务函数
KEY3对应的外部中断的服务函数
main函数代码
//STM32的头文件
#include <stm32f10x.h>
//STM32函数
#include "delay.h"
/**************************************************
* Function main
* @author 行走的皮卡丘
* @date 2021/3/24
* @brief
* @param[in]
* @param[out] void
* @retval void
* @par History 无
* LED1 ---> PB.0
* LED2 ---> PC.4
* LED3 ---> PC.3
* KEY1 ---> PA0
* KEY2 ---> PC13
*************************************************/
//定义LED1 LED2 LED3 方便管理修改和命名查看
//对应的IO硬件
// LED1 LED2 LED3
// PB4 PC4 PC3
#define LED1 PBout(0)
#define LED2 PCout(4)
#define LED3 PCout(3)
//定义读取按键的定义
//对应的IO硬件
// KEY2 KEY3
// PA0 PC13
#define KEY2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键
#define KEY3 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13)//读取按键
//应用于控制LED的变量
short i = 0;
//LED函数
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStr;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);//
GPIO_InitStr.GPIO_Mode=GPIO_Mode_Out_PP;//推挽
GPIO_InitStr.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStr.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStr); // PB0 LED1
GPIO_InitStr.GPIO_Pin=GPIO_Pin_4;
GPIO_Init(GPIOC,&GPIO_InitStr); // PC4 LED2
GPIO_InitStr.GPIO_Pin=GPIO_Pin_3;
GPIO_Init(GPIOC,&GPIO_InitStr); // PC3 LED3
GPIO_SetBits(GPIOB,GPIO_Pin_0);
GPIO_SetBits(GPIOC,GPIO_Pin_4);
GPIO_SetBits(GPIOC,GPIO_Pin_3);
}
//按键函数
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStr;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE); //开启时钟
GPIO_InitStr.GPIO_Mode=GPIO_Mode_IPD;//下拉输入
GPIO_InitStr.GPIO_Pin=GPIO_Pin_0;
GPIO_Init(GPIOA,&GPIO_InitStr); // PA0 KEY2
GPIO_InitStr.GPIO_Pin=GPIO_Pin_13;
GPIO_Init(GPIOC,&GPIO_InitStr); // PC13 KEY3
}
//中断函数
void EXTIX_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
KEY_Init(); // 按键端口初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟
//GPIOA—0 中断线以及中断初始化配置 上升沿触发 //KEY2
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_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
//GPIOC.13 中断线以及中断初始化配置 下降沿触发 //KEY3
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource13);
EXTI_InitStructure.EXTI_Line=EXTI_Line13;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键KEY2所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //使能按键KEY3所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
//外部中断0服务程序
void EXTI0_IRQHandler(void)
{
if( KEY2 == 1) //KEY2按键 硬件上以消抖
{
i++;
switch( i%4)
{
case 1: LED1 = 0; LED2 = 1; LED3 = 1; delay_ms(1000); break;
case 2: LED1 = 0; LED2 = 0; LED3 = 1; delay_ms(1000); delay_ms(1000); break;
case 3: LED1 = 0; LED2 = 0; LED3 = 0; delay_ms(1000); delay_ms(1000); delay_ms(1000);i=0;break;
}
}
EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位
}
//外部中断0服务程序
void EXTI15_10_IRQHandler(void)
{
short n;
if( KEY3 == 0) //KEY3按键 硬件上以消抖
{
for(n = 0; n<3; n++)
{
LED1 = 1; LED2 = 1; LED3 = 0; delay_ms(200);
LED1 = 1; LED2 = 0; LED3 = 1; delay_ms(200);
LED1 = 0; LED2 = 1; LED3 = 1; delay_ms(200);
}
}
EXTI_ClearITPendingBit(EXTI_Line13); //清除LINE0上的中断标志位
}
//主函数
int main()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
//分别
delay_init();
LED_Init();
KEY_Init();
EXTIX_Init();
while(1)
{
LED1 = 0; LED2 = 1; LED3 = 1; delay_ms(200);
LED1 = 1; LED2 = 1; LED3 = 1; delay_ms(200);
LED1 = 1; LED2 = 0; LED3 = 1; delay_ms(200);
LED1 = 1; LED2 = 1; LED3 = 1; delay_ms(200);
LED1 = 1; LED2 = 1; LED3 = 0; delay_ms(200);
}
}
任务二、 利用定时器编程实现以下内容:
LED1交替亮灭,间隔时间0.2S。
定时器中断服务函数
时钟初始化函数
main函数
//STM32的头文件
#include <stm32f10x.h>
//STM32函数
#include "delay.h"
/**************************************************
* Function main
* @author 行走的皮卡丘
* @date 2021/3/24
* @brief
* @param[in]
* @param[out] void
* @retval void
* @par History 无
* LED1 ---> PB.0
* LED2 ---> PC.4
* LED3 ---> PC.3
* KEY1 ---> PA0
* KEY2 ---> PC13
*************************************************/
//定义LED1 LED2 LED3 方便管理修改和命名查看
//对应的IO硬件
// LED1 LED2 LED3
// PB4 PC4 PC3
#define LED1 PBout(0)
#define LED2 PCout(4)
#define LED3 PCout(3)
//定义读取按键的定义
//对应的IO硬件
// KEY2 KEY3
// PA0 PC13
#define KEY2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键
#define KEY3 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13)//读取按键
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStr;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);//
GPIO_InitStr.GPIO_Mode=GPIO_Mode_Out_PP;//推挽
GPIO_InitStr.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStr.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStr); // PB0 LED1
GPIO_InitStr.GPIO_Pin=GPIO_Pin_4;
GPIO_Init(GPIOC,&GPIO_InitStr); // PC4 LED2
GPIO_InitStr.GPIO_Pin=GPIO_Pin_3;
GPIO_Init(GPIOC,&GPIO_InitStr); // PC3 LED3
GPIO_SetBits(GPIOB,GPIO_Pin_0);
GPIO_SetBits(GPIOC,GPIO_Pin_4);
GPIO_SetBits(GPIOC,GPIO_Pin_3);
}
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStr;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE); //开启时钟
GPIO_InitStr.GPIO_Mode=GPIO_Mode_IPD;//下拉输入
GPIO_InitStr.GPIO_Pin=GPIO_Pin_0;
GPIO_Init(GPIOA,&GPIO_InitStr); // PA0 KEY2
GPIO_InitStr.GPIO_Pin=GPIO_Pin_13;
GPIO_Init(GPIOC,&GPIO_InitStr); // PC13 KEY3
}
//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_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; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为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 = 3; //先占优先级3级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIMx
}
//定时器3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志
LED1=!LED1;
}
}
int main()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
delay_init();
LED_Init();
KEY_Init();
TIM3_Int_Init(1999,7199);//10Khz的计数频率,计数到2000为200ms
while(1)
{
}
}
三、实验总结
加油!!!行走的皮卡丘!!!!