STM32L476RG_中断开发与实列

本程序的主要功能是实现按键控制灯的亮灭。当灯为灭的状态时按键按下点亮灯,当灯为亮的状态时按键按下熄灭灯,即实现灯的电平翻转操作。

按键扫描是利用 GPIO 下降中断,来监测按键按下动作。并加以消抖操作,便可以获得可靠的按键操作。根据原理图,配置主控芯片与按钮相连引脚外部中断,并设置优先级信息。为了代码可读性和编写方便,我们利用结构体来管理按键信息。同时采用函数指针,进行按键结果回调。 

GPIO 中断回调函数中,会根据 GPIO 引脚记录按键按下的标志和起始系统 Tick 时间。紧靠这些信息还是无法实现按键操作。还需要程序对按键事件进行消抖操作并回调最终结果。 

硬件原理图如下所示:

GPIO.c文件的配置初始化操作。

  1 /* USER CODE BEGIN 0 */
  2 //=================================================================================
  3 //2018.5.16 中断开发与实例
  4 //=================================================================================
  5 #define KEY_DELAY_TICK   20//主要用于按键延迟消抖的操作
  6 //定义一个按键的事件结构体
  7 typedef struct
  8 {
  9   uint8_t key_event;//按键按下事件
 10   int     start_tick;//用于消抖的起始时间 Ticks
 11 }key_press_t;
 12 
 13 static key_press_t key_check_press = {0,0};
 14 
 15 static key_cb   pFkey_cb;
 16 //=================================================================================
 17 //=================================================================================
 18 /* USER CODE END 0 */
 19 
 20 /*----------------------------------------------------------------------------*/
 21 /* Configure GPIO                                                             */
 22 /*----------------------------------------------------------------------------*/
 23 /* USER CODE BEGIN 1 */
 24 
 25 /* USER CODE END 1 */
 26 
 27 /** Configure pins as 
 28         * Analog 
 29         * Input 
 30         * Output
 31         * EVENT_OUT
 32         * EXTI
 33 */
 34 void MX_GPIO_Init(void)
 35 {
 36 
 37   GPIO_InitTypeDef GPIO_InitStruct;
 38 
 39   /* GPIO Ports Clock Enable */
 40   __HAL_RCC_GPIOC_CLK_ENABLE();
 41   __HAL_RCC_GPIOH_CLK_ENABLE();
 42   __HAL_RCC_GPIOA_CLK_ENABLE();
 43   __HAL_RCC_GPIOB_CLK_ENABLE();
 44 
 45   /*Configure GPIO pin Output Level */
 46   HAL_GPIO_WritePin(LED_LD2_GPIO_Port, LED_LD2_Pin, GPIO_PIN_RESET);
 47 
 48   /*Configure GPIO pin : PtPin */
 49   GPIO_InitStruct.Pin = KEY_INPUT_Pin;
 50   GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
 51   GPIO_InitStruct.Pull = GPIO_PULLUP;
 52   HAL_GPIO_Init(KEY_INPUT_GPIO_Port, &GPIO_InitStruct);
 53 
 54   /*Configure GPIO pin : PtPin */
 55   GPIO_InitStruct.Pin = LED_LD2_Pin;
 56   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 57   GPIO_InitStruct.Pull = GPIO_NOPULL;
 58   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 59   HAL_GPIO_Init(LED_LD2_GPIO_Port, &GPIO_InitStruct);
 60 
 61 }
 62 
 63 /* USER CODE BEGIN 2 */
 64 //**************************************
 65 //=================================================================================
 66 //=================================================================================
 67 // fn : GPIO_Led_Toggle
 68 //
 69 // brief : 翻转LED控制引脚电平
 70 //
 71 // param : none
 72 //
 73 // return : none
 74 void GPIO_Led_Toggle(void)
 75 {
 76   HAL_GPIO_TogglePin(LED_LD2_GPIO_Port,LED_LD2_Pin);//用来控制 LED 引脚电平
 77 }
 78 //**************************************
 79 //**************************************
 80 // fn : KEY_RegisterCb
 81 //
 82 // brief : 注册按钮事件回调
 83 //
 84 // param : cb -> 处理按钮事件函数指针
 85 //
 86 // return : none
 87 void KEY_RegisterCb(key_cb cb)
 88 {
 89   if(cb != 0)
 90   {
 91     pFkey_cb = cb;
 92   }
 93 }
 94 
 95 //**************************************
 96 //在 GPIO 中断回调函数中,会根据 GPIO 引脚记录按键按下的标志和起始系统 Tick 时间。
 97 //紧靠这些信息还是无法实现按键操作。还需要程序对按键事件进行消抖操作并回调最终结果。
 98 // fn : KEY_Poll
 99 //
