1. 程式人生 > 其它 >嵌入式linux與物聯網進階之路五:嵌入式驅動方式點亮LED

嵌入式linux與物聯網進階之路五:嵌入式驅動方式點亮LED

話說前面章節講到了如何利用嵌入式驅動開發的方式進行驅動開發。由於其學習路線相比於裸機開發來說,上手難度稍微大一些,而且程式碼量也相對來說較多,所以對剛上手的人來說是頗有難度的。本章節,我們將以一個類似於Hello World點燈的例子,來講解在linux下如何進行核心驅動的開發。

工欲善其事,必先利其器,開始之前,我們需要先將驅動開發用到的主體框架搭建一下,這裡由於上節講過,我這裡直接貼上來:

#include <linux/init.h>  
#include <linux/module.h>
#include <linux/device.h>  
#include <linux/kernel.h>  
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/string.h>

#define LED_MAJOR 200
#define LED_NAME  "LED"

static int led_open(struct inode *inode, struct file *filep){
    printk("GPIO init \n");
    return 0;
}

static int led_write(struct file *filep, const char __user *buf, size_t count, loff_t *ppos){
    return count;
}

static int led_release(struct inode *inode, struct file *filep){
    printk("Release !! \n");
    return 0;
}


static const struct file_operations led_fops = {
    .owner   = THIS_MODULE,
    .open    = led_open,
    .write   = led_write,
    .release = led_release,
};

static int __init led_init(void){

    printk("led control device init success! \r\n");

    return 0;
}

static void __exit led_exit(void){
    printk(" led_exit \r\n");
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("CXSR");

可以看到,整個驅動開發框架無非是如下幾個東西,首先是module_init和module_exit函式,之後就是file_operations結構體,結構體中有對檔案的讀,寫,開啟,關閉等等,我們只需要把我們用到的操作去實現就行了。由於這部分整體比較固化,所以這裡我不再贅述了。

由於在荔枝派中,我選擇了A1口作為我的控制口,所以我先嚐試利用GPIO手動控制了一下,整體控制流程如下:

1、 進入sys/class/gpio目錄下
2、 執行echo 1 > export命令,可以看出來建立了gpio1的資料夾
3、 進入gpio1資料夾,cat direction檢視其值為in,通過vi direction,將其值改為out後, wq儲存。
4、 執行 echo 1 > value 命令,則可以設定A1口高電平,設定echo 0 > value 命令,則可以設定A1口低電平。

通過如上步驟,我們發現,我們可以控制板子上的LED燈的亮滅了。之所以能這麼控制,是因為我們編譯生成的根檔案中,包含了對GPIO的支援,所以使得我們很容易的進行控制。這裡的內容,之後我們會用到,先繼續。

接下來,我們就開始針對剛才的驅動框架模板,來慢慢的填寫我們的內容吧。

#include <linux/init.h>  
#include <linux/module.h>
#include <linux/device.h>  
#include <linux/kernel.h>  
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/string.h>

#define LED_MAJOR 200
#define LED_NAME  "LED"

/*led引腳,這裡是A1腳*/
#define LED_PIN 1
static int gpio_status;

/*使用者態-核心態互動緩衝區*/
static char recv_msg[20];

/*class名稱, 會建立到/sys/class/目錄下 */
static const char *CLASS_NAME = "led_control_class";

/*led分類,由此分類可以創建出裝置*/
static struct class *led_control_class = NULL;

/*led裝置,由此可以實現led控制*/
static struct device *led_control_device = NULL;

/*gpio初始設定*/
static void gpio_config(void){
    if(!gpio_is_valid(LED_PIN)){
        printk("Error wrong gpio number !!\n");
        return;
    }
    gpio_request(LED_PIN, "led_ctr");
    /*設定引腳為輸出狀態*/
    gpio_direction_output(LED_PIN,1);
    /*初始置為高電平*/
    gpio_set_value(LED_PIN,1);
    gpio_status = 1;
}

/*gpio關閉設定*/ static void gpio_deconfig(void){ gpio_free(LED_PIN); }
/*初始燈*/ static int led_open(struct inode *inode, struct file *filep){ printk("GPIO init \n"); gpio_config(); return 0; }
/*為燈的緩衝區進行資料交換*/ static int led_write(struct file *filep, const char __user *buf, size_t count, loff_t *ppos){ int cnt = _copy_from_user(recv_msg, buf, count); if(0 == cnt){
/*on命令, 則開燈*/ if(0 == memcmp(recv_msg, "on", 2)){ printk("LED on! \n"); gpio_set_value(LED_PIN, 1); gpio_status = 1; }
/*off命令,則關燈*/
else{ printk("LED off! \n"); gpio_set_value(LED_PIN, 0); gpio_status = 0; } }else{ printk("ERROR occur when writing!!\n"); return -EIO; } return count; }
/*燈裝置關閉*/ static int led_release(struct inode *inode, struct file *filep){ printk("Release !! \n"); gpio_deconfig(); return 0; } /*檔案操作結構體*/ static const struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, .write = led_write, .release = led_release, };
/*裝置初始化*/ static int __init led_init(void){ int ret = 0; /* 1. 註冊裝置 */ ret = register_chrdev(LED_MAJOR, LED_NAME,&led_fops); if(ret <0){ printk("register fail!\r\n"); return -EIO; } printk("register success, major number is %d \r\n",ret);
/* 2. 建立裝置分類 */ led_control_class = class_create(THIS_MODULE, CLASS_NAME); if(IS_ERR(led_control_class)){ unregister_chrdev(LED_MAJOR, LED_NAME); return -EIO; }    
/* 3. 建立裝置 */ led_control_device = device_create(led_control_class, NULL, MKDEV(LED_MAJOR,0), NULL,LED_NAME); if(IS_ERR(led_control_device)){ class_destroy(led_control_class); unregister_chrdev(LED_MAJOR, LED_NAME); return -EIO; } printk("led control device init success! \r\n"); return 0; }
/*設備註銷*/ static void __exit led_exit(void){ printk(" led_exit \r\n"); device_destroy(led_control_class, MKDEV(LED_MAJOR,0)); class_unregister(led_control_class); class_destroy(led_control_class); unregister_chrdev(LED_MAJOR,LED_NAME); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("CXSR");