linux键盘设置的文件在哪个文件夹,「正点原子Linux连载」第十五章按键输入试验...
原標題:「正點原子Linux連載」第十五章按鍵輸入試驗
第十五章按鍵輸入試驗
前面幾章試驗都是講解如何使用I.MX6U的GPIO輸出控制功能,I.MX6U的IO不僅能作為輸出,而且也可以作為輸入。I.MX6U-ALPHA開發板上有一個按鍵,按鍵連接了一個IO,將這個IO配置為輸入功能,讀取這個IO的值即可獲取按鍵的狀態(按下或松開)。本章通過這個按鍵來控制蜂鳴器的開關,通過本章的學習你將掌握如何將I.MX6UL的IO作為輸入來使用。
15.1按鍵輸入簡介
按鍵就兩個狀態:按下或彈起,將按鍵連接到一個IO上,通過讀取這個IO的值就知道按鍵是按下的還是彈起的。至于按鍵按下的時候是高電平還是低電平要根據實際電路來判斷。前面幾章我們都是講解I.MX6U的GPIO作為輸出使用,當GPIO連接按鍵的時候就要做為輸入使用。關于I.MX6U的GPIO已經在第八章詳細的講解了,本章我們的主要工作就是配置按鍵所連接的IO為輸入功能,然后讀取這個IO的值來判斷按鍵是否按下。
I.MX6U-ALPHA開發板上有一個按鍵KEY0,本章我們將會編寫代碼通過這個KEY0按鍵來控制開發板上的蜂鳴器,按一下KEY0蜂鳴器打開,再按一下蜂鳴器就關閉。
15.2 硬件原理分析
本試驗我們用到的硬件有:
1) LED燈LED0。
2)蜂鳴器。
3)1個按鍵KEY0。
按鍵KEY0的原理圖如圖15.2.1所示:
圖15.2.1 按鍵原理圖
從圖15.2.1可以看出,按鍵KEY0是連接到I.MX6U的UART1_CTS這個IO上的,KEY0接了一個10K的上拉電阻,因此KEY0沒有按下的時候UART1_CTS應該是高電平,當KEY0按下以后UART1_CTS就是低電平。
15.3實驗程序編寫
本實驗對應的例程路徑為:開發板光盤-> 1、裸機例程->7_key。
本試驗在上一章試驗例程的基礎上完成,重新創建VSCode工程,工作區名字為“key”,在工程目錄的bsp文件夾中創建名為“key”和“gpio”兩個文件夾。按鍵相關的驅動文件都放到“key”文件夾中,本章試驗我們對GPIO的操作編寫一個函數集合,也就是編寫一個GPIO驅動文件,GPIO的驅動文件放到“gpio”文件夾里面。
新建bsp_gpio.c和bsp_gpio.h這兩個文件,將這兩個文件都保存到剛剛創建的bsp/gpio文件夾里面,然后在bsp_gpio.h文件夾里面輸入如下內容:
示例代碼15.3.1 bsp_gpio.h文件代碼
1 #ifndef _BSP_GPIO_H
2 #define _BSP_GPIO_H
3 #define _BSP_KEY_H
4 #include "imx6ul.h"
5/***************************************************************
6 Copyright zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
7文件名 : bsp_gpio.h
8作者 : 左忠凱
9版本 : V1.0
10描述 : GPIO操作文件頭文件。
11其他 : 無
12論壇 : www.openedv.com
13日志 : 初版V1.0 2019/1/4 左忠凱創建
14 ***************************************************************/
15
16/* 枚舉類型和結構體定義 */
17
typedef
enum _gpio_pin_direction
18
{
19 kGPIO_DigitalInput
=
0U
,
/* 輸入 */
20 kGPIO_DigitalOutput
=
1U
,
/* 輸出 */
21
}
gpio_pin_direction_t
;
22
23/* GPIO配置結構體 */
24
typedef
struct _gpio_pin_config
25
{
26 gpio_pin_direction_t direction
;
/* GPIO方向:輸入還是輸出 */
27uint8_t outputLogic
;
/* 如果是輸出的話,默認輸出電平 */
28
}
gpio_pin_config_t
;
29
30
31/* 函數聲明 */
32void gpio_init
(
GPIO_Type
*
base
,
int pin
,
gpio_pin_config_t
*
config
);
33int gpio_pinread
(
GPIO_Type
*
base
,
int pin
);
34void gpio_pinwrite
(
GPIO_Type
*
base
,
int pin
,
int value
);
35
36 #endif
bsp_gpio.h中定義了一個枚舉類型gpio_pin_direction_t和結構體gpio_pin_config_t,枚舉類型gpio_pin_direction_t表示GPIO方向,輸入或輸出。結構體gpio_pin_config_t是GPIO的配置結構體,里面有GPIO的方向和默認輸出電平兩個成員變量。在bsp_gpio.c中輸入如下所示內容:
示例代碼15.3.2 bsp_gpio.c文件代碼
1 #include "bsp_gpio.h"
2/***************************************************************
3 Copyright zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
4文件名 : bsp_gpio.h
5作者 : 左忠凱
6版本 : V1.0
7描述 : GPIO操作文件。
8其他 : 無
9論壇 : www.openedv.com
10日志 : 初版V1.0 2019/1/4 左忠凱創建
11 ***************************************************************/
12
13/*
14 * @description : GPIO初始化。
15 * @param - base : 要初始化的GPIO組。
16 * @param - pin : 要初始化GPIO在組內的編號。
17 * @param - config : GPIO配置結構體。
18 * @return : 無
19 */
20void gpio_init
(
GPIO_Type
*
base
,
int pin
,
gpio_pin_config_t
*
config
)
21
{
22
if(
config
->
direction
==
kGPIO_DigitalInput
)
/* 輸入 */
23
{
24 base
->
GDIR
&=~(
1
<<
pin
);
25
}
26
else
/* 輸出 */
27
{
28 base
->
GDIR
|=
1
<<
pin
;
29 gpio_pinwrite
(
base
,
pin
,
config
->
outputLogic
);
/* 默認輸出電平 */
30
}
31
}
32
33/*
34 * @description : 讀取指定GPIO的電平值。
35 * @param – base : 要讀取的GPIO組。
36 * @param - pin : 要讀取的GPIO腳號。
37 * @return : 無
38 */
39int gpio_pinread
(
GPIO_Type
*
base
,
int pin
)
40
{
41
return(((
base
->
DR
)>>
pin
)&
0x1
);
42
}
43
44/*
45 * @description : 指定GPIO輸出高或者低電平。
46 * @param – base : 要輸出的的GPIO組。
47 * @param - pin : 要輸出的GPIO腳號。
48 * @param – value : 要輸出的電平,1 輸出高電平, 0 輸出低低電平
49 * @return : 無
50 */
51void gpio_pinwrite
(
GPIO_Type
*
base
,
int pin
,
int value
)
52
{
53
if(
value
==
0U
)
54
{
55 base
->
DR
&=~(
1U
<<
pin
);
/* 輸出低電平 */
56
}
57
else
58
{
59 base
->
DR
|=(
1U
<<
pin
);
/* 輸出高電平 */
60
}
61
}
文件bsp_gpio.c中有三個函數:gpio_init、gpio_pinread和gpio_pinwrite,函數gpio_init用于初始化指定的GPIO引腳,最終配置的是GDIR寄存器,此函數有三個參數,這三個參數的含義如下:
base:
要初始化的GPIO所屬于的GPIO組,比如GPIO1_IO18就屬于GPIO1組。
pin:
要初始化GPIO在組內的標號,比如GPIO1_IO18在組內的編號就是18。
config:
要初始化的GPIO配置結構體,用來指定GPIO配置為輸出還是輸入。
函數gpio_pinread是讀取指定的GPIO值,也就是讀取DR寄存器的指定位,此函數有兩個參數和一個返回值,參數含義如下:
base:
要讀取的GPIO所屬于的GPIO組,比如GPIO1_IO18就屬于GPIO1組。
pin:
要讀取的GPIO在組內的標號,比如GPIO1_IO18在組內的編號就是18。
返回值:
讀取到的GPIO值,為0或者1。
函數gpio_pinwrite是控制指定的GPIO引腳輸入高電平(1)或者低電平(0),就是設置DR寄存器的指定位,此函數有三個參數,參數含義如下:
base:
要設置的GPIO所屬于的GPIO組,比如GPIO1_IO18就屬于GPIO1組。
pin:
要設置的GPIO在組內的標號,比如GPIO1_IO18在組內的編號就是18。
value:
要設置的值,1(高電平)或者0(低電平)。
我們以后就可以使用函數gpio_init設置指定GPIO為輸入還是輸出,使用函數gpio_pinread和gpio_pinwrite來讀寫指定的GPIO,文件bsp_gpio.c文件就講解到這里。
接下來編寫按鍵驅動文件,新建bsp_key.c和bsp_key.h這兩個文件,將這兩個文件都保存到剛剛創建的bsp/key文件夾里面,然后在bsp_key.h文件夾里面輸入如下內容:
示例代碼15.3.3 bsp_key.h文件代碼
1 #ifndef _BSP_KEY_H
2 #define _BSP_KEY_H
3 #include "imx6ul.h"
4/***************************************************************
5 Copyright zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
6文件名 : bsp_key.h
7作者 : 左忠凱
8版本 : V1.0
9描述 : 按鍵驅動頭文件。
10其他 : 無
11論壇 : www.openedv.com
12日志 : 初版V1.0 2019/1/4 左忠凱創建
13 ***************************************************************/
14
15/* 定義按鍵值 */
16enum keyvalue
{
17 KEY_NONE
=
0
,
18 KEY0_VALUE
,
19
};
20
21/* 函數聲明 */
22void key_init
(
void
);
23int key_getvalue
(
void
);
24
25 #endif
bsp_key.h文件中定義了一個枚舉類型:keyvalue,此枚舉類型表示按鍵值,因為I.MX6U-ALPHA開發板上只有一個按鍵,因此枚舉類型里面只到KEY0_VALUE。在bsp_key.c中輸入如下所示內容:
示例代碼15.3.4 bsp_key.c文件代碼
1 #include "bsp_key.h"
2 #include "bsp_gpio.h"
3 #include "bsp_delay.h"
4/***************************************************************
5 Copyright zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
6文件名 : bsp_key.c
7作者 : 左忠凱
8版本 : V1.0
9描述 : 按鍵驅動文件。
10其他 : 無
11論壇 : www.openedv.com
12 日志 : 初版V1.0 2019/1/4 左忠凱創建
13 ***************************************************************/
14
15/*
16 * @description : 初始化按鍵
17 * @param : 無
18 * @return : 無
19 */
20void key_init
(
void
)
21
{
22 gpio_pin_config_t key_config
;
23
24 /* 1、初始化IO復用, 復用為GPIO1_IO18 */
25 IOMUXC_SetPinMux
(
IOMUXC_UART1_CTS_B_GPIO1_IO18
,
0
);
26
27 /* 2、、配置UART1_CTS_B的IO屬性
28 *bit 16:0 HYS關閉
29 *bit [15:14]: 11 默認22K上拉
30 *bit [13]: 1 pull功能
31 *bit [12]: 1 pull/keeper使能
32 *bit [11]: 0 關閉開路輸出
33 *bit [7:6]: 10 速度100Mhz
34 *bit [5:3]: 000 關閉輸出
35 *bit [0]: 0 低轉換率
36 */
37 IOMUXC_SetPinConfig
(
IOMUXC_UART1_CTS_B_GPIO1_IO18
,
0xF080
);
38
39 /* 3、初始化GPIO GPIO1_IO18設置為輸入*/
40 key_config
.
direction
=
kGPIO_DigitalInput
;
41 gpio_init
(
GPIO1
,
18
,&
key_config
);
42
43
}
44
45 /*
46 * @description : 獲取按鍵值
47 * @param : 無
48 * @return : 0 沒有按鍵按下,其他值:對應的按鍵值
49 */
50int key_getvalue
(
void
)
51
{
52 int ret
=
0
;
53 staticunsignedchar release
=
1
;
/* 按鍵松開 */
54
55
if((
release
==
1
)&&(
gpio_pinread
(
GPIO1
,
18
)==
0
))
/* KEY0按下 */
56
{
57 delay
(
10
);
/* 延時消抖 */
58 release
=
0
;
/* 標記按鍵按下 */
59
if(
gpio_pinread
(
GPIO1
,
18
)==
0
)
60 ret
=
KEY0_VALUE
;
61
}
62
elseif(
gpio_pinread
(
GPIO1
,
18
)==
1
)
/* KEY0未按下 */
63
{
64 ret
=
0
;
65 release
=
1
;
/* 標記按鍵釋放 */
66
}
67
68
return
ret
;
69
}
bsp_key.c中一共有兩個函數:key_init和key_getvalue,key_init是按鍵初始化函數,用來初始化按鍵所使用的UART1_CTS這個IO。函數key_init先設置UART1_CTS復用為GPIO1_IO18,然后配置UART1_CTS這個IO為速度為100MHz,默認22K上拉。最后調用函數gpio_init來設置GPIO1_IO18為輸入功能。
函數key_getvalue用于獲取按鍵值,此函數沒有參數,只有一個返回值,返回值表示按鍵值,返回值為0的話就表示沒有按鍵按下,如果返回其他值的話就表示對應的按鍵按下了。獲取按鍵值其實就是不斷的讀取GPIO1_IO18的值,如果按鍵按下的話相應的IO被拉低,那么GPIO1_IO18值就為0,如果按鍵未按下的話GPIO1_IO18的值就為1。此函數中靜態局部變量release表示按鍵是否釋放。
“示例代碼15.3.4”中的57行是按鍵消抖延時函數,延時時間大約為10ms,用于消除按鍵抖動。理想型的按鍵電壓變化過程如圖15.3.1所示:
圖15.3.1 理想的按鍵電壓變化過程
在圖15.3.1中,按鍵沒有按下的時候按鍵值為1,當按鍵在t1時刻按鍵被按下以后按鍵值就變為0,這是最理想的狀態。但是實際的按鍵是機械結構,加上剛按下去的一瞬間人手可能也有抖動,實際的按鍵電壓變化過程如圖15.3.2所示:
圖15.3.2實際的按鍵電壓變化過程
在圖15.3.2中t1時刻按鍵被按下,但是由于抖動的原因,直到t2時刻才穩定下來,t1到t2這段時間就是抖動。一般這段時間就是十幾ms左右,從圖15.3.2中可以看出在抖動期間會有多次觸發,如果不消除這段抖動的話軟件就會誤判,本來按鍵就按下了一次,結果軟件讀取IO值發現電平多次跳變以為按下了多次。所以我們需要跳過這段抖動時間再去讀取按鍵的IO值,也就是至少要在t2時刻以后再去讀IO值。在“示例代碼15.3.4”中的57行是延時了大約10ms后再去讀取GPIO1_IO18的IO值,如果此時按鍵的值依舊是0,那么就表示這是一次有效的按鍵觸發。
按鍵驅動就講解到這里,最后就是main.c文件的內容了,在main.c中輸入如下代碼:
示例代碼15.3.5 main.c文件代碼
/**************************************************************
Copyright zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名 : mian.c
作者 : 左忠凱
版本 : V1.0
描述 : I.MX6U開發板裸機實驗7 按鍵輸入實驗
其他 : 本實驗主要學習如何配置I.MX6U的GPIO作為輸入來使用,通過
開發板上的按鍵控制蜂鳴器的開關。
論壇 : www.openedv.com
日志 : 初版V1.0 2019/1/4 左忠凱創建
**************************************************************/
1 #include "bsp_clk.h"
2 #include "bsp_delay.h"
3 #include "bsp_led.h"
4 #include "bsp_beep.h"
5 #include "bsp_key.h"
6
7/*
8 * @description : main函數
9 * @param : 無
10 * @return : 無
11 */
12int main
(
void
)
13
{
14 int i
=
0
;
15 int keyvalue
=
0
;
16 unsignedchar led_state
=
OFF
;
17 unsignedchar beep_state
=
OFF
;
18
19 clk_enable
();
/* 使能所有的時鐘 */
20 led_init
();
/* 初始化led */
21 beep_init
();
/* 初始化beep */
22 key_init
();
/* 初始化key */
23
24
while(
1
)
25
{
26 keyvalue
=
key_getvalue
();
27
if(
keyvalue
)
28
{
29
switch(
keyvalue
)
30
{
31
case
KEY0_VALUE
:
32 beep_state
=!
beep_state
;
33 beep_switch
(
beep_state
);
34
break;
35
}
36
}
37 i
++;
38
if(
i
==
50
)
39
{
40 i
=
0
;
41 led_state
=!
led_state
;
42 led_switch
(
LED0
,
led_state
);
43
}
44 delay
(
10
);
45
}
46
return
0
;
47
}
main.c函數先初始化led燈、蜂鳴器和按鍵,然后在while(1)循環中不斷的調用函數key_getvalue來讀取按鍵值,如果KEY0按下的話就打開/關閉蜂鳴器。LED0作為系統提示指示燈閃爍,閃爍周期大約為500ms。本章例程的軟件編寫就到這里結束了,接下來就是編譯下載驗證了。
15.4編譯下載驗證
15.4.1編寫Makefile和鏈接腳本
Makefile使用第十三章編寫的通用Makefile,修改變量TARGET為key,在變量INCDIRS和SRCDIRS中追加“bsp/gpio”和“bsp/key”,修改完成以后如下所示:
示例代碼15.4.1.1 Makefile文件代碼
1 CROSS_COMPILE ?
=
arm-linux-gnueabihf-
2 TARGET ?
=
key
3
4/* 省略掉其它代碼...... */
5
6 INCDIRS
:=
imx6ul \
7 bsp/clk \
8 bsp/led \
9 bsp/delay \
10 bsp/beep \
11 bsp/gpio \
12 bsp/key
13
14 SRCDIRS
:=
project \
15 bsp/clk \
16 bsp/led \
17 bsp/delay \
18 bsp/beep \
19 bsp/gpio \
20 bsp/key
21
22/* 省略掉其它代碼...... */
23
24 clean
:
25 rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS)$(SOBJS)
第2行修改變量TARGET為“key”,也就是目標名稱為“key”。
第11、12行在變量INCDIRS中添加GPIO和按鍵驅動頭文件(.h)路徑。
第19、20行在變量SRCDIRS中添加GPIO和按鍵驅動文件(.c)路徑。
鏈接腳本就使用第十三章試驗中的鏈接腳本文件imx6ul.lds即可。
15.4.2編譯下載
使用Make命令編譯代碼,編譯成功以后使用軟件imxdownload將編譯完成的key.bin文件下載到SD卡中,命令如下:
chmod 777 imxdownload //給予imxdownload可執行權限,一次即可
./imxdownload key.bin /dev/sdd //燒寫到SD卡中
燒寫成功以后將SD卡插到開發板的SD卡槽中,然后復位開發板。如果代碼運行正常的話LED0會以大約500ms周期閃爍,按下開發板上的KEY0按鍵,蜂鳴器打開,再按下KEY0按鍵,蜂鳴器關閉。
責任編輯:
總結
以上是生活随笔為你收集整理的linux键盘设置的文件在哪个文件夹,「正点原子Linux连载」第十五章按键输入试验...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux自启进程管理工具,进程管理工具
- 下一篇: linux 内核 3.18,Linux