文章目錄
- 按鍵掃描
- 設計需求
- 基礎知識
- 硬體設計
- STM32CubeIDE設計
- MX設定
- 代碼設計
- 實驗結果
- 按鍵中斷
- 設計需求
- 基礎知識
- 硬體設計
- STM32CubeIDE設計
- MX設定
- 代碼設計
- 總結
按鍵掃描
設計需求
通過按鍵掃描的方式實作,按下KEY_USER1(KEY1)按鍵,點亮LED_GREEN,再次按下熄滅LED_GREEN;按下KEY_USER2(KEY2)按鍵,點亮LED_YELLOW,再次按下熄滅LED_YELLOW.
基礎知識
前面LED燈是控制GPIO輸出,而按鍵則是讀取GPIO電平,從而獲知按鍵是否按下,
按鍵檢測一般有兩種:按鍵掃描(類似于輪詢)和按鍵中斷(中斷檢測),
按鍵掃描:是間隔很短時間反復查詢GPIO狀態,從而的值是否有按鍵動作,這種方式簡單,但是比較耗費資源,按鍵中斷則是通過按鍵產生中斷信號,從而實作按鍵的檢測,這種方式需要使用到中斷機制,需要對MCU有一定的了解,后面的按鍵中斷實驗將會詳細介紹
按鍵一般占用一個GPIO口,通過檢測該GPIO的電平變化得知按鍵操作,我們查看按鍵原理圖如下
通過原理圖我們可以分析出,當按鍵沒有按下的時候,3.3V的VDD通過電阻直接連在我們的GPIO口上(PG2),那么我們的MCU讀取到的PG2GPIO口的電平就是高電平,當我們的按鍵按下,左邊電路導通,那么我們的GPIO口的電平就是低電平,MCU讀取到的電平就是低電平,
我們常用的按鍵都是機械觸點式按鍵,機械式按鍵在按下或釋放程序中,由于機械彈性作用的影響,會伴隨著機械抖動,如下所示:

抖動的時長與機械開關特性相關,一般為5ms-10ms,在這個抖動程序中,會產生多次高低電平,所以為了確定電平的穩定性,我們需要截取穩定的電平斷,所以我們需要進行按鍵的消抖,按鍵消抖可以硬體上處理,即在硬體旁并聯電容,吸收抖動的電平,也可以軟體處理,即通過延時,避開抖動,
硬體設計

開發板上有4個按鍵,其中兩個是復位按鍵和喚醒按鍵,這次實驗不會介紹,后面介紹,另外兩個按鍵就是我們的上面的KEY1和KEY2.KEY1接在了MCU的PG3腳,并且并聯了一個C34電容用于硬體的消抖,還并聯了一個TVS二極管防靜電,同理,KEY2接在了PG2上,
STM32CubeIDE設計
MX設定
注意這里的紅綠兩個燈也需要配置,就像第一個實驗那樣
代碼設計
driver_led.h
#ifndef DRIVER_LED_H_
#define DRIVER_LED_H_
#include "main.h"
#include "stm32mp1xx_hal.h"
#define LED_GREEN_ON() HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_RESET)
#define LED_GREEN_OFF() HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_SET)
#define LED_YELLOW_ON() HAL_GPIO_WritePin(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin, GPIO_PIN_RESET)
#define LED_YELLOW_OFF() HAL_GPIO_WritePin(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin, GPIO_PIN_SET)
extern void DemoLedInit(void);
extern void LedBlinking(void);
#endif /* DRIVER_LED_H_ */
driver_key.h
#ifndef DRIVER_KEY_H_
#define DRIVER_KEY_H_
#include "driver_led.h"
#include "main.h"
#include "stm32mp1xx_hal.h"
#define PUSH_DOWN GPIO_PIN_RESET
#define PUSH_UP GPIO_PIN_SET
#define KEY1_READ HAL_GPIO_ReadPin(KEY_USER1_GPIO_Port,KEY_USER1_Pin)
#define KEY2_READ HAL_GPIO_ReadPin(KEY_USER2_GPIO_Port,KEY_USER2_Pin)
extern void Scan_key1(void);
extern void Scan_key2(void);
#endif /* DRIVER_KEY_H_ */
driver_key.c
#include "driver_key.h"
#include <stdbool.h>
static bool key1_flag=false;
static bool key2_flag=false;
void Scan_key1(void){
if(KEY1_READ==PUSH_DOWN){//如果按鍵按下
HAL_Delay(5);//延遲5秒,消抖
if(KEY1_READ==PUSH_DOWN){
key1_flag=!key1_flag;
if(key1_flag){
LED_GREEN_ON();//改變綠燈的狀態
}else{
LED_GREEN_OFF();
}
}
}
}
void Scan_key2(void){
if(KEY2_READ==PUSH_DOWN){
HAL_Delay(5);
if(KEY2_READ==PUSH_DOWN){
key2_flag=!key2_flag;
if(key2_flag){
LED_YELLOW_ON();
}else{
LED_YELLOW_OFF();
}
}
}
}
main.c
int main(void)
{
/* USER CODE BEGIN 1 */
static uint32_t sys_freq=0;
/* 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 */
if(IS_ENGINEERING_BOOT_MODE())
{
/* Configure the system clock */
SystemClock_Config();
}
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
sys_freq=HAL_RCC_GetSystemCoreClockFreq();
if(!sys_freq){
return -1;
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
Scan_key1();
Scan_key2();
}
/* USER CODE END 3 */
}
實驗結果
按下和松開KEY2,黃燈進行熄滅,同理KEY1
按鍵中斷
設計需求
通過按鍵中斷的方式實作,按下KEY2,點亮黃燈,再次按下,熄滅黃燈,同理按下KEY1,控制綠燈
基礎知識
-
中斷的基本概念
正常情況下,微處理器根據代碼內容,按順序執行指令,執行程序中,如果遇到其他緊急的事件需要處理,則先暫定當前任務,執行緊急事件,待緊急事件處理完后,再恢復到剛才暫定的地方繼續執行,這個緊急事件就叫做中斷,中斷的執行流程如下圖

