STM32L476RG_中断开发与实列
本程序的主要功能是实现按键控制灯的亮灭。当灯为灭的状态时按键按下点亮灯,当灯为亮的状态时按键按下熄灭灯,即实现灯的电平翻转操作。
按键扫描是利用 GPIO 下降中断,来监测按键按下动作。并加以消抖操作,便可以获得可靠的按键操作。根据原理图,配置主控芯片与按钮相连引脚外部中断,并设置优先级信息。为了代码可读性和编写方便,我们利用结构体来管理按键信息。同时采用函数指针,进行按键结果回调。
在 GPIO 中断回调函数中,会根据 GPIO 引脚记录按键按下的标志和起始系统 Tick 时间。紧靠这些信息还是无法实现按键操作。还需要程序对按键事件进行消抖操作并回调最终结果。
硬件原理图如下所示:

GPIO.c文件的配置初始化操作。
/* USER CODE BEGIN 0 */
//=================================================================================
//2018.5.16 中断开发与实例
//=================================================================================
#define KEY_DELAY_TICK 20//主要用于按键延迟消抖的操作
//定义一个按键的事件结构体
typedef struct
{
uint8_t key_event;//按键按下事件
int start_tick;//用于消抖的起始时间 Ticks
}key_press_t; static key_press_t key_check_press = {,}; static key_cb pFkey_cb;
//=================================================================================
//=================================================================================
/* USER CODE END 0 */ /*----------------------------------------------------------------------------*/
/* Configure GPIO */
/*----------------------------------------------------------------------------*/
/* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{ GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LED_LD2_GPIO_Port, LED_LD2_Pin, GPIO_PIN_RESET); /*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = KEY_INPUT_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(KEY_INPUT_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = LED_LD2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED_LD2_GPIO_Port, &GPIO_InitStruct); } /* USER CODE BEGIN 2 */
//**************************************
//=================================================================================
//=================================================================================
// fn : GPIO_Led_Toggle
//
// brief : 翻转LED控制引脚电平
//
// param : none
//
// return : none
void GPIO_Led_Toggle(void)
{
HAL_GPIO_TogglePin(LED_LD2_GPIO_Port,LED_LD2_Pin);//用来控制 LED 引脚电平
}
//**************************************
//**************************************
// fn : KEY_RegisterCb
//
// brief : 注册按钮事件回调
//
// param : cb -> 处理按钮事件函数指针
//
// return : none
void KEY_RegisterCb(key_cb cb)
{
if(cb != )
{
pFkey_cb = cb;
}
} //**************************************
//在 GPIO 中断回调函数中,会根据 GPIO 引脚记录按键按下的标志和起始系统 Tick 时间。
//紧靠这些信息还是无法实现按键操作。还需要程序对按键事件进行消抖操作并回调最终结果。
// fn : KEY_Poll
//
// brief : 轮询按钮事件
//
// param : none
//
// return : none
//在 KEY_Poll 函数中,如果发现 key_event 不为 0,即发现引脚有中断产生。则会进行延
//时操作,并最终读取引脚电平,确认按键是否真的按下。 如果真的有按键按下操作,且根据
//回调函数指针进行结果上报。
void KEY_Poll(void)
{
uint8_t key_event = ;
if(key_check_press.key_event)//key_check_press.key_event = 0x01
{
if(HAL_GetTick() - key_check_press.start_tick >= KEY_DELAY_TICK )//delay 20ms
{
if(key_check_press.key_event & KEY_INPUT)//0x01 & 0x01 = true
{
if(HAL_GPIO_ReadPin(KEY_INPUT_GPIO_Port,KEY_INPUT_Pin) == GPIO_PIN_RESET)//读取引脚电平判断是否按下
{
key_event |= KEY_INPUT;//全部为false为false 结果为1 true
}
key_check_press.key_event ^= KEY_INPUT;//异或 0^0x01 = 1 1^0x01 = 0 赋值为0(相等为0,不等为1)等待下一次的按下触发操作
}
}
}
//=======================================================================
//如果真的有按钮按下,则执行回调函数
if(key_event && pFkey_cb)//key_event不等于0 true 1 && pFkey_cb(pFkey_cb 肯定不等于0)所以结果为true
{
pFkey_cb(key_event);//true 传入的为1
}
//=======================================================================
}
//************************************************************************
// fn : HAL_GPIO_EXTI_Callback
//
// brief : 按键中断回调函数
//
// param : GPIO_Pin-> 引脚编号
//
// return : none
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
//引脚有中断发生,要进行消抖,以确定是否为有效操作
if(GPIO_Pin == KEY_INPUT_Pin)
{
key_check_press.key_event = KEY_INPUT;//把按键当前的状态传给按键触发事件变量 0x01
key_check_press.start_tick = HAL_GetTick();
}
}
//=================================================================================
//=================================================================================
/* USER CODE END 2 */
GPIO.H文件的基本操作:
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __gpio_H
#define __gpio_H
#ifdef __cplusplus
extern "C" {
#endif /* Includes ------------------------------------------------------------------*/
#include "stm32l4xx_hal.h"
#include "main.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* USER CODE BEGIN Private defines */
//定义按键标识
#define KEY_INPUT 0x01
//定义按键回调函数指针
typedef void (*key_cb)(uint8_t pin);
/* USER CODE END Private defines */ void MX_GPIO_Init(void); /* USER CODE BEGIN Prototypes */
//**************************************
// fn : KEY_RegisterCb
//
// brief : 注册按钮事件回调
//
// param : cb -> 处理按钮事件函数指针
//
// return : none
void KEY_RegisterCb(key_cb cb); //**************************************
// fn : KEY_Poll
//
// brief : 轮询按钮事件
//
// param : none
//
// return : none
void KEY_Poll(void);
/* USER CODE END Prototypes */ #ifdef __cplusplus
}
#endif
#endif /*__ pinoutConfig_H */
main.c基本语法:
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32l4xx_hal.h"
#include "gpio.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_NVIC_Init(void); /* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
//======================================================================================
//======================================================================================
//******************************************************************************
// fn : AppKey_cb
//
// brief : 处理按键事件
//
// param : key -> 按钮按下标识
//
// return : none
void AppKey_cb(uint8_t key);
//======================================================================================
//======================================================================================
/* USER CODE END PFP */ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /**
* @brief The application entry point.
*
* @retval None
*/
int main(void)
{
/* USER CODE BEGIN 1 */
//注册按钮回调函数
//KEY_RegisterCb(AppKey_cb);
/* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */
SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */
MX_GPIO_Init(); /* Initialize interrupts */
MX_NVIC_Init();
/* USER CODE BEGIN 2 */
//===========================================================================
//===========================================================================
//注册按钮回调函数
KEY_RegisterCb(AppKey_cb);//注册按钮回调函数
//===========================================================================
//===========================================================================
/* USER CODE END 2 */ /* Infinite loop */
/* USER CODE BEGIN WHILE */
while ()
{ /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */
//程序需要写在BEGIN 和 END之间否则下一次导入会覆盖之前的操作
{//这个只能实现点亮灯的操作
//HAL_GPIO_WritePin(LED_LD2_GPIO_Port, LED_LD2_Pin, GPIO_PIN_SET);//OPEN THE LED
//HAL_Delay(1000);//自带延迟函数//延时1000ms
//HAL_GPIO_WritePin(LED_LD2_GPIO_Port, LED_LD2_Pin, GPIO_PIN_RESET);//CLOSED THE LED
}
{//实现某个引脚电平的反转
//GPIO_Led_Toggle();
//HAL_Delay(500);//延时500ms
}
KEY_Poll();
}
/* USER CODE END 3 */ } /**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{ RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct; /**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = ;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
} /**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
} /**Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
} /**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/); /**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, , );
} /**
* @brief NVIC Configuration.
* @retval None
*/
static void MX_NVIC_Init(void)
{
/* EXTI15_10_IRQn interrupt configuration */
HAL_NVIC_SetPriority(EXTI15_10_IRQn, , );
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
} /* USER CODE BEGIN 4 */
//******************************************************************************
// fn : AppKey_cb
//
// brief : 处理按键事件 灯亮的时候灭 灭的时候灯亮
//
// param : key -> 按钮按下标识
//
// return : none
void AppKey_cb(uint8_t key)
{
if(key & KEY_INPUT)
{
{//实现某个引脚电平的反转
GPIO_Led_Toggle();
HAL_Delay();//延时500ms
}
}
}
/* USER CODE END 4 */ /**
* @brief This function is executed in case of error occurrence.
* @param file: The file name as string.
* @param line: The line in file as a number.
* @retval None
*/
void _Error_Handler(char *file, int line)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
while()
{
}
/* USER CODE END Error_Handler_Debug */
} #ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
main.h:
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H__
#define __MAIN_H__ /* Includes ------------------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private define ------------------------------------------------------------*/ #define KEY_INPUT_Pin GPIO_PIN_13
#define KEY_INPUT_GPIO_Port GPIOC
#define KEY_INPUT_EXTI_IRQn EXTI15_10_IRQn
#define LED_LD2_Pin GPIO_PIN_5
#define LED_LD2_GPIO_Port GPIOA /* ########################## Assert Selection ############################## */
/**
* @brief Uncomment the line below to expanse the "assert_param" macro in the
* HAL drivers code
*/
/* #define USE_FULL_ASSERT 1U */ /* USER CODE BEGIN Private defines */ /* USER CODE END Private defines */ #ifdef __cplusplus
extern "C" {
#endif
void _Error_Handler(char *, int); #define Error_Handler() _Error_Handler(__FILE__, __LINE__)
#ifdef __cplusplus
}
#endif #endif /* __MAIN_H__ */
STM32L476RG_中断开发与实列的更多相关文章
- GO后端开发+VUE实列
因为我是从java转到go,代码结构跟我之前用java的很像 在这里只浅显的实战运用,没有过多理论讲解 工作环境:IDE:Goland , Go 1.17.7 框架 Gin+Gorm ,前端VUE 这 ...
- AD域控Dsquery查询命令实列
注:请以管理员的身份运行cmd程序,要不然某些命令不生效 AD域控Dsquery查询命令实列 查询技术支持二部的所有用户 dsquery user OU=技术支持二部,OU=技术部, ...
- IoT开发精英实战营招募啦!速来报名!
具有了向上的力量,才能一眼望到山外的大地,蜿蜒的长河,人类精神的进步. --罗曼·罗兰<爱与死的搏斗> 七月流火,八月未央,九月授衣.说是长长长长的夏天,眨眼间,也早过了立秋而迎来处暑.距 ...
- Flask常用实列化参数
Flask中实列化配置: app = Flask( __name__, template_folder=’temp’ , ...... ) >template_folder = "te ...
- XML建模实列
XML建模 建模的由来: 就是将指定的xml字符串当作对象来操作 好处在于,只需要调用指定的方法就可以完成预定的字符串获取: 建模的一个思路: 1.分析需要被建模的文件中有那几个对 ...
- docker中启动2个mysql实列
一.mac环境安装docker容器 在docker官网中下载docker容器,地址:https://www.docker.com/products/docker-desktop 具体安装教程及设置网络 ...
- 实列+JVM讲解类的实列化顺序
刨根问底---类的实列化顺序 开篇三问 1什么是类的加载,类的加载和类的实列有什么关系,什么时候类加载 2类加载会调用构造函数吗,什么时候调用构造函数 3什么是实列化对象,实列化的对象有什么东西. 我 ...
- 美化传奇NPC对话框添加图片显示实列
NPC对话框一般都是文字显示,有些GM想突出版本特色,在NPC对话框加些专业图片,彰显独特之处,其实这是很简单的.下面为你讲解美化传奇NPC对话框添加图片显示实列 我们要添加你要放入npc图片的补丁. ...
- mima开发实列
最顶层父基类Clinet:用于记录公共内容 切供多个Clinet继承公用 import java.net.InetSocketAddress; import java.nio.charset.Char ...
随机推荐
- Knockoutjs 响应式计算研究
reactive programming https://en.wikipedia.org/wiki/Reactive_programming In computing, reactive progr ...
- js手写'Promise'
/* * pending:初始化成功 * fulfilled:成功 * rejected:失败 * */ function Promise(executor) {// 执行器 this.status ...
- vue项目中遇到的那些事。
前言 有好几天没更新文章了.这段实际忙着做了一个vue的项目,从 19 天前开始,到今天刚好 20 天,独立完成. 做vue项目做这个项目一方面能为工作做一些准备,一方面也精进一下技术. 技术栈:vu ...
- hibernate之一对多,多对一
配置文件 <!--一对多--><!--name:集合属性名字 column:外键列名 class:与它相关的对象的完整列名 cascade:级联操作:分3种 save-update: ...
- E: Unable to locate package clang-7 E: Unable to locate package clang++-7 E: Couldn't find any package by regex 'clang++-7'
我的系统是Debian 9.8, 然后在装下面这两个包的时候老是提示找不到.然后再github上一问,过了几分钟就有大佬回复了,而且亲测有效 ~$ sudo apt-get -y install cl ...
- git本机服务器配置(四):git+TortoiseGit+gitblit配置本机服务器
1.配置本机git服务器 1.1 打开gitblit服务器,登录之前设置的服务页面localhost:1081 1.2.登录账号,账号在(三)中有提到. 1.3 打开用户中心 1.4 点击SSH Ke ...
- YOLO v3
yolo为you only look once. 是一个全卷积神经网络(FCN),它有75层卷积层,包含跳跃式传递和降采样,没有池化层,当stide=2时用做降采样. yolo的输出是一个特征映射(f ...
- First Unique Character in a String
Given a string, find the first non-repeating character in it and return it's index. If it doesn't ex ...
- numpy数组取每一列的数据
也可以运用到列表中,a原本是一个列表的嵌套,将a转为了数组进行此操作,可以取固定的值,这就是numpy的好处.
- git上传到版本库报错:Pull is not possible because you have unmerged files(已解决)
问题所在:操作次数太多,第一次报错之删掉了.git并没有删除下面两个文件 才报了题述错误. 解决办法: 将这三个文件都删除在重新运行所有指令.