1實驗目的
(1)了解按鍵原理及其與S3C2410的接口電路設計
(2)了解S3C2410芯片的外部中斷處理機制
(3)掌握按鍵中斷驅動的編寫及測試過程
(1)按鍵的硬件原理
在嵌入式系統(tǒng)中,按鍵的硬件原理比較簡單,通過一個上拉電阻將處理器的外部中斷(或GPIO)引腳拉高,電阻的另一端連接按鍵并接地即可實現。如圖2-1所示:
圖
2-1按鍵接口電路
仔細看圖2-1,不難知道,當按鍵被按下時,EINT0上將產生低電平,這個低電平將中斷CPU,CPU可以依據中斷判斷按鍵被按下。
(2)按鍵“消抖”
所有按鍵、觸摸屏等機械設備都存在一個固有的問題,那就是"抖動",按鍵從最初接通到穩(wěn)定接通要經過數毫秒乃至數十毫秒,其間可能發(fā)生多次"接通―斷開"的過程。因此僅僅依據中斷被產生就認定有一次按鍵行為是很不準確的。如果不消除"抖動"的影響,一次按鍵可能被理解為多次按鍵。
消除按鍵抖動影響的方法是:在判斷有鍵按下后,進行軟件延時(如20ms,在延時過程中要屏蔽對應中斷),再判斷鍵盤狀態(tài),如果仍處于按鍵按下狀態(tài),則可以判定該按鍵被按下。圖2-2是典型的包含消抖功能的按鍵中斷處理流程。
圖2-2按鍵中斷處理流程
3實驗任務(1)編寫按鍵中斷設備驅動程序,驅動程序中手動定義設備名稱及主設備號為213,實現與BUTTON設備相應的端口配置,中斷的申請,以及讀寫設備的接口函數等。
(2)將驅動編譯成模塊,并實現模塊的加載及卸載。
(3)編寫驅動的測試程序,在程序中實現打開BUTTON設備和LED設備,主循環(huán)中不斷讀取按鍵的狀態(tài),當按鍵按下時,控制LED亮一段時間(1S左右)后滅掉。
4.實驗步驟以下操作都在nfs文件系統(tǒng)目錄(/home/kernel/rootfs/rootfs)下進行,因此先執(zhí)行如下命令。獲取
cd /home/kernel/rootfs/rootfs
(1)編寫led.c文件
建立led目錄:
mkdir usr/button
進入button目錄,在該目錄下建立兩個子目錄driver和test,前者用來存放驅動程序,后者用來存放驅動測試程序:
cd usr/ button
mkdir driver test
進入驅動程序目錄,建立設備驅動文件button.c:
cd driver
vi button.c
按鍵驅動程序如下button.c所示:
/***************************頭文件***************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//***********************定義設備結構體及相關宏***************************
#define DEVICE_NAME"button"http://定義設備名
#define DEVICE_MAJOR213//手動定義BUTTON設備的主設備號為213
static int button_major = DEVICE_MAJOR ;
#define BUTTON_IRQ IRQ_EINT0//定義BUTTON對應S3C2410的外部中斷0
#define BUTTON S3C2410_GPF0//定義BUTTON對應S3C2410的GPF0端口
#defineBUTTON_EINT0 S3C2410_GPF0_EINT0
#defineBUTTON_INP S3C2410_GPF0_INP
#define BUTTON_UP0//按鍵抬起狀態(tài)
#define BUTTON_DOWN1//按鍵按下狀態(tài)
#define BUTTON_X2//不確定狀態(tài),本實例中可理解為抖動狀態(tài)
//定義BUTTON設備結構體
struct button_dev
{
struct cdev cdev;//BUTTON設備對應一個字符設備結構體
int status;//按鍵狀態(tài)標識:抬起、按下、抖動
};
static struct button_dev dev;
//*****************************函數聲明*********************************
void s3c2410_button_s3c2410_button_InitIO(void);//初始化IO端口的函數
/*
******************************s3c2410_button_InitIO**********************
*描述:初始化IO端口
*參數:無
*返回值:無
*************************************************************************
*/
void s3c2410_button_InitIO(void)
{
s3c2410_gpio_cfgpin(BUTTON,BUTTON_EINT0); //配置按鍵中斷的端口為中斷功能
}
/*
******************************isr_button()*******************************
*描述:EINT0的中斷處理函數,設置按鍵狀態(tài)為BUTTON_X
*參數:irq :中斷號; dev_id;regs;
*返回值:成功返回0
*在linux/interrupt.h中定義了typedef irqreturn_t (*irq_handler_t)(int, void *);
*************************************************************************
*/
static irqreturn_t isr_button(int irq,void *dev_id,struct pt_regs *regs)
{
disable_irq(0);//禁止中斷
dev.status = BUTTON_X;//將按鍵置為抖動狀態(tài),說明有按鍵中斷,但不一定有鍵按下
enable_irq(0);//使能中斷
return 0;
}
/*
**************************s3c2410_button_open()**************************
*描述:打開設備函數,向系統(tǒng)申請中斷
*參數:struct inode *inode,struct file *filp
*返回值:失敗返回錯誤代碼ret,成功返回0
*************************************************************************
*/
static int s3c2410_button_open(struct inode *inode,struct file *filp)
{
int ret;
ret=request_irq(BUTTON_IRQ,isr_button,IRQF_SAMPLE_RANDOM,DEVICE_NAME,NULL); //申請中斷
if(ret) {//申請失敗
printk("BUTTON_IRQ: could not register interruptn");
return ret;
}
return 0;
}
/*
************************s3c2410_button_release()*************************
*描述:注銷設備函數,實現中斷釋放
*參數:struct inode *inode,struct file *filp
*返回值:0
*************************************************************************
*/
static int s3c2410_button_release(struct inode *inode,struct file *filp)
{
free_irq(BUTTON_IRQ,NULL); //釋放中斷
return 0;
}
/*
**************************3c2410_button_ioctl()**************************
*描述:IO控制函數,本實例中不做任何事
*參數:cmd:用戶定義的IO控制命令; arg:傳遞用戶參數
*返回值:0
*************************************************************************
*/
static int s3c2410_button_ioctl(struct inode *inode,struct file *filp,
unsigned int cmd,unsigned long arg)
{
return 0;
}
/*
**************************s3c2410_button_read()**************************
*描述:讀函數,讀取按鍵的狀態(tài)
*參數:buffer:用來存儲按鍵狀態(tài);
count:用來記錄用戶讀取了多少個字符
*返回值:count:用戶讀取的字符數
*************************************************************************
*/
static ssize_t s3c2410_button_read(struct file *filp,char *buffer,size_t count,loff_t *ppos)
{
int ret = count;
if(dev.status = BUTTON_X){//如果按鍵狀態(tài)是BUTTON_X,說明有按鍵中斷產生。
msleep(20);//延時20毫秒去除按鍵抖動
disable_irq(0);//禁止中斷
s3c2410_gpio_cfgpin(BUTTON,BUTTON_INP); //配置按鍵中斷的端口為輸入功能
if(!s3c2410_gpio_getpin(BUT