100 // brief : 轮询按钮事件
101 //
102 // param : none
103 //
104 // return : none
105 //在 KEY_Poll 函数中,如果发现 key_event 不为 0,即发现引脚有中断产生。则会进行延
106 //时操作,并最终读取引脚电平,确认按键是否真的按下。 如果真的有按键按下操作,且根据
107 //回调函数指针进行结果上报。
108 void KEY_Poll(void)
109 {
110   uint8_t key_event = 0 ;
111   if(key_check_press.key_event)//key_check_press.key_event = 0x01
112   {
113     if(HAL_GetTick() - key_check_press.start_tick >= KEY_DELAY_TICK )//delay 20ms
114     {
115       if(key_check_press.key_event & KEY_INPUT)//0x01 & 0x01 = true
116       {
117         if(HAL_GPIO_ReadPin(KEY_INPUT_GPIO_Port,KEY_INPUT_Pin) == GPIO_PIN_RESET)//读取引脚电平判断是否按下
118         {
119           key_event |= KEY_INPUT;//全部为false为false  结果为1 true
120         }
121         key_check_press.key_event ^= KEY_INPUT;//异或   0^0x01 = 1 1^0x01 = 0 赋值为0(相等为0,不等为1)等待下一次的按下触发操作
122       }            
123     }
124   }
125     //=======================================================================
126   //如果真的有按钮按下,则执行回调函数
127   if(key_event && pFkey_cb)//key_event不等于0 true 1 && pFkey_cb(pFkey_cb 肯定不等于0)所以结果为true
128   {
129     pFkey_cb(key_event);//true  传入的为1
130   }
131     //=======================================================================
132 }
133 //************************************************************************
134 // fn : HAL_GPIO_EXTI_Callback
135 //
136 // brief : 按键中断回调函数
137 //
138 // param : GPIO_Pin-> 引脚编号
139 //
140 // return : none
141 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
142 {
143   //引脚有中断发生,要进行消抖,以确定是否为有效操作
144   if(GPIO_Pin == KEY_INPUT_Pin)
145   {
146     key_check_press.key_event = KEY_INPUT;//把按键当前的状态传给按键触发事件变量 0x01
147     key_check_press.start_tick = HAL_GetTick();
148   }
149 }
150 //=================================================================================
151 //=================================================================================
152 /* USER CODE END 2 */

GPIO.H文件的基本操作:

 1 /* Define to prevent recursive inclusion -------------------------------------*/
 2 #ifndef __gpio_H
 3 #define __gpio_H
 4 #ifdef __cplusplus
 5  extern "C" {
 6 #endif
 7 
 8 /* Includes ------------------------------------------------------------------*/
 9 #include "stm32l4xx_hal.h"
10 #include "main.h"
11 
12 /* USER CODE BEGIN Includes */
13 
14 /* USER CODE END Includes */
15 
16 /* USER CODE BEGIN Private defines */
17 //定义按键标识
18 #define KEY_INPUT     0x01
19 //定义按键回调函数指针
20 typedef void (*key_cb)(uint8_t pin);
21 /* USER CODE END Private defines */
22 
23 void MX_GPIO_Init(void);
24 
25 /* USER CODE BEGIN Prototypes */
26 //**************************************
27 // fn : KEY_RegisterCb
28 //
29 // brief : 注册按钮事件回调
30 //
31 // param : cb -> 处理按钮事件函数指针
32 //
33 // return : none
34 void KEY_RegisterCb(key_cb cb);
35 
36 //**************************************
37 // fn : KEY_Poll
38 //
39 // brief : 轮询按钮事件
40 //
41 // param : none
42 //
43 // return : none
44 void KEY_Poll(void);
45 /* USER CODE END Prototypes */
46 
47 #ifdef __cplusplus
48 }
49 #endif
50 #endif /*__ pinoutConfig_H */

