STM32F103开关控制LED灯

本文介绍如何使用STM32F103C8T6芯片的中断功能,通过B1端口的开关控制A1端口LED灯的亮灭。涉及NVIC和EXTI中断配置,提供库函数和HAL函数两种实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


本文主要介绍了通过中断来实现开关控制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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值