30、Firefly-rk3399定时器
一、思想概述:
定时器:顾名思义就是用来定时的,分为三个阶段:定时开始->定时中->定时结束。三个阶段依托于内核中的jiffies,它记录定时器计数个数,上电就开始计数依次递增,所以我们只需要知道一个定时器周期时间是多少HZ即可自由设置定时器。
二、函数介绍
1、定时器相关结构体
struct timer_list {
struct hlist_nodeentry;
/* 记录定时器超时时间 */
unsigned longexpires;
/* 记录定时器超时处理函数 */
void(*function)(unsigned long);
/* 上面函数的参数 */
unsigned longdata;
u32flags; // 未使用
intslack; // 未使用
};
2、定时器超时函数
static void key_expire(unsigned long data)
{
/* 用于超时完成后执行的函数及处理 */
}
3、初始化定时器
void setup_timer(struct timer_list *timer, void (*function)(unsigned long), unsigned long data);
timer:struct timer_list*数据
fn: 超时处理函数
data: 超时处理函数的参数。unsigned long type
4、添加定时器
void add_timer(struct timer_list *timer)
//将timer_list放入内核链表,并开启内核定时
//定时器只会启动一次
5、修改定时器
int mod_timer(struct timer_list *timer, unsigned long expires)
//再次启动定时器
6、注销定时器
int del_timer(struct timer_list *timer)
三、代码中使用
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/poll.h>
/* 头文件 */
#include <linux/timer.h>
struct gpio_key {
int gpio;
int irq;
enum of_gpio_flags flags;
/* 两个GPIO各自的定时器 */
struct timer_list key_timer;
};
static int major = 0;
static struct class *led_class;
static unsigned int key_signal = 0;
static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);
struct gpio_key *gpios_key;
static struct fasync_struct *key_async;
static int key_open(struct inode *inode, struct file *file) {
printk("%s %s %d led device open\r\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
static ssize_t key_read(struct file *file, char __user *buf, size_t cnt, loff_t *offt) {
int err;
printk("%s %s %d led device read\r\n", __FILE__, __FUNCTION__, __LINE__);
wait_event_interruptible(gpio_key_wait, key_signal);
printk("led read : key statu is %d\r\n", key_signal);
err = copy_to_user(buf, &key_signal, 4);
key_signal = 0;
return 0;
}
static ssize_t key_write(struct file *file, const char __user *buf, size_t cnt, loff_t *offt) {
printk("%s %s %d led device write\r\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
static int key_release(struct inode *inode, struct file *file) {
printk("%s %s %d led device release\r\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
static unsigned int key_poll(struct file *file, struct poll_table_struct *wait) {
poll_wait(file, &gpio_key_wait, wait);
printk("key_poll enter key_signal is %d\r\n", key_signal);
return key_signal ? POLLIN | POLLRDNORM : 0;
}
static int key_fasync(int fd, struct file *file, int on)
{
return fasync_helper(fd, file, on, &key_async);
}
const struct file_operations key_fops = {
.owner = THIS_MODULE,
.open = key_open,
.release = key_release,
.read = key_read,
.write = key_write,
.poll = key_poll,
.fasync = key_fasync,
};
/* 中断处理函数 */
static irqreturn_t gpio_key_rk3399(int irq, void *dev_id)
{
struct gpio_key *gpios_key1 = dev_id;
printk("gpio_key_rk3399 : key %d val %d\r\n", irq, gpio_get_value(gpios_key1->gpio));
/* 修改定时时间重启定时器 */
mod_timer(&gpios_key1->key_timer, jiffies + HZ/5);
return IRQ_HANDLED;
}
/* 定时器处理函数 */
static void key_expire(unsigned long data)
{
struct gpio_key *gpios_key1 = (struct gpio_key *)data;
key_signal = ((gpio_get_value(gpios_key1->gpio)) << 8) |(gpios_key1->gpio);
printk("key_expire :val %d\r\n", gpio_get_value(gpios_key1->gpio));
wake_up_interruptible(&gpio_key_wait);
kill_fasync(&key_async, SIGIO, POLL_IN);
}
static int rk3399_key_probe(struct platform_device *pdev) {
int count = 0;
int i = 0;
int err = 0;
printk("enter interrupt\r\n");
count = of_gpio_count(pdev->dev.of_node);
printk("count is %d\r\n", count);
gpios_key = kzalloc(count * sizeof(struct gpio_key), GFP_KERNEL);
for(i=0; i<count; i++) {
gpios_key[i].gpio = of_get_gpio_flags(pdev->dev.of_node, i, &(gpios_key[i].flags));
gpios_key[i].irq = gpio_to_irq(gpios_key[i].gpio);;
/* 初始化定时器 */
setup_timer(&gpios_key[i].key_timer, key_expire, (unsigned long)&gpios_key[i]);
/* 防止五执行定时器函数,设置超时时间为当前位数最大值 */
gpios_key[i].key_timer.expires = ~0;
/* 添加定时器开始定时 */
add_timer(&gpios_key[i].key_timer);
err = request_irq(gpios_key[i].irq, gpio_key_rk3399, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "rk3399_key", &gpios_key[i]);
}
major = register_chrdev(0, "KEY_L", &key_fops);
led_class = class_create(THIS_MODULE, "KEY_CLASS");
device_create(led_class, NULL, MKDEV(major, 0), NULL, "diy_key_double");
return err;
}
static int rk3399_key_remove(struct platform_device *pdev) {
int count = 0;
int i = 0;
count = of_gpio_count(pdev->dev.of_node);
for(i=0; i<count; i++) {
free_irq(gpios_key[i].irq, &gpios_key[i]);
/* 注销定时器 */
del_timer(&gpios_key[i].key_timer);
}
device_destroy(led_class, MKDEV(major, 0));
class_destroy(led_class);
unregister_chrdev(major, "KEY_L");
return 0;
}
static const struct of_device_id firefly_rk3399_key[] = {
{ .compatible = "rk3399, keydrv" },
{},
};
struct platform_driver key_interrupt_drv = {
.probe = rk3399_key_probe,
.remove = rk3399_key_remove,
.driver = {
.name = "rk3399",
.of_match_table = firefly_rk3399_key,
},
};
static int gpio_interrupt_init(void) {
return platform_driver_register(&key_interrupt_drv);
}
static void gpio_interrupt_exit(void) {
platform_driver_unregister(&key_interrupt_drv);
}
module_init(gpio_interrupt_init);
module_exit(gpio_interrupt_exit);
MODULE_LICENSE("GPL");
四、按键为什么要消抖
若不消抖会多次误触发。
原文地址:https://blog.csdn.net/lyyaj/article/details/144011239
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!