STM32F103开关控制LED灯


本文主要介绍了通过中断来实现开关控制LED灯的亮和灭。
软件:Keil μVision
芯片:STM32F103C8T6


一、实验简介

本次实验通过B1端口的开关控制A1端口的LED灯,即B1端口接高电平时LED亮,B1端口接低电平时LED灭。实验电路图比较简单,这里就不做展示。

二、实验原理

本次实验主要使用了中断、GPIO输入和输出模式来进行实验。

CM3内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级可编程中断设置。STM32并没有CM3的全部中断服务。STM32有84个中断,包括16个内核中断和68个可屏蔽中断,具有16级可编程的中断优先级(STM32F103系列有60个可屏蔽中断)。在STM32中文参考手册第9章,第130页,比较详细的介绍了STM32的中断事件。

在这里插入图片描述

对于这么多中断,如何管理?通过寄存器对STM32中断进行分组,再对每个中断设置一个抢占优先级和一个响应优先级。在STM32固件库使用手册第165页中有分组情况。具体可以在B站观看相关视频。

在这里插入图片描述

1. NVIC简介

所以我们需要设置中断分组,比如我们设置中断分组为2

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

还需要初始化NVIC,配置相关参数

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x00;
NVIC_Init(&NVIC_InitStructure);

这里设置中断为EXTI1中断(下一小节介绍),然后使能,设置抢占优先级和响应优先级。其中IRQChannel的值可以在stm32f10x.h中找到,也可以在STM32固件库使用手册第166也查到。下面是部分表

在这里插入图片描述

2.EXTI简介

通用I/O端口以下图的方式连接到16个外部中断/事件线上:(STM32中文参考手册第137页)
在这里插入图片描述
和之前类似,首先初始化EXTI。

EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
EXTI_InitStructure.EXTI_Line=EXTI_Line1;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising_Falling;
EXTI_Init(&EXTI_InitStructure);

EXTI_Line的值和GPIOX端口类似,参考上面图片,EXTI_Line的值如下

在这里插入图片描述在这里插入图片描述在这里插入图片描述

EXTI_LineCmd的值设置为ENABLE,使能,模式(EXTI_Mode)设置为中断(Interrupt),触发方式(EXTI_Trigger)选择为上下沿触发,最后调用初始化函数EXTI_Init(&EXTI_InitStructure)

然后是写中断函数,在启动文件中,已经写了中断函数的引用
在这里插入图片描述

中断函数如下:

void EXTI1_IRQHandler(void)
{
	delay_ms(10);//消除抖动
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==1)
	{
		GPIO_ResetBits(GPIOA,GPIO_Pin_1);
	}
	else
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_1);
	}
	EXTI_ClearITPendingBit(EXTI_Line1);
}

最后一定要清除中断位,用EXTI_ClearPendingBit(EXTI_LineX)函数

当B1端口是高电平时,A1端口是低电平,LED灯亮;当A1端口是低电平时,A1端口是高电平,LED灯灭。

有关LED灯和按键的代码这里不做讲解,可以在我之前博客STM32F103点亮LED流水灯_江南烟浓雨的博客-CSDN博客中查看原理

三、实验代码

1.库函数方式

创建工程后,新建四个文件夹,分别为DELAY、EXTI、KEY、LED,分别对应四个C文件和四个头文件,代码如下

delay.h

#ifndef __DELAY_H
#define	__DELAY_H
#include "stm32f10x.h"
void DELAY_Init(void);
void delay_ms(u16 nms);
#endif

delay.c

#include "delay.h"
static u16 fac_ms = 0;
void DELAY_Init()
{
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
	fac_ms = (u16)(SystemCoreClock/8000);
}

void delay_ms(u16 nms)
{	 		  	  
	u32 temp;		   
	SysTick->LOAD=(u32)nms*fac_ms;				//时间加载(SysTick->LOAD为24bit)
	SysTick->VAL =0x00;							//清空计数器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//开始倒数  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));		//等待时间到达   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//关闭计数器
	SysTick->VAL =0X00;       					//清空计数器	  	    
}

exti.h

#ifndef __EXTI_H
#define	__EXTI_H
#include "stm32f10x.h"
#include "delay.h"
#include "key.h"
void EXTIX_Init(void);
#endif

exti.c

