30、Firefly-rk3399定时器

文章目录

一、思想概述:

​ 定时器:顾名思义就是用来定时的,分为三个阶段:定时开始->定时中->定时结束。三个阶段依托于内核中的jiffies,它记录定时器计数个数,上电就开始计数依次递增,所以我们只需要知道一个定时器周期时间是多少HZ即可自由设置定时器。

二、函数介绍

1、定时器相关结构体
C 复制代码
struct timer_list {
	struct hlist_node	entry;
    /* 记录定时器超时时间 */
	unsigned long		expires;
    /* 记录定时器超时处理函数 */
	void			(*function)(unsigned long);
    /* 上面函数的参数 */
	unsigned long		data;
	u32			flags; // 未使用
	int			slack; // 未使用
};
2、定时器超时函数
C 复制代码
static void key_expire(unsigned long data)
{
    /* 用于超时完成后执行的函数及处理 */
}
3、初始化定时器
C 复制代码
void setup_timer(struct timer_list *timer, void (*function)(unsigned long), unsigned long data);
timer:struct timer_list*数据
fn:	   超时处理函数
data:  超时处理函数的参数。unsigned long type
4、添加定时器
C 复制代码
void add_timer(struct timer_list *timer)
//将timer_list放入内核链表,并开启内核定时
//定时器只会启动一次
5、修改定时器
c 复制代码
int mod_timer(struct timer_list *timer, unsigned long expires)
//再次启动定时器
6、注销定时器
C 复制代码
int del_timer(struct timer_list *timer)

三、代码中使用

C 复制代码
#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");

四、按键为什么要消抖

若不消抖会多次误触发。

相关推荐
一心只为学21 分钟前
Linux运维中常用的命令总结
linux·运维·服务器
m0_7482398335 分钟前
【MySQL】【已解决】Windows安装MySQL8.0时的报错解决方案
数据库·windows·mysql
网络安全(华哥)1 小时前
网络安全-kail linux 网络配置(基础篇)
linux·网络·web安全
嘻嘻嘻哈哈哈嘻嘻嘻1 小时前
CentOS: RPM安装、YUM安装、编译安装(详细解释+实例分析!!!)
linux·运维·centos
今晚努力早睡1 小时前
linux之自动挂载
linux·运维·服务器
爱吃土豆的程序员1 小时前
flowable mysql 表名大小写问题
linux·windows·mysql·flowable
2301_805962931 小时前
NRF24L01模块STM32通信-发送端
stm32·单片机·嵌入式硬件
Stark、2 小时前
【Linux】文件系统--文件存储/软硬链接/inode/dentry
linux·运维·服务器·c语言·后端
杰克崔2 小时前
linux上对于so库的调试——包含通过vs2019远程ssh调试so库
linux·运维·服务器
科技语者2 小时前
Linux常用的100种命令大集合
linux