STM32按键实验
后面實現按鍵功能
過程
使能按鍵對應IO口時鐘。調用函數:RCC_APB2PeriphClockCmd()
初始化IO模式:上拉/下拉輸入。調用函數GPIO_Init()
掃描IO口電平(庫函數/寄存器/位操作)
按鍵掃描:
支持連續按:檢測到高電平,認為按鍵沒有按下;檢測到低電平,認為按鍵已經按下。
連續按:只要是低電平就有效。
補充c語言關鍵字 static,static申明的局部變量,存儲在靜態存儲區。它在函數調用之后,不會被釋放,它的值一直保留下來。
static舉例
下面兩個getValue函數,執行效果有什么不一樣呢?
第一個
flag是局部變量,每次調用getValue函數,flag首先被置0,然后flag++,所以每次調用返回值都是1
第二個
這里flag使用static 聲明,由于static具有記憶功能,flag變量在靜態存儲區不被釋放,所以每次getValue函數執行完flag的值一直保留。 第一次調用flag=1;第二次調用返回flag=2;依次類推。
下面給出按鍵掃描的代碼框架
支持連續按:
按下沒有松開,一直有效。
掃描按鍵是否按下,如果按下并且 給10ms的消抖,然后再次確認是否按下,如果確實是按下,則返回鍵值;否則就返回無效值。假設按鍵按下返回值為1,如果按鍵一直按下,則一直返回1.
不支持連續按:
前一次按下如果沒有松開,則本次按無效。
這里需要static 來聲明一個標志位key_up來記錄上一次是否按下:如果沒按,記為1;如果按過,標記為0。
然后把上面兩組代碼合二為一,通過參數來控制是否支持連續按。
如果參數mode=1,表示支持連續按
u8 KEY_Scan( u8 mode){static u8 key_up =1;if(mode==1 ) key_up=1;//支持連續按if(key_up&&KEY按下){//如果上次按鍵沒按下,現在按delay_ms(10);key_up=0;//標志位=0,表示本次按下if(KEY確實按下){return KEY_VALUE:}}else if (KEY沒有按下) key_up=1;return 沒有按下(無效值) }下面開始動手操作
這是宏定義,表示讀取按鍵
#define KEY0 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)//讀取按鍵0 #define KEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)//讀取按鍵1 #define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//讀取按鍵2由原理圖可以知道如下信息:
來源:正點原子
KEY0,KEY1按鍵一端接的是低電平(接地),如果按鍵沒有按下的話,檢測到的是高電平,需要設置成上拉輸入。
上拉輸入的含義是:端口設置為輸入,并且通過電阻接高電平。這樣在沒有按鍵的時候,檢測到的就是高電平。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//PA15GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //設置成上拉輸入GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA15GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//PC5GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //設置成上拉輸入GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC5WK_UP按鍵一端接的是高電平,如果按鍵沒有按下,檢測到的是低電平,需要設置成下拉輸入。
下拉輸入的含義是:端口設置為輸入,并且接低電平(接地)。這樣在沒有按鍵的時候,檢測到的就是低電平。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//PA0GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0設置成輸入,默認下拉 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0初始化按鍵
根據原理圖:
WK_UP 對應的是PA0
KEY1 對應的是PA15
KEY0對應的是PC5
時鐘使能函數使用RCC_APB2PeriphClockCmd(),為什么不使用RCC_APB1PeriphClockCmd()呢?
這里的原因是
兩種的區別包括但是不局限于所對接的端口不同:
APB1負責DA,USB,SPI,I2C,CAN,串口2345,普通TIM。
APB2負責AD,I/O,高級TIM,串口1。
這里有一篇介紹APB1和APB2區別的博客文章,馬住以后看
RCC_APB2PeriphClockCmd()在庫函數中的定義
我們要使用的IO口是PORTA和PORTC,所以時鐘使能端口A和C,這是因為:WK_UP 對應的是PA0,KEY1 對應的是PA15,KEY0對應的是PC5。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);//使能PORTA,PORTC時鐘下面這句話,還需要時間去學習
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//關閉jtag,使能SWD,可以用SWD模式調試它的第一個參數意思是
@arg GPIO_Remap_SWJ_JTAGDisable : JTAG-DP Disabled and SW-DP Enabled后面是結構體的介紹
GPIO_InitTypeDef是一個結構的別名,該結構體成員包括端口,速度,操作模式。
然后聲明一個結構體變量,名字叫做GPIO_InitStructure,通過它來初始化IO口。
//初始化KEY1=PA15GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;//PA15GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//設置成上拉輸入GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化GPIOA15GPIO引腳記錄如下
/** @defgroup GPIO_pins_define * @{*/#define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */ #define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */ #define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */ #define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */ #define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */ #define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */ #define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */ #define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */ #define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */ #define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */ #define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */ #define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */ #define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */ #define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */ #define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */ #define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */ #define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */IO口模式有八種,列舉如下
/** * @brief Configuration Mode enumeration */typedef enum { GPIO_Mode_AIN = 0x0,GPIO_Mode_IN_FLOATING = 0x04,GPIO_Mode_IPD = 0x28,GPIO_Mode_IPU = 0x48,//上拉輸入GPIO_Mode_Out_OD = 0x14,GPIO_Mode_Out_PP = 0x10,GPIO_Mode_AF_OD = 0x1C,GPIO_Mode_AF_PP = 0x18 }GPIOMode_TypeDef;GPIO初始化函數GPIO_Init()在庫函數中的一部分如下
包含兩個參數,第一個參數是IO口(比如PORTA),第二個參數是含有IO口配置信息的的結構體引用。
下面進行一些變量的宏定義
讀取輸入端口函數
IO口輸入輸出
//IO口操作,只對單一的IO口! //確保n的值小于16! #define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //輸出 #define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //輸入 #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //輸出 #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //輸入 #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //輸出 #define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //輸入 #define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //輸出 #define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //輸入 #define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //輸出 #define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //輸入#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //輸出 #define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //輸入#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //輸出 #define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //輸入mini板中
LED0 對應的端口是PA8
LED1對應的端口是PD2
下面的代碼是學習正點原子的代碼
main.c文件
key.c文件
#include "key.h" #include "stm32f10x.h" #include "delay.h"//端口的初始化函數定義 void KEY_Init(void){GPIO_InitTypeDef GPIO_InitStructure;//結構體變量RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);//端口A和端口C時鐘使能GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//調試模式的選擇,使能SWD//初始化KEY1=PA15GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;//PA15GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//設置成上拉輸入GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化GPIOA15//初始化KEY2=PC5GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//設置成上拉輸入GPIO_Init(GPIOC,&GPIO_InitStructure);//初始化GPIOC15//初始化WK_UP=PA0GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//PA0GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0設置成輸入,默認下拉 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0}//按鍵掃描函數的定義 /*mode ==1:允許連續按mode==0 :不允許連續按 */u8 KEY_Scan(u8 mode){static u8 key_up=1;if(mode==1) key_up=1;//如果有按if(key_up&&(KEY0==0||KEY1==0||WK_UP==1)){delay_ms(10);key_up=0;if(KEY0==0) return KEY0_PRES;else if(KEY1==0) return KEY1_PRES;else if(WK_UP==1) return WK_UP_PRES;}//如果都沒有按下else if(KEY0==1&&KEY1==1&&WK_UP==0) key_up=1;//標志位=1,表示沒有按下return 0;//返回值0,表示無按鍵按下 }key.h文件
#ifndef __KEY_H //避免頭文件內容重復引用定義 #define __KEY_H #include "sys.h"//宏定義 按鍵 #define KEY0_PRES 1 #define KEY1_PRES 2 #define WK_UP_PRES 3#define KEY0 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)//讀取按鍵0 #define KEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)//讀取按鍵1 #define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//讀取按鍵2 //聲明函數 void KEY_Init(void); u8 KEY_Scan(u8 mode);#endifled.c
#include "led.h"#include "stm32f10x.h"void LED_Init(void){GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//GPIOB的時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);//GPIOE的時鐘GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//設置推挽輸出GPIO_InitStructure.GPIO_Pin= GPIO_Pin_8;//GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//輸出速度GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_8);GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//設置推挽輸出GPIO_InitStructure.GPIO_Pin= GPIO_Pin_2;//GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//輸出速度GPIO_Init(GPIOD,&GPIO_InitStructure);GPIO_SetBits(GPIOD,GPIO_Pin_2);}led.h
#ifndef __LED_H #define __LED_H#define LED0 PAout(8) //PA8 輸出 #define LED1 PDout(2) //PD2void LED_Init(void);#endif總結
- 上一篇: 从餐桌到田间初体验过程记录及感言?
- 下一篇: stm32跑马灯实验