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");

四、按键为什么要消抖

若不消抖会多次误触发。

相关推荐
legend_jz几秒前
【linux】手搓线程池
linux·运维·服务器·c++·笔记·学习·学习方法
Axelioc13 分钟前
conda、pip同时安装包引起混乱问题剖析
linux·python
EVERSPIN43 分钟前
蓝牙MCU单片机8k高回报率无线应用
单片机·嵌入式硬件
妙哉7361 小时前
零基础学安全--shell(8)脚本相互利用
linux·运维·服务器
Curtis09801 小时前
RHCE——SELinux
linux·运维·服务器
团子tuan1 小时前
Ubuntu20.04下安装Matlab2018
linux·matlab
maxiumII2 小时前
Diving into the STM32 HAL-----I²C笔记
c语言·笔记·stm32
lantiandianzi2 小时前
基于单片机的多功能儿童书桌设计
单片机·嵌入式硬件
sayang_shao2 小时前
STM32 使用ARM Compiler V6 编译裸机 LWIP协议栈报错的解决方法
arm开发·stm32·嵌入式硬件
daizikui2 小时前
内网穿透产品 frp ngrok FastTunnel
linux·运维·网络·nginx