日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ARM(IMX6U)裸机按键输入实验(BSP+SDK、GPIO输入与输出、按键消抖)

發布時間:2023/12/10 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ARM(IMX6U)裸机按键输入实验(BSP+SDK、GPIO输入与输出、按键消抖) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

參考:Linux之ARM(IMX6U)裸機按鍵輸入實驗(GPIO的輸出與輸入)
作者:一只青木呀
發布時間: 2020-08-17 21:43:37
網址:https://blog.csdn.net/weixin_45309916/article/details/108057687

目錄

  • 1、按鍵輸入簡介
  • 2、硬件原理圖分析
    • 原理圖
    • 配置寄存器為GPIO
    • 配置寄存器的電器屬性
  • 3、實驗程序的編寫
    • 3.1、bsp_gpio.h
    • 3.2、bsp_gpio.c
    • 3.3、gpio_key.h
    • 3.4、gpio_key.c(按鍵消抖delay完再讀取狀態值)
    • 3.5、main.c
  • 4、編譯下載驗證
    • 4.1、連接腳本的編寫
    • 4.2、Makefile的編寫
    • 4.3、編譯下載
  • 出現的問題(清除BSS段代碼4字節對齊)

前面幾篇文章試驗都是講解如何使用 I.MX6U 的 GPIO 輸出控制功能, I.MX6U 的 IO 不僅能作為輸出,而且也可以作為輸入。 I.MX6U-ALPHA 開發板上有一個按鍵,按鍵連接了一個 IO,將這個 IO 配置為輸入功能,讀取這個 IO 的值即可獲取按鍵的狀態(按下或松開)。本篇文章通過這個按鍵來控制蜂鳴器的開關

1、按鍵輸入簡介

按鍵就兩個狀態:按下或彈起,將按鍵連接到一個 IO 上,通過讀取這個 IO 的值就知道按鍵是按下的還是彈起的。至于按鍵按下的時候是高電平還是低電平要根據實際電路來判斷。

I.MX6U-ALPHA 開發板上有一個按鍵 KEY0,本篇文章我們將會編寫代碼通過這個 KEY0 按鍵來控制開發板上的蜂鳴器,按一下 KEY0 蜂鳴器打開,再按一下蜂鳴器就關閉

2、硬件原理圖分析

本試驗我們用到的硬件有:

1) LED 燈 LED0。
2)蜂鳴器。
3) 1 個按鍵 KEY0。

原理圖

按鍵 KEY0 的原理圖如圖 15.2.1 所示:


從圖可以看出,按鍵 KEY0 是連接到 I.MX6U 的 UART1_CTS 這個 IO 上的, KEY0接了一個 10K 的上拉電阻,因此KEY0 沒有按下的時候 UART1_CTS 應該是高電平,當 KEY0按下以后 UART1_CTS 就是低電平,采用輪詢方式檢測。

配置寄存器為GPIO

配置寄存器的電器屬性


位描述
bit 160 HYS 關閉
bit [15:14]11 默認 22K 上拉
bit [13]1 pull 功能
bit [12]1 pull/keeper 使能
bit [11]0 關閉開路輸出
bit [7:6]10 速度 100Mhz
bit [5:3]000 關閉輸出
bit [0]0 低轉換率

3、實驗程序的編寫

本次實在在上一次實驗的基礎上完成(蜂鳴器實驗),我們把上一篇的代碼復制一份,在上面做修改,重新創建 VSCode 工程,工作區名字為“key”,在工程目錄的 bsp 文件夾中創建名為“key”和“gpio”兩個文件夾。按鍵相關的驅動文件都放到“key”文件夾中,本次試驗我們對 GPIO 的操作編寫一個函數集合,也就是編寫一個 GPIO驅動文件, GPIO 的驅動文件放到“gpio”文件夾里面。

新建 bsp_gpio.c 和 bsp_gpio.h 這兩個文件,將這兩個文件都保存到剛剛創建的 bsp/gpio 文件夾里面

3.1、bsp_gpio.h

#ifndef __BSP_KEY_H #define __BSP_KEY_H#include "imx6ul.h"typedef enum _gpio_pin_direction {//枚舉類型kGPIO_DigitalInput = 0U, /*輸入*/kGPIO_DigitalOutput = 1U, /*輸出*/}gpio_pin_direction_t;typedef struct _gpio_pin_config {gpio_pin_direction_t direction; /*gpio方向:輸入還是輸出*/uint8_t outputLogic; /*如果是輸出的話,默認輸出低電平*/}gpio_pin_config_t;void gpio_init(GPIO_Type *base,int pin, gpio_pin_config_t *config); int gpio_pinread(GPIO_Type *base,int pin); void gpio_pinwrite(GPIO_Type *base,int pin,int value);#endif // !__BSP_KEY_H