main.c基本语法:

  1 /* Includes ------------------------------------------------------------------*/
  2 #include "main.h"
  3 #include "stm32l4xx_hal.h"
  4 #include "gpio.h"
  5 
  6 /* USER CODE BEGIN Includes */
  7 
  8 /* USER CODE END Includes */
  9 
 10 /* Private variables ---------------------------------------------------------*/
 11 
 12 /* USER CODE BEGIN PV */
 13 /* Private variables ---------------------------------------------------------*/
 14 
 15 /* USER CODE END PV */
 16 
 17 /* Private function prototypes -----------------------------------------------*/
 18 void SystemClock_Config(void);
 19 static void MX_NVIC_Init(void);
 20 
 21 /* USER CODE BEGIN PFP */
 22 /* Private function prototypes -----------------------------------------------*/
 23 //======================================================================================
 24 //======================================================================================
 25 //******************************************************************************
 26 // fn : AppKey_cb
 27 //
 28 // brief : 处理按键事件
 29 //
 30 // param : key -> 按钮按下标识
 31 //
 32 // return : none
 33 void AppKey_cb(uint8_t key);
 34 //======================================================================================
 35 //======================================================================================
 36 /* USER CODE END PFP */
 37 
 38 /* USER CODE BEGIN 0 */
 39             
 40 /* USER CODE END 0 */
 41 
 42 /**
 43   * @brief  The application entry point.
 44   *
 45   * @retval None
 46   */
 47 int main(void)
 48 {
 49   /* USER CODE BEGIN 1 */
 50     //注册按钮回调函数
 51     //KEY_RegisterCb(AppKey_cb);
 52   /* USER CODE END 1 */
 53 
 54   /* MCU Configuration----------------------------------------------------------*/
 55 
 56   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
 57   HAL_Init();
 58 
 59   /* USER CODE BEGIN Init */
 60 
 61   /* USER CODE END Init */
 62 
 63   /* Configure the system clock */
 64   SystemClock_Config();
 65 
 66   /* USER CODE BEGIN SysInit */
 67 
 68   /* USER CODE END SysInit */
 69 
 70   /* Initialize all configured peripherals */
 71   MX_GPIO_Init();
 72 
 73   /* Initialize interrupts */
 74   MX_NVIC_Init();
 75   /* USER CODE BEGIN 2 */
 76     //===========================================================================
 77     //===========================================================================
 78     //注册按钮回调函数
 79   KEY_RegisterCb(AppKey_cb);//注册按钮回调函数
 80     //===========================================================================
 81     //===========================================================================
 82   /* USER CODE END 2 */
 83 
 84   /* Infinite loop */
 85   /* USER CODE BEGIN WHILE */
 86   while (1)
 87   {
 88 
 89   /* USER CODE END WHILE */
 90 
 91   /* USER CODE BEGIN 3 */
 92         //程序需要写在BEGIN 和 END之间否则下一次导入会覆盖之前的操作
 93         {//这个只能实现点亮灯的操作
 94             //HAL_GPIO_WritePin(LED_LD2_GPIO_Port, LED_LD2_Pin, GPIO_PIN_SET);//OPEN THE LED
 95             //HAL_Delay(1000);//自带延迟函数//延时1000ms
 96             //HAL_GPIO_WritePin(LED_LD2_GPIO_Port, LED_LD2_Pin, GPIO_PIN_RESET);//CLOSED THE LED
 97         }
 98         {//实现某个引脚电平的反转
 99             //GPIO_Led_Toggle();            
100             //HAL_Delay(500);//延时500ms
101         }
102           KEY_Poll();
103   }
104   /* USER CODE END 3 */
105 
106 }
107 
108 /**
109   * @brief System Clock Configuration
110   * @retval None
111   */
112 void SystemClock_Config(void)
113 {
114 
115   RCC_OscInitTypeDef RCC_OscInitStruct;
116   RCC_ClkInitTypeDef RCC_ClkInitStruct;
117 
118     /**Initializes the CPU, AHB and APB busses clocks 
119     */
120   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
121   RCC_OscInitStruct.MSIState = RCC_MSI_ON;
122   RCC_OscInitStruct.MSICalibrationValue = 0;
123   RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
124   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
125   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
126   {
127     _Error_Handler(__FILE__, __LINE__);
128   }
129 
130     /**Initializes the CPU, AHB and APB busses clocks 
131     */
132   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
133                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
134   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
135   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
136   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
137   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
138 
139   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
140   {
141     _Error_Handler(__FILE__, __LINE__);
142   }
143 
144     /**Configure the main internal regulator output voltage 
145     */
146   if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
147   {
148     _Error_Handler(__FILE__, __LINE__);
149   }
150 
151     /**Configure the Systick interrupt time 
152     */
153   HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
154 
155     /**Configure the Systick 
156     */
157   HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
158 
159   /* SysTick_IRQn interrupt configuration */
160   HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
161 }
162 
163 /**
164   * @brief NVIC Configuration.
165   * @retval None
166   */
167 static void MX_NVIC_Init(void)
168 {
169   /* EXTI15_10_IRQn interrupt configuration */
170   HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
171   HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
172 }
173 
174 /* USER CODE BEGIN 4 */
175 //******************************************************************************
176 // fn : AppKey_cb
177 //
178 // brief : 处理按键事件 灯亮的时候灭 灭的时候灯亮
179 //
180 // param : key -> 按钮按下标识
181 //
182 // return : none
183 void AppKey_cb(uint8_t key)
184 {
185   if(key & KEY_INPUT)
186   {
187     {//实现某个引脚电平的反转
188             GPIO_Led_Toggle();            
189             HAL_Delay(500);//延时500ms
190         }        
191   }
192 }
193 /* USER CODE END 4 */
194 
195 /**
196   * @brief  This function is executed in case of error occurrence.
197   * @param  file: The file name as string.
198   * @param  line: The line in file as a number.
199   * @retval None
200   */
201 void _Error_Handler(char *file, int line)
202 {
203   /* USER CODE BEGIN Error_Handler_Debug */
204   /* User can add his own implementation to report the HAL error return state */
205   while(1)
206   {
207   }
208   /* USER CODE END Error_Handler_Debug */
209 }
210 
211 #ifdef  USE_FULL_ASSERT
212 /**
213   * @brief  Reports the name of the source file and the source line number
214   *         where the assert_param error has occurred.
215   * @param  file: pointer to the source file name
216   * @param  line: assert_param error line source number
217   * @retval None
218   */
219 void assert_failed(uint8_t* file, uint32_t line)
220 { 
221   /* USER CODE BEGIN 6 */
222   /* User can add his own implementation to report the file name and line number,
223      tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
224   /* USER CODE END 6 */
225 }
226 #endif /* USE_FULL_ASSERT */

