STM32跑马灯实验&蜂鸣器实验&按键输入实验&NVIC中断优先级管理 您所在的位置:网站首页 单片机按键实验流程图视频 STM32跑马灯实验&蜂鸣器实验&按键输入实验&NVIC中断优先级管理

STM32跑马灯实验&蜂鸣器实验&按键输入实验&NVIC中断优先级管理

2024-07-15 12:07| 来源: 网络整理| 查看: 265

目录

1.  跑马灯

1.1  跑马灯硬件连接

1.2  跑马灯实验讲解

1.2.1  实验步骤

1.2.2  代码及注释

2.  蜂鸣器

2.1  蜂鸣器硬件连接

2.2  蜂鸣器实验讲解

2.2.1  实验步骤

2.2.2  代码及注释

3.  按键输入

3.1  按键实验硬件连接

3.2  GPIO输入操作说明

3.3  按键实验讲解

3.3.1  实验步骤

3.3.2  按键扫描思路

​ 3.3.3  代码与注释

4.  NVIC中断优先级管理

4.1  NVIC中断优先级分组

4.1.1  中断管理方法

​4.1.2  抢占优先级和相应优先级

4.1.3  中断优先级分组函数 

4.2  NVIC中断优先级设置

4.3  NVIC总结

1.  跑马灯

参考资料:

战舰/精英STM32F1开发板

《STM32F1开发指南-库函数版本》-第六章 跑马灯实验

1.1  跑马灯硬件连接

如图可以看到PB5,PE5 

1.2  跑马灯实验讲解 1.2.1  实验步骤

1.使能IO口时钟。调用函数RCC_APB2PeriphColckCmd();不同的IO组,调用的时钟使能函数不一样。

2.初始化IO口模式。调用函数GPIO_Init();

3.操作IO口,输出高低电平。

GPIO_SetBits()   高电平

GPIO_ResetBits()   低电平

1.2.2  代码及注释

main.c

#include"stm32f10x.h" #include"led.h" #include"delay.h" //注意:调用了函数,就要引用其头文件 int main(void) { delay_init();//调用delay初始化函数 LED_Init();//调用led初始化函数 while(1) { GPIO_SetBits(GPIOB,GPIO_Pin_5);//对PB5输出高电平 GPIO_SetBits(GPIOE,GPIO_Pin_5);//对PE5输出高电平 delay_ms(500);//延时500毫秒 GPIO_ResetBits(GPIOB,GPIO_Pin_5);//对PB5输出低电平 GPIO_ResetBits(GPIOE,GPIO_Pin_5);//对PE5输出低电平 delay_ms(500); } }

led.h

#ifndef __LED_H #define __LED_H //避免重复定义 if not define void LED_Init(void);//声明led初始化函数 #endif

led.c

#include"led.h" #include"stm32f10x.h" void LED_Init(void)//编辑led初始化函数 { GPIO_InitTypeDef GPIO_InitStructure;//定义指针 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOB的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);//使能GPIOE的时钟 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;//5 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//速度50MHz GPIO_Init(GPIOB,&GPIO_InitStructure);//GPIOB GPIO_SetBits(GPIOB,GPIO_Pin_5);//对PB5输出高电平 //即完成了对PB5的初始化 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;//5 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//速度50MHz GPIO_Init(GPIOE,&GPIO_InitStructure);//GPIOE GPIO_SetBits(GPIOE,GPIO_Pin_5);//对PE5输出高电平 //即完成了对PE5的初始化 }

delay.h在SYSTEM文件夹中delay.c目录下

以上

2.  蜂鸣器

参考资料:

战舰/精英STM32F1开发板

《STM32F1开发指南-库函数版本》-第七章 蜂鸣器实验

2.1  蜂鸣器硬件连接

2.2  蜂鸣器实验讲解

头文件中,使用#ifndef、#define、#endif条件编译,避免头文件内容重复定义

2.2.1  实验步骤

1.使能IO口时钟。调用函数RCC_APB2PeriphColckCmd();不同的IO组,调用的时钟使能函数不一样。

2.初始化IO口模式。调用函数BEEP_Init();

3.操作IO口,输出高低电平。

2.2.2  代码及注释

main.c