bsp_gpio.h 中定義了一個枚舉類型 gpio_pin_direction_t 和結構體 gpio_pin_config_t,枚舉類型 gpio_pin_direction_t 表示 GPIO 方向,輸入或輸出。結構體 gpio_pin_config_t 是 GPIO 的配置結構體,里面有 GPIO 的方向和默認輸出電平兩個成員變量

3.2、bsp_gpio.c

#include "bsp_gpio.h"/** @description : GPIO 初始化。* @param - base : 要初始化的 GPIO 組。* @param - pin : 要初始化 GPIO 在組內的編號。* @param - config : GPIO 配置結構體。* @return : 無*/void gpio_init(GPIO_Type *base,int pin, gpio_pin_config_t *config) {if(config->direction == kGPIO_DigitalInput) /*輸入*/{base->GDIR &= ~(1 << pin);}else /*輸出*/{base->GDIR |= (1 << pin);gpio_pinwrite(&base,pin,config->outputLogic); /*默認輸出電平*/}}/** @description : 讀取指定 GPIO 的電平值 。* @param – base : 要讀取的 GPIO 組。* @param - pin : 要讀取的 GPIO 腳號。* @return : 無*/int gpio_pinread(GPIO_Type *base,int pin) {return (((base->DR) >> pin) & 0x1); }/** @description : 指定 GPIO 輸出高或者低電平 。* @param – base : 要輸出的的 GPIO 組。* @param - pin : 要輸出的 GPIO 腳號。* * @param – value : 要輸出的電平, 1 輸出高電平, 0 輸出低低電平* @return : 無*/void gpio_pinwrite(GPIO_Type *base,int pin,int value) {if(value == 0U){base->DR &= ~(1U<<pin); /*輸出低電平*/}else{base->DR |= (1U << pin); /*輸出高電平*/}}

文件 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_key.c 和 bsp_key.h 這兩個文件,將這兩個文件都保存到剛剛創建的 bsp/key 文件夾里面

3.3、gpio_key.h

#ifndef __BSP_KEY_H #define __BSP_KEY_H#include "imx6ul.h" #include "bsp_delay.h"/*定義按鍵值 枚舉 方便有多個按鍵 這里只有一個按鍵*/ enum keyvalue {KEY_NONE =0,KEY_VALUE , };/*函數聲明*/ void key_init(); int key_get_value();#endif // !__BSP_KEY_H

bsp_key.h 文件中定義了一個枚舉類型: keyvalue, 此枚舉類型表示按鍵值, 因為 I.MX6UALPHA 開發板上只有一個按鍵,因此枚舉類型里面只到 KEY0_VALUE

3.4、gpio_key.c(按鍵消抖delay完再讀取狀態值)

#include "bsp_key.h"/** @description : 初始化按鍵* @param : 無* @return : 無*/void key_init(void) {gpio_pin_config_t key_config;/* 1、初始化 IO 復用, 復用為 GPIO1_IO18 .h文件找到這個宏*/IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0);/* 2、、配置 UART1_CTS_B 的 IO 屬性*bit 16:0 HYS 關閉*bit [15:14]: 11 默認 22K 上拉*bit [13]: 1 pull 功能*bit [12]: 1 pull/keeper 使能*bit [11]: 0 關閉開路輸出*bit [7:6]: 10 速度 100Mhz*bit [5:3]: 000 關閉輸出*bit [0]: 0 低轉換率*/ //0xf080演算過程如下圖所示IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xf080);/* 3、初始化 GPIO GPIO1_IO18 設置為輸入*/key_config.direction=kGPIO_DigitalInput;gpio_init(GPIO1,18,&key_config);//或者不用庫函數 直接操作結構體里的寄存器://GPIO1->GDIR &= ~(1<<18);}/* * @description : 獲取按鍵值 * @param : 無 * @return : 0 沒有按鍵按下,其他值:對應的按鍵值 */ int key_get_value(void) {int ret =0;static unsigned char release =1; /*為1表示按鍵處于釋放狀態*/if((release == 1) && (gpio_pin_read(GPIO1,18) == 0))//釋放狀態下檢測到按鍵被按下{delay(10); /*按鍵消抖處理 大概10ms就夠了*/release = 0;if(gpio_pin_read(GPIO1,18) == 0)//延時10ms讀取還是0 說明按鍵按下是有效的{ret = KEY_VALUE;}}else if(gpio_pin_read(GPIO1,18) == 1)//沒有被按下{ret =0;release = 1;}return ret; }