main.h:

 1 /* Define to prevent recursive inclusion -------------------------------------*/
 2 #ifndef __MAIN_H__
 3 #define __MAIN_H__
 4 
 5 /* Includes ------------------------------------------------------------------*/
 6 
 7 /* USER CODE BEGIN Includes */
 8 
 9 /* USER CODE END Includes */
10 
11 /* Private define ------------------------------------------------------------*/
12 
13 #define KEY_INPUT_Pin GPIO_PIN_13
14 #define KEY_INPUT_GPIO_Port GPIOC
15 #define KEY_INPUT_EXTI_IRQn EXTI15_10_IRQn
16 #define LED_LD2_Pin GPIO_PIN_5
17 #define LED_LD2_GPIO_Port GPIOA
18 
19 /* ########################## Assert Selection ############################## */
20 /**
21   * @brief Uncomment the line below to expanse the "assert_param" macro in the 
22   *        HAL drivers code
23   */
24 /* #define USE_FULL_ASSERT    1U */
25 
26 /* USER CODE BEGIN Private defines */
27 
28 /* USER CODE END Private defines */
29 
30 #ifdef __cplusplus
31  extern "C" {
32 #endif
33 void _Error_Handler(char *, int);
34 
35 #define Error_Handler() _Error_Handler(__FILE__, __LINE__)
36 #ifdef __cplusplus
37 }
38 #endif
39 
40 #endif /* __MAIN_H__ */

 

posted @ 2018-05-16 16:30  NEO-Karl  阅读(1740)  评论(0编辑  收藏  举报