最近工作中涉及到在一定的时间之后对特定的动作进行处理。比如按键,按键需要在按下至少4S之后,重新启动系统之类、此时使用定时器,可以确保准确的计时。下面的实现可以通用。struct timer_list os_timer_t; //定义定时器#define OS_TIMER_FUNC(_fn)\void _fn(unsigned long timer_arg)#define OS_GET_TIMER_ARG(_arg, _type)\(_arg) = (_type)(timer_arg)#define OS_INIT_TIMER(_osdev, _timer, _fn, _arg)\do {\init_timer(_timer);\(_timer)->function = (_fn);\(_timer)->data = (unsigned long)(_arg);\} while (0)#define OS_SET_TIMER(_timer, _ms)\mod_timer(_timer, jiffies + ((_ms)*HZ)/1000)#define OS_CANCEL_TIMER(_timer)del_timer(_timer)1:初始化定时器//初始化,其处理函数为:wps_led_blinkOS_INIT_TIMER(NULL, &os_timer_t, wps_led_blink, &os_timer_t); 2:启动定时器/设置定时器OS_SET_TIMER(&os_timer_t, 1000);//设置表示,在1000ms之后启动定时器。3:取消定时器: OS_CANCEL_TIMER(&os_timer_t);4:定时器的处理函数定义如下:static OS_TIMER_FUNC(wps_led_blink){ static int WPSled = WPS_LED_ON,sec = 0; ar7242_gpio_out_val(WPS_LED_GPIO,WPSled); WPSled=!WPSled; OS_SET_TIMER(&os_timer_t, 1000); /* sec++ ; if(sec < 130) {OS_SET_TIMER(&os_timer_t, 1000); } else {sec = 0;wps_led_blinking = 0 ;OS_CANCEL_TIMER(&os_timer_t);ar7242_gpio_out_val (WPS_LED_GPIO, WPS_LED_OFF); }*/}上面的处理函数可知:每隔1000ms即1S对WPS_LED_GPIO输出高低电平。使其周期性的闪烁。完整的测试代码如下:#include <linux/kernel.h>#include <linux/module.h>#include <linux/signal.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <linux/init.h>#include <linux/resource.h>#include <linux/proc_fs.h>#include <linux/miscdevice.h>#include <asm/types.h>#include <asm/irq.h>#include <asm/delay.h>#include <asm/system.h>//Ar7240.h (e:\sdk_wlan_db12x\sdk\wlan-ap\linux\kernels\mips-linux-2.6.31\arch\mips\include\asm\mach-ar7240)407732011-12-1#include <asm/mach-ar7240/ar7240.h>#include <asm/mach-atheros/724x.h>#define WPS_LED_GPIO 0#define WPS_LED_OFF 1#define WPS_LED_ON 0#define SIMPLE_CONFIG_OFF 1#define SIMPLE_CONFIG_ON 2 #define SIMPLE_CONFIG_BLINK 3typedef enum { LED_STATE_OFF = 1, LED_STATE_ON = 2, LED_STATE_BLINKING = 3,} led_state_e;#define OS_TIMER_FUNC(_fn) \ void _fn(unsigned long timer_arg)#define OS_GET_TIMER_ARG(_arg, _type) \ (_arg) = (_type)(timer_arg)#define OS_INIT_TIMER(_osdev, _timer, _fn, _arg) \do { \ init_timer(_timer); \ (_timer)->function = (_fn); \ (_timer)->data = (unsigned long)(_arg); \} while (0)#define OS_SET_TIMER(_timer, _ms) mod_timer(_timer, jiffies + ((_ms)*HZ)/1000)#define OS_CANCEL_TIMER(_timer) del_timer(_timer)static struct proc_dir_entry *simple_config_entry = NULL;static struct proc_dir_entry *simple_config_led_entry = NULL;static int wps_led_blinking = 0;struct timer_list os_timer_t;static led_state_e simple_config_led_state = LED_STATE_BLINKING;void ar7242_gpio_config_output(int gpio){#ifdef CONFIG_WASP_SUPPORT ar7240_reg_rmw_clear(AR7240_GPIO_OE, (1 << gpio));#else ar7240_reg_rmw_set(AR7240_GPIO_OE, (1 << gpio));#endif}void ar7242_gpio_config_input(int gpio){#ifdef CONFIG_WASP_SUPPORT ar7240_reg_rmw_set(AR7240_GPIO_OE, (1 << gpio));#else ar7240_reg_rmw_clear(AR7240_GPIO_OE, (1 << gpio));#endif}void ar7242_gpio_out_val(int gpio, int val){ if (val & 0x1) { ar7240_reg_rmw_set(AR7240_GPIO_OUT, (1 << gpio)); } else { ar7240_reg_rmw_clear(AR7240_GPIO_OUT, (1 << gpio)); }}int ar7242_gpio_in_val(int gpio){ return((1 << gpio) & (ar7240_reg_rd(AR7240_GPIO_IN)));}static OS_TIMER_FUNC(wps_led_blink){ static int WPSled = WPS_LED_ON,sec = 0; ar7242_gpio_out_val(WPS_LED_GPIO,WPSled); WPSled=!WPSled; OS_SET_TIMER(&os_timer_t, 1000); /* sec++ ; if(sec < 130) {OS_SET_TIMER(&os_timer_t, 1000); } else {sec = 0;wps_led_blinking = 0 ;OS_CANCEL_TIMER(&os_timer_t);ar7242_gpio_out_val (WPS_LED_GPIO, WPS_LED_OFF); }*/}static int gpio_simple_config_led_read (char *page, char **start, off_t off, int count, int *eof, void *data){ return sprintf (page, "%d\n", simple_config_led_state);}static int gpio_simple_config_led_write (struct file *file, const char *buf,unsigned long count, void *data){u_int32_t val = 0; if(sscanf(buf, "%d", &val) != 1){return -EINVAL;}if ((val == SIMPLE_CONFIG_BLINK) && !wps_led_blinking) /* wps LED blinking */{wps_led_blinking = 1 ;simple_config_led_state = SIMPLE_CONFIG_BLINK ;ar7242_gpio_out_val (WPS_LED_GPIO, WPS_LED_ON);//OS_INIT_TIMER(NULL, &os_timer_t, wps_led_blink, &os_timer_t);OS_SET_TIMER(&os_timer_t, 1000);}else if (val == SIMPLE_CONFIG_ON) /* WPS Success */{wps_led_blinking = 0 ;simple_config_led_state = SIMPLE_CONFIG_ON ;OS_CANCEL_TIMER(&os_timer_t);ar7242_gpio_out_val (WPS_LED_GPIO, WPS_LED_ON);}else if (val == SIMPLE_CONFIG_OFF) /* WPS failed */{wps_led_blinking = 0 ;simple_config_led_state = SIMPLE_CONFIG_OFF ;OS_CANCEL_TIMER(&os_timer_t);ar7242_gpio_out_val (WPS_LED_GPIO, WPS_LED_OFF);} return count;}static int create_simple_config_led_proc_entry (void){ if (simple_config_entry != NULL) { printk ("Already have a proc entry for /proc/simple_config!\n"); return -ENOENT; } simple_config_entry = proc_mkdir("simple_config", NULL); if (!simple_config_entry) return -ENOENT; simple_config_led_entry = create_proc_entry ("simple_config_led", 0644, simple_config_entry); if (!simple_config_led_entry) return -ENOENT; simple_config_led_entry->write_proc = gpio_simple_config_led_write; simple_config_led_entry->read_proc = gpio_simple_config_led_read; /* configure gpio as outputs */ ar7242_gpio_config_output (WPS_LED_GPIO); /* switch off the led */ ar7242_gpio_out_val(WPS_LED_GPIO, WPS_LED_OFF); OS_INIT_TIMER(NULL, &os_timer_t, wps_led_blink, &os_timer_t);OS_SET_TIMER(&os_timer_t, 1000);//此处启动定时器。 return 0;}//ar7240_reg_rd(AR7240_GPIO_IN_ETH_SWITCH_LED)=480fa //ar7240_reg_rd(AR7240_GPIO_IN_ETH_SWITCH_LED)=4800a static int __init init_ar7242_gpio_module(void){unsigned int rddata; rddata = ar7240_reg_rd(AR7240_GPIO_IN_ETH_SWITCH_LED); printk("first:reg 0x18040028=%x\n",rddata); rddata = rddata & (~(0xf0)); ar7240_reg_wr(AR7240_GPIO_IN_ETH_SWITCH_LED, rddata); rddata = ar7240_reg_rd(AR7240_GPIO_IN_ETH_SWITCH_LED); printk("second:reg 0x18040028=%x\n",rddata); create_simple_config_led_proc_entry();printk("*** init_ar7242_gpio_module success *** \n");return 0;}static void __exit cleanup_ar7242_gpio_module(void){ printk("%s (%s) line: %d\n", __FILE__, __func__,__LINE__);}module_init(init_ar7242_gpio_module);module_exit(cleanup_ar7242_gpio_module);MODULE_LICENSE("GPL");MODULE_AUTHOR("suiyuan from test"); MODULE_DESCRIPTION("Led driver for Atheros 7242 platform");--------------------------测试代码二----------------------------------------#include <linux/kernel.h>#include <linux/module.h>#include <linux/signal.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <linux/init.h>#include <linux/resource.h>#include <linux/proc_fs.h>#include <linux/miscdevice.h>\#include <linux/delay.h>#include <linux/types.h>#include <asm/types.h>#include <asm/irq.h>#include <asm/delay.h>#include <asm/system.h>#include <asm/mach-atheros/724x.h>#include <asm/mach-ar7240/ar7240.h>#define ATH_FACTORY_RESET0x89ABCDEF#define BUTTON_GPIO 11#define UDELAY_COUNT 8000000#define BUTTON_MINOR 189//#define ATH_WDT_TEST_CODE#ifdef ATH_WDT_TEST_CODE#define btdbg printk#else#define btdbg(junk, ...)#endif /* ATH_WDT_TEST_CODE 8 */typedef enum { INT_TYPE_EDGE, INT_TYPE_LEVEL,}ar7240_gpio_int_type_t;typedef enum { INT_POL_ACTIVE_LOW, INT_POL_ACTIVE_HIGH,}ar7240_gpio_int_pol_t;typedef struct {wait_queue_head_t buttons_waitqueue; /* 等待队列,当没有按键被按下时,如果有进程调用s3c24xx_buttons_read函数,它将休眠 */volatile int ev_press; /* 中断事件标志, 中断服务程序将它置1,s3c24xx_buttons_read将它清0 */volatile unsigned int press_cnt; /* 4个按键被按下的次数(准确地说,是发生中断的次数) */struct timer_list button_timers; /* buttons delay timer */int ar7242_ButtonOpened;int button_short_time;int is_interrupt_finished;} buttons_dev_t;/*extern void ar7240_gpio_config_int(int gpio, ar7240_gpio_int_type_t type,ar7240_gpio_int_pol_t polarity);extern void ar7240_gpio_config_output(int gpio);extern void ar7240_gpio_config_input(int gpio);extern void ar7240_gpio_out_val(int gpio, int val);extern int ar7240_gpio_in_val(int gpio);*/void ar7240_gpio_config_int(int gpio, ar7240_gpio_int_type_t type,ar7240_gpio_int_pol_t polarity){ u32 val; /* * allow edge sensitive/rising edge too */ if (type == INT_TYPE_LEVEL) { /* level sensitive */ ar7240_reg_rmw_set(AR7240_GPIO_INT_TYPE, (1 << gpio)); } else { /* edge triggered */ val = ar7240_reg_rd(AR7240_GPIO_INT_TYPE); val &= ~(1 << gpio); ar7240_reg_wr(AR7240_GPIO_INT_TYPE, val); } if (polarity == INT_POL_ACTIVE_HIGH) { ar7240_reg_rmw_set (AR7240_GPIO_INT_POLARITY, (1 << gpio)); } else { val = ar7240_reg_rd(AR7240_GPIO_INT_POLARITY); val &= ~(1 << gpio); ar7240_reg_wr(AR7240_GPIO_INT_POLARITY, val); } ar7240_reg_rmw_set(AR7240_GPIO_INT_ENABLE, (1 << gpio));}voidar7240_gpio_config_output(int gpio){#ifdef CONFIG_WASP_SUPPORT ar7240_reg_rmw_clear(AR7240_GPIO_OE, (1 << gpio));#else ar7240_reg_rmw_set(AR7240_GPIO_OE, (1 << gpio));#endif}voidar7240_gpio_config_input(int gpio){#ifdef CONFIG_WASP_SUPPORT ar7240_reg_rmw_set(AR7240_GPIO_OE, (1 << gpio));#else ar7240_reg_rmw_clear(AR7240_GPIO_OE, (1 << gpio));#endif}voidar7240_gpio_out_val(int gpio, int val){ if (val & 0x1) { ar7240_reg_rmw_set(AR7240_GPIO_OUT, (1 << gpio)); } else { ar7240_reg_rmw_clear(AR7240_GPIO_OUT, (1 << gpio)); }}intar7240_gpio_in_val(int gpio){ return((1 << gpio) & (ar7240_reg_rd(AR7240_GPIO_IN)));}static buttons_dev_t buttons_dev ={.ev_press = 0,.press_cnt = 0,.button_short_time =0, .is_interrupt_finished=1,};struct timer_list os_timer_t;#define OS_TIMER_FUNC(_fn)\void _fn(unsigned long timer_arg)#define OS_GET_TIMER_ARG(_arg, _type)\(_arg) = (_type)(timer_arg)#define OS_INIT_TIMER(_osdev, _timer, _fn, _arg)\do {\init_timer(_timer);\(_timer)->function = (_fn);\(_timer)->data = (unsigned long)(_arg);\} while (0)#define OS_SET_TIMER(_timer, _ms)\mod_timer(_timer, jiffies + ((_ms)*HZ)/1000)#define OS_CANCEL_TIMER(_timer)del_timer(_timer)static OS_TIMER_FUNC(wps_led_blink){static int sec = 0;sec++;if(sec < 40) {//printk("sec:%d\n",sec);{if(ar7240_gpio_in_val(BUTTON_GPIO)==0) {OS_SET_TIMER(&os_timer_t, 100); //printk("01_ar7240_gpio_in_val(BUTTON_GPIO):%d\n",ar7240_gpio_in_val(BUTTON_GPIO));}else{buttons_dev.button_short_time=0;OS_CANCEL_TIMER(&os_timer_t);buttons_dev.is_interrupt_finished =1;printk("按键时间少于4秒,您按键已:%d 秒\n",(sec/10));sec =0;enable_irq(AR7240_GPIO_IRQn(BUTTON_GPIO));//printk("02_ar7240_gpio_in_val(BUTTON_GPIO):%d\n",ar7240_gpio_in_val(BUTTON_GPIO));}}} else{OS_SET_TIMER(&os_timer_t, 100);if(ar7240_gpio_in_val(BUTTON_GPIO)){printk("按键时间大于4秒,您按键已:%d 秒,系统设置将复位。\n",(sec/10));OS_CANCEL_TIMER(&os_timer_t);sec =0;buttons_dev.button_short_time=1; buttons_dev.is_interrupt_finished=1;enable_irq(AR7240_GPIO_IRQn(BUTTON_GPIO));}}if(buttons_dev.button_short_time==1){buttons_dev.press_cnt = 1; /* 按键计数加1 */buttons_dev.ev_press = 1; buttons_dev.button_short_time = 0;sec =0;printk("buttons_dev.press_cnt:%d\n",buttons_dev.press_cnt);//wake_up_interruptible(&(buttons_dev.buttons_waitqueue)); /* 唤醒休眠的进程 */}}//中断响应函数,到这里表明已经发生了中断,进入了中断处理函数。static irqreturn_t ar7242buttons_interrupt(int irq, void *dev_id){disable_irq(AR7240_GPIO_IRQn(BUTTON_GPIO));//此处关闭中断,之后,系统不会再次响应中断。OS_SET_TIMER(&os_timer_t, 0);//printk("您请求按键中断一次,系统为您做出按键响应,请等待.................\n");return IRQ_HANDLED;}static int ar7242Button_open(struct inode *inode, struct file *file){int ret =0;if (MINOR(inode->i_rdev) != BUTTON_MINOR) {return -ENODEV;}if (buttons_dev.ar7242_ButtonOpened) {return -EBUSY;}buttons_dev.ar7242_ButtonOpened = 1;ret = request_irq(AR7240_GPIO_IRQn(BUTTON_GPIO), ar7242buttons_interrupt, 0,"ar7242 button", NULL);if (ret != 0) {printk("request_irq for button (error %d)\n", ret);}return ret;}static int ar7242Button_close(struct inode *inode, struct file *file){if (MINOR(inode->i_rdev) != BUTTON_MINOR) {return -ENODEV;}buttons_dev.ar7242_ButtonOpened = 0;free_irq(ATH_GPIO_IRQn(BUTTON_GPIO), NULL);return 0;}static ssize_t ar7242Button_read(struct file *file, char *buff, size_t count, loff_t * ppos){unsigned long err;int retval = 0;/* 如果ev_press等于0,休眠 *///应用程序需要读取按键的状态,故将这句屏蔽,不然应用程序会阻塞到这里。//即读不到数据的时候直接返回(-EFAULT)//wait_event_interruptible(buttons_dev.buttons_waitqueue, (buttons_dev.ev_press != 0));/* 执行到这里时,ev_press等于1,将它清0 */buttons_dev.ev_press = 0;/* 将按键状态复制给用户,并清0 */err = copy_to_user(buff,(const void *)&buttons_dev.press_cnt,sizeof(buttons_dev.press_cnt)); if ((err < 0)) {//printk("\ncopy_to_user error ret: %d\n",err);retval = -EFAULT;}else{retval = sizeof(buttons_dev.press_cnt);} // buttons_dev.press_cnt =0; //当应用程序读到按键的次数>1后,表示按键已经按下。可以根据此值,做出下一步的判断。//printk("\nretval:%d buttons_dev.press_cnt: %d: buttons_dev.ev_press:%d\n",retval,buttons_dev.press_cnt ,buttons_dev.ev_press);return retval;}static ssize_t ar7242Button_write(struct file *file, const char *buf, size_t count, loff_t * ppos){unsigned int cnt =0;int ret ;int __user *ptr = (int __user *)buf;ret = get_user(cnt, ptr);if(ret){ret= -EFAULT;}else{ret = count;}buttons_dev.press_cnt = 0;//printk("\rret: %d buttons_dev.press_cnt: %d: cnt:%d count;%d\n",ret,buttons_dev.press_cnt ,cnt,count);return ret;}static int ar7242Button_ioctl(struct inode *inode, struct file *file, unsigned int cmd,unsigned long arg){int ret = 0;return ret;}static struct file_operations ar7242Button_fops = {read: ar7242Button_read,write:ar7242Button_write,ioctl:ar7242Button_ioctl,open:ar7242Button_open,release:ar7242Button_close};static struct miscdevice athfr_miscdev = {BUTTON_MINOR,"ar7242_button",&ar7242Button_fops};static int __init ar7242_button_init(void){int ret;ret = misc_register(&athfr_miscdev);if (ret < 0) {printk("*** insmod ar7242_button.ko failed %d *** \n", ret);return -1;}OS_INIT_TIMER(NULL, &os_timer_t, wps_led_blink, &os_timer_t);init_waitqueue_head(&(buttons_dev.buttons_waitqueue));ar7240_gpio_config_input(BUTTON_GPIO);ar7240_gpio_config_int(BUTTON_GPIO, INT_TYPE_LEVEL,INT_POL_ACTIVE_LOW); printk("*** insmod ar7242_button.ko success *** \n");return ret;}static void __exit ar7242_buttons_exit(void){ misc_deregister(&athfr_miscdev);// ath_gpio_intr_shutdown(ATH_GPIO_IRQn(BUTTON_GPIO)); printk("%s (%s) line: %d\n", __FILE__, __func__,__LINE__);}module_init(ar7242_button_init);module_exit(ar7242_buttons_exit);MODULE_AUTHOR("cctv from test"); // 驱动程序的作者MODULE_DESCRIPTION("button driver for Atheros 7242 platform"); // 一些描述信息MODULE_LICENSE("GPL"); // 遵循的协议