-
中斷的分類
CPU在執行指令時,檢測到非法指令,比如除0,地址越界訪問等,會產生中斷,這種中斷屬于內部中斷,也叫系統例外,由CPU外部設備引起的外部事件,比如GPIO中斷,USART中斷等,這屬于外部中斷,
ARM CM4內核可以支持256個中斷(2^8=256,說明是用一個8至少8位的暫存器來表示中斷)16個內部中斷和240個外部中斷,**對于stm32mp157的M4,沒有用到CM4內核的所有資源,只是用到了一部分,只有10個內部中斷和150個外部中斷,總計160個中斷,**如下圖

-
中斷優先級
M4擁有這么多中斷,當這些中斷同時發生時,CPU應該怎么來處理呢?因此就有了中斷優先級的概念,中斷優先級數越小,優先級越高,
搶占優先級:M4支持嵌套中斷,所以當CPU在進行一個中斷的時候,如果來了一個優先級更高的中斷,CPU就立馬取執行優先級更高的中斷
回應優先級:回應優先級就是當優先級相同的中斷同時發生,誰的回應優先級更高,就先執行誰,另一個則等待上一個執行完了在被執行, -
中斷優先級的分組
這是需要我們根據實際情況進行設計的 -
GPIO的中斷
STM32MP157有PA-PI、PZ共10組GPIO,每組GPIO又有0~15共16個GPIO口,數字編號相同的GPIO(PA0,PB0.PC0…)共享一個中斷源,如下圖

硬體設計
就是按鍵的原理圖,同上面的掃描實驗
STM32CubeIDE設計
MX設定


代碼設計
GPIO_init.c
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOG_CLK_ENABLE();//時鐘使能
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_RESET);//初始化綠燈
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : KEY_USER3_Pin KEY_USER2_Pin */
GPIO_InitStruct.Pin = KEY_USER3_Pin|KEY_USER2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;//上升沿觸發中斷
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
/*Configure GPIO pin : LED_GREEN_Pin */
GPIO_InitStruct.Pin = LED_GREEN_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(LED_GREEN_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : LED_YELLOW_Pin */
GPIO_InitStruct.Pin = LED_YELLOW_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(LED_YELLOW_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI2_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
HAL_NVIC_SetPriority(EXTI3_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
}

頭檔案
/*
* driver_key_int.h
*
* Created on: Jan 1, 2022
* Author: lenovo
*/
#ifndef DRIVER_KEY_INT_H_
#define DRIVER_KEY_INT_H_
#include "main.h"
#include "stm32mp1xx_hal.h"
#define LED_GREEN_ON() HAL_GPIO_WritePin(GPIOA,GPIO_PIN_10,GPIO_PIN_RESET);
#define LED_GREEN_OFF() HAL_GPIO_WritePin(GPIOA,GPIO_PIN_10,GPIO_PIN_SET);
#define LED_YELLOW_ON() HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,GPIO_PIN_RESET);
#define LED_YELLOW_OFF() HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,GPIO_PIN_SET);
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin);
#endif /* DRIVER_KEY_INT_H_ */
.c檔案
/*
* driver_key_int.c
*
* Created on: Jan 1, 2022
* Author: lenovo
*/
#include "driver_key_int.h"
#include <stdbool.h>
static bool key1_flag=false;
static bool key2_flag=false;
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin){
switch(GPIO_Pin){
case KEY_USER1_Pin:
{
key1_flag=!key1_flag;
if(key1_flag){
LED_GREEN_ON();
}else{
LED_GREEN_OFF();
}
break;
}
case KEY_USER2_Pin:
{
key2_flag=!key2_flag;
if(key2_flag){
LED_YELLOW_ON();
}else{
LED_YELLOW_OFF();
}
break;
}
break;
}
}
總結
加油
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/401454.html
標籤:其他
下一篇:5款國產ARM芯片替代ST