程序中2、配置 UART1_CTS_B 的 IO 屬性的演算過程:
按鍵消抖原理:

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 表示按鍵是否釋放。

3.5、main.c

#include "main.h"int main() {int i=0;int keyvalue=0; unsigned char led_status= OFF;unsigned char beep_status= OFF;clk_enable(); //使能外設時鐘led_init(); //初始化LEDinit_beep();//初始化蜂鳴器key_init(); //初始化keywhile(1){//按鍵控制蜂鳴器keyvalue = key_getvalue();if(keyvalue)//值為正 表示有效的按鍵值{switch (keyvalue)//按鍵狀態{case KEY_VALUE://這里只寫了一種casebeep_status=!beep_status;beep_switch(beep_status);break;default:break;}}i++;if(i==50)//50*10=500ms 燈亮滅一次{i=0;led_status=!led_status;led_switch(LED0,led_status);}}return 0; }

main.c 函數先初始化 led 燈、蜂鳴器和按鍵,然后在 while(1)循環中不斷的調用函數key_getvalue 來讀取按鍵值,如果 KEY0 按下的話就打開/關閉蜂鳴器。 LED0 作為系統提示指示燈閃爍,閃爍周期大約為 500ms。

4、編譯下載驗證

4.1、連接腳本的編寫

SECTIONS {. = 0x87800000;.text :{obj/start.o*(.text)}.rodata ALIGN(4) : {*(.rodata*)}.data ALIGN(4) : {*(.data)}. = ALIGN(4) ;__bss_start = .;.bss ALIGN(4) : { *(.bss) *(COMMON)}__bss_end = .; }

這里注意bss段需要四字節對其,否則會清除其他字段的內容,造成程序的崩潰

4.2、Makefile的編寫

CROSS_COMPILE ?= arm-linux-gnueabihf- TARGET ?= keyCC := $(CROSS_COMPILE)gcc LD := $(CROSS_COMPILE)ld OBJCOPY := $(CROSS_COMPILE)objcopy OBJDUMP := $(CROSS_COMPILE)objdumpINCDIRS := imx6ul \bsp/clk \bsp/led \bsp/delay \bsp/beep \bsp/gpio \bsp/keySRCDIRS := project \bsp/clk \bsp/led \bsp/delay \bsp/beep \bsp/key \bsp/gpio INCLUDE := $(patsubst %, -I %, $(INCDIRS))SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.s)) CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))SFILENDIR := $(notdir $(SFILES)) CFILENDIR := $(notdir $(CFILES))SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.s=.o)) COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o)) OBJS := $(SOBJS) $(COBJS)VPATH := $(SRCDIRS).PHONY: clean$(TARGET).bin : $(OBJS)$(LD) -Timx6ul.lds -o $(TARGET).elf $^$(OBJCOPY) -O binary -S $(TARGET).elf $@$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis$(SOBJS) : obj/%.o : %.s$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<$(COBJS) : obj/%.o : %.c$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<clean:rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)

4.3、編譯下載

使用 Make 命令編譯代碼,編譯成功以后使用軟件 imxdownload 將編譯完成的 key.bin 文件下載到 SD 卡中,命令如下:

chmod 777 imxdownload //給予 imxdownload 可執行權限,一次即可 ./imxdownload key.bin /dev/sdd //燒寫到 SD 卡中

燒寫成功以后將 SD 卡插到開發板的 SD 卡槽中,然后復位開發板。如果代碼運行正常的話 LED0 會以大約 500ms 周期閃爍, 按下開發板上的 KEY0 按鍵,蜂鳴器打開,再按下 KEY0按鍵,蜂鳴器關閉

具體燒寫過程請參考程序燒寫到SD卡詳情

出現的問題(清除BSS段代碼4字節對齊)

解決方法:


編譯再次查看反匯編文件中BSS段的地址

按照四字節對齊原則,發現往后移動了,能被4整除

總結

以上是生活随笔為你收集整理的ARM(IMX6U)裸机按键输入实验(BSP+SDK、GPIO输入与输出、按键消抖)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。