#include "sys.h" #include "delay.h" #include "led.h" #include "beep.h" int main(void) { delay_init();//初始化延时函数 LED_Init();//初始化与LED连接的硬件接口 BEEP_Init();/初始化蜂鸣器端口 while(1) { LED0=0;//位操作,输出低电平 BEEP=0; delay_ms(300);//延时300毫秒 //或GPIO_ResetBits(GPIOB,GPIO_Pin_8); 同BEEP=0 LED0=1; BEEP=1; delay_ms(300);//延时300毫秒 } }

beep.h

#ifndef __BEEP_H #define __BEEP_H #include "sys.h" #define BEEP PBout(8) // BEEP,蜂鸣器接口 void BEEP_Init(void); //初始化BEEP函数 #endif

beep.c

#include "beep.h" void BEEP_Init(void) { GPIO_InitTypeDef GPIO_InitStructure;//定义结构体指针 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能GPIOB端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;//BEEP-->PB.8 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度为50MHz GPIO_Init(GPIOB, &GPIO_InitStructure);//根据参数初始化GPIOB.8 GPIO_ResetBits(GPIOB,GPIO_Pin_8);//输出0,关闭蜂鸣器输出 //以上为PB8初始化 }

位操作在sys.h

3.  按键输入

参考资料:

战舰/精英STM32F1开发板

《STM32F1开发指南-库函数版本》-第八章 按键输入实验

3.1  按键实验硬件连接

精英版(无KEY2)

注意:KEY0 和 KEY1 是低电平有效的,而 KEY_UP 是高电平有效的,并且外部都没有上下拉电阻,所以,需要在 STM32F1 内部设置上下拉。

3.2  GPIO输入操作说明 读取IO口输入电平调用库函数为:

uint8_tGPIO_ReadlnputDataBit(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);

读取IO口输入电平操作寄存器为:

GPIOx_IDR:端口输入寄存器

使用位带操作读取IO口输入电平:

PEin(4)     读取GPIOE.4口电平

PEin(n)     读取GPIOE.n口电平

3.3  按键实验讲解 3.3.1  实验步骤

1.使能按键对应IO口时钟。调用函数:RCC_APB2PeriphClockCmd();

2.初始化IO模式:上拉/下拉输入。调用函数:GPIO_Init();

3.扫描IO口电平(库函数/寄存器/位操作)。

3.3.2  按键扫描思路

支持连续按:不用调用上一次按键情况

不支持连续按:要调用上一次按键情况

C语言关键字:static

1.static申明的局部变量,存储在静态存储区。

2.它在函数调用结束之后,不会被释放,它的值会一直保留下来。

3.所以可以说static申明的局部变量具有记忆功能。

第一个:每次调用flag返回值均为1。

第二个:初始化flag只有第一次调用时执行,所以第二次调用flag返回值为2,第三次调用flag返回值为3,依次类推。

 3.3.3  代码与注释

main.c

#include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "beep.h" int main(void) { vu8 key=0; delay_init(); //延时函数初始化 LED_Init(); //初始化与LED连接的硬件接口 BEEP_Init(); //初始化蜂鸣器端口 KEY_Init(); //初始化与按键连接的硬件接口 LED0=0; //先点亮红灯 while(1) { key=KEY_Scan(0); //得到键值,括号里可以选择写1或0 if(key) { switch(key) { case WKUP_PRES: //控制蜂鸣器 BEEP=!BEEP; break; case KEY1_PRES: //控制LED1翻转 LED1=!LED1; break; case KEY0_PRES: //同时控制LED0,LED1翻转 LED0=!LED0; LED1=!LED1; break; } }else delay_ms(10); } }

key.h

#ifndef __KEY_H #define __KEY_H #include "sys.h" //位操作 //#define KEY0 PEin(4) //PE4 //#define KEY1 PEin(3) //PE3 //#define WK_UP PAin(0) //PA0 WK_UP //宏定义 #define KEY0 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)//读取按键0 #define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)//读取按键1 #define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键3(WK_UP) #define KEY0_PRES 1 //KEY0按下 #define KEY1_PRES 2 //KEY1按下 #define WKUP_PRES 3 //KEY_UP按下(即WK_UP/KEY_UP) void KEY_Init(void);//IO初始化KEY u8 KEY_Scan(u8); //按键扫描函数 #endif

key.c