#include "exti.h"
void EXTIX_Init(void)
{
	EXTI_InitTypeDef EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	
	KEY_Init();
	
	//GPIOB.1中断线初始化配置
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
	
	EXTI_InitStructure.EXTI_Line=EXTI_Line1;
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising_Falling;
	EXTI_Init(&EXTI_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x00;
	NVIC_Init(&NVIC_InitStructure);
}

void EXTI1_IRQHandler(void)
{
	delay_ms(10);//消除抖动
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==1)
	{
		GPIO_ResetBits(GPIOA,GPIO_Pin_1);
	}
	else
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_1);
	}
	EXTI_ClearITPendingBit(EXTI_Line1);
}

key.h

#ifndef __KEY_H
#define	__KEY_H
#include "stm32f10x.h"
void KEY_Init(void);
u8 KEY_Scan(void);
#endif

key.c

#include "key.h"
void KEY_Init(void)
{
	/* 定义一个GPIO_InitTypeDef类型的结构体 */
	GPIO_InitTypeDef GPIO_InitStructure;
	/* 设置时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	/* 将B1端口GPIO_Mode和GPIO_Speed设置为下拉输入模式 */
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
}

led.h

#ifndef __LED_H
#define	__LED_H
#include "stm32f10x.h"
#include "key.h"
void LED_Init(void);
#endif

led.c

#include "led.h"   
void LED_Init(void)
{
	/* 定义一个GPIO_InitTypeDef类型的结构体 */
	GPIO_InitTypeDef GPIO_InitStructure;
	/* 设置时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	/* 将A1端口GPIO_Mode和GPIO_Speed设置为PP模式和50MHz */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==1)
	{
		GPIO_ResetBits(GPIOA,GPIO_Pin_1);
	}
	else
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_1);
	}
}

main.c

#include "stm32f10x.h"
#include "delay.h"
#include "exti.h"
#include "key.h"
#include "led.h"
int main(void)
{	
	DELAY_Init();
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	EXTIX_Init();
	LED_Init();
	while(1)
	{
		
	}
}

2.HAL函数方式

我们使用STM32CubeMX来生成代码,和上次的实验类似,需要GPIO口的设置类似。需要注意的是,需要设置PB1口位EXTI1。
在这里插入图片描述
GPIO口设置位上下沿触发中断

注意:NVIC中System tick timer需要设置优先级高于EXTI

EXTI中断可以比较随便的设置,这里设置为2和0

在这里插入图片描述

其他方面可以参考STM32CubeMX的安装与简单应用_江南烟脓雨的博客-CSDN博客

代码修改如下:

if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==1)
{
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET);
}
else
{
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET);
}

这里我们希望刚通电时(初始状态)灯的亮灭和开关状态保持一致

在这里插入图片描述

接下来修改stm32f1xx_hal_gpio.c中的中断函数

HAL_Delay(10);
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==1)
{
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET);
}
else
{
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET);
}

添加中断函数内容,如下图所示
在这里插入图片描述

四、实验结果

在这里插入图片描述

五、总结

本次实验初步实现了中断函数,因为实验比较简单,所以没有设计复杂的函数。对于中断函数的学习可以参考stm32中文手册和库函数手册,或通过网络资源学习。

六、参考文献

【正点原子】STM32开发板实验教程(F103)_哔哩哔哩_bilibili

  • 7
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
STM32F103是一款32位的Cortex-M3内核微控制器,具有多种功能和丰富的外设。 通过使用两个开关控制LED,我们可以采用以下步骤: 1. 首先,我们需连开关LED到正确的GPIO引脚上。假设我们将开关1连到GPIOA的引脚2上,开关2连到GPIOA的引脚3上,到GPIOC的引脚13上。 2. 在代码中,我们需要初始化引脚。可以使用STM32CubeIDE或者其他的开发工具生成初始化代码。这些代码将帮助我们配置引脚为输入或输出,并设置默认状态。 3. 下来,我们需要编写代码来实现开关控制的逻辑。首先,我们需要对开关状态进行监测。可以通过读取开关引脚的状态来实现。例如,我们可以使用GPIO_ReadPin函数来读取GPIOA的引脚2和引脚3的状态。当开关被按下时,引脚状态将变为高电平,否则为低电平。 4. 在读取开关状态后,我们可以根据开关的状态来控制LED。可以使用GPIO_WritePin函数来设置GPIOC的引脚13的状态。例如,当开关1被按下时,我们可以将引脚13设置为高电平,从而点亮LED。当开关2被按下时,我们可以将引脚13设置为低电平,从而关闭LED。 5. 最后,我们需要在主循环中持续检测开关状态和控制LED的状态。可以使用延时函数来定期检测开关状态,以避免频繁的检测。 总结来说,通过初始化引脚、读取开关状态并根据状态控制LED,我们可以实现使用两个开关控制LED的功能。这种方法简单且直观,适用于许多嵌入式应用中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值