嵌入式LINUX驅動學習之7中斷相關(四)定時器

2020-08-13 12:31:15

嵌入式LINUX驅動學習之7中斷相關(四)定時器


說明:linux定時器是基於軟中斷實現的,不能進行休眠操作

一、標頭檔案、函數及說明

//原始碼位置:include/linux/timer.h
struct timer_list {
    //.............省略更多,由內核維護或一般不用關心的結構體成員...................
    unsigned long expires; //給定時器設定的時間
    void (*function)(unsigned long);//倒計時完成後執行的函數 
    unsigned long data; //向function函數傳遞的參數
    //.............省略更多,由內核維護或一般不用關心的結構體成員...................
};
/*初始化定時器*/
#ifdef CONFIG_LOCKDEP
#define init_timer(timer)                                               \
        do {                                                            \
                static struct lock_class_key __key;                     \
                init_timer_key((timer), #timer, &__key);                \
        } while (0)

else
#define init_timer(timer)\
        init_timer_key((timer), NULL, NULL)
#endif
/*向內核註冊定時器物件*/
void add_timer(struct timer_list *timer)/*向內核刪除一個定時器物件*/
int del_timer(struct timer_list * timer);
/*修改定時器物件的值,並重新計算*/
int mod_timer(struct timer_list *timer, unsigned long expires);

二、程式碼舉例

#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/gpio.h>
#include <cfg_type.h>
/*定義LED燈定義資訊*/
struct led_src {
    char *name;
    int   gpio;
};
struct led_src led_info[] = {
    {
        .name = "LED1",
        .gpio = PAD_GPIO_B + 26
    },
    {
        .name = "LED2",
        .gpio = PAD_GPIO_C + 11
    },
    {
        .name = "LED3",
        .gpio = PAD_GPIO_C + 7
    },
    {
        .name = "LED4",
        .gpio = PAD_GPIO_C + 12
    }
};

static unsigned long g_data = 0xff;//全域性data
static struct timer_list mytimer; // 定時器物件
/*定時器時間完成,執行的函數
  功能:實現4個LED燈每秒閃一次。
*/
static void mytimer_func (unsigned long data){
    int i = 0;
    unsigned long *num = (unsigned long *) data;
    for(; i < ARRAY_SIZE(led_info);i++){
        gpio_set_value(led_info[i].gpio,\
                       1-gpio_get_value(led_info[i].gpio));//設定燈的狀態爲:開/關
        /*列印燈的狀態資訊
        printk("%s state : %s   ",led_info[i].name,\
               gpio_get_value(led_info[i].gpio) ? "關" :\
                "開");
    }
    printk("%lu\n",*num);
    /*回圈計數,只起到測試作用*/
    *num -= 1;
    if(*num ==0)
        *num = 255;
    /*因這條函數會重置定時器,並且重新設定定時器時間,
    所以mytimer_func會一直執行,並且時間爲mod_timer()函數的expires參數*/
    mod_timer(&mytimer,jiffies + 1 * HZ);
}
static int mytimer_init(void){
    int i = 0;
    for(; i< ARRAY_SIZE(led_info);i ++){
        gpio_request(led_info[i].gpio, led_info[i].name); //爲LED燈申請GPIO資源
        gpio_direction_output(led_info[i].gpio,1); //設定GPIO爲輸出口,且爲高電平
    }
    init_timer(&mytimer); // 初始化定時器
    mytimer.expires  = jiffies + 2 * HZ;//jiffies表示系統的當前時間,2 * HZ 表示2秒。
    mytimer.function = mytimer_func;  //指明定時器時間完成後執行的函數
    mytimer.data    = (unsigned long *) &g_data; //向mytimer_func函數傳遞的參數
    add_timer(&mytimer); //向內核註冊定時器
    return 0;
}
/*rmmod  模組名     
  執行的函數
*/
static void mytimer_exit(void){
    int i = 0;
    for(; i < ARRAY_SIZE(led_info); i++){
        gpio_set_value(led_info[i].gpio,1);//設定LED燈爲高電平
        gpio_free(led_info[i].gpio);  //釋放LED燈對應的GPIO資源
    }
    /*刪除定時器物件
      因mytimer_func函數中有mod_timer函數,會一直重置定時器,
      並且重新設定定時器時間,所以模組解除安裝時,一定要將時間器
      物件從內核刪除
    */
    del_timer(&mytimer);
}
module_init(mytimer_init);
module_exit(mytimer_exit);
MODULE_LICENSE("GPL");