#include "stm32f10x.h" #include "key.h" #include "sys.h" #include "delay.h" //按键初始化函数 void KEY_Init(void) //IO初始化 { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//使能PORTA,PORTE时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_3;//KEY0-KEY1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入 GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE4,3 //初始化 WK_UP-->GPIOA.0 下拉输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0设置成输入,默认下拉 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0 } //按键处理函数 //返回按键值 //mode:0,不支持连续按;1,支持连续按; //0,没有任何按键按下 //1,KEY0按下 //2,KEY1按下 //3,KEY3按下 WK_UP //注意此函数有响应优先级,KEY0>KEY1>KEY_UP!! u8 KEY_Scan(u8 mode) { static u8 key_up=1;//按键按松开标志 if(mode)key_up=1; //支持连按 if(key_up&&(KEY0==0||KEY1==0||WK_UP==1)) { delay_ms(10);//去抖动 key_up=0; if(KEY0==0)return KEY0_PRES; else if(KEY1==0)return KEY1_PRES; else if(WK_UP==1)return WKUP_PRES; }else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1; return 0;// 无按键按下 } 4.  NVIC中断优先级管理

参考资料:

战舰/精英STM32F1开发板

《STM32F1开发指南-库函数版本》-4.5小节 中断优先级分组管理

4.1  NVIC中断优先级分组 CM3 内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有 256 级的可编程中断设置。STM32 并没有使用 CM3 内核的全部东西,而是只用了它的一部分。STM32 有 84 个中断,包括 16 个内核中断和 68 个可屏蔽中断,具有 16 级可编程的中断优先级。STM32F103 系列 上面,又只有 60 个可屏蔽中断(在 107 系列才有 68 个)。

 详情:STM32参考资料/STM32中文参考手册_V10.pdf    9.1.2    表55   0~59共60个中断。

4.1.1  中断管理方法

首先,对STM32中断进行分组,组0~4。同时,对每个中断设置一个抢占优先级和一个响应优先级。

分组配置是在寄存器SCB->AIRCR中配置。

4.1.2  抢占优先级和相应优先级

值越小,优先级越高。

1.高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。

2.抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。

3.抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。

4.如果两个中断的抢占优先级和响应优先级都是一样的,则看哪个中断先发生就先执行。

言外之意,高抢占优先级可以打断低抢占优先级,只有在抢占优先级相同且两中断同时发生的时候,响应优先级才起作用,此时高响应优先级先执行。

特别说明:

一般情况下,系统代码执行过程中,只设置一次中断优先级分组,比如分组2,设置好分组之后一般不会再改变分组。随意改变分组会导致中断管理混乱,程序出现意想不到的执行结果。

4.1.3  中断优先级分组函数 

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup) { assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup)); SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup; }

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

4.2  NVIC中断优先级设置

1.中断参数初始化函数

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)

2.其中 NVIC_InitTypeDef 是一个结构体,其成员变量:

typedef struct { uint8_t NVIC_IRQChannel; //设置中断通道 uint8_t NVIC_IRQChannelPreemptionPriority;//设置抢占优先级 uint8_t NVIC_IRQChannelSubPriority; //设置子优先级 FunctionalState NVIC_IRQChannelCmd;//使能 }NVIC_InitTypeDef;

NVIC_InitTypeDef 结构体中间有三个成员变量,这三个成员变量的作用是:

NVIC_IRQChannel:定义初始化的是哪个中断,这个可以在 stm32f10x.h 中找到 每个中断对应的名字。例如 USART1_IRQn。

NVIC_IRQChannelPreemptionPriority:定义这个中断的抢占优先级别。

NVIC_IRQChannelSubPriority:定义这个中断的子优先级别。

NVIC_IRQChannelCmd:该中断是否使能。

3.若使能串口 1 的中断,同时设置抢占优先级为 1,子优先级位 2,初始化的方法是:

NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口 1 中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;// 抢占优先级为 1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;// 子优先级位 2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能 NVIC_Init(&NVIC_InitStructure); //根据上面指定的参数初始化 NVIC 寄存器 4.3  NVIC总结

中断优先级设置步骤:

1.系统运行后先设置中断优先级分组。调用函数:

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

整个系统执行过程中,只设置一次中断分组。

2.针对每个中断,设置对应的抢占优先级和响应优先级:

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)

3.如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有