<span style="font-family:'Microsoft YaHei';font-size:18px;">最近工作中涉及到在一定的时间之后对特定的动作进行处理。比如按键,按键需要在按下至少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_blink
OS_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) 40773 2011-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 3
typedef 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_RESET 0x89ABCDEF
#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));
}
void
ar7240_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
ar7240_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
ar7240_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
ar7240_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"); // 遵循的协议
</span>
定时器 LED 闪烁功能
最新推荐文章于 2024-04-08 18:05:05 发布