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 ...
随机推荐
- kali linux工具--信息批量收集工具theharvester
在渗透测试早期阶段,安全人员往往需要从互联网快速获取目标的一些信息,以确认测试目标的概况.为了满足这个需求,Kali Linux提供了theharvester工具.该工具可以搜索引擎.社交网站获取目标 ...
- react native头部标题样式修改
navigationOptions: ({navigation}) => ({ headerTitle:'评估记录', headerBackTitle:null, headerLeft:null ...
- webstorm快速输入标签
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- vue swiper中的大坑
mounted() { var self = this; for (var i = 0; i < self.$refs.mySwiper.swiper.pagination.bullets.le ...
- 3、if和while语句
a=1 b=2 if a<b: print("Yes") print("Yes") print("Yes") print(" ...
- mysql性能优化分析 --- 下篇
概要回顾 之前看过<高性能mysql>对mysql数据库有了系统化的理解,虽然没能达到精通,但有了概念,遇到问题时会有逻辑条理的分析; 这回继上次sql分析结果的一个继续延伸分析,我拿了; ...
- springboo+nginx测试反向代理02
本节对nginx配置方面会略微研究~~ 1:切换到 /opt/nginx-1.8.1/conf 目录,将nginx.conf文件拷贝到 /myprojects/nginx 目录下 2:切换到/opt/ ...
- 洛谷P4770 [NOI2018]你的名字 [后缀自动机,线段树合并]
传送门 思路 按照套路,直接上后缀自动机. 部分分:\(l=1,r=|S|\) 首先把\(S\)和\(T\)的后缀自动机都建出来. 考虑枚举\(T\)中的右端点\(r\),查询以\(r\)结尾的串最长 ...
- (转)理解maven命令package、install、deploy的联系与区别
我们在用maven构建java项目时,最常用的打包命令有mvn package.mvn install.deploy,这三个命令都可完成打jar包或war(当然也可以是其它形式的包)的功能,但这三个命 ...
- C#接口的简单创建及其用法
我初次接触接口(Interface),对接口的作用有点迷茫,C#接口中包含方法.属性.索引器和事件的声明,但常用的接口中一般就是方法和属性,然而接口中并没有方法的具体实现代码(不能提供任何成员实现), ...