欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 建筑 > fmql之Linux内核定时器

fmql之Linux内核定时器

2025/2/23 20:21:55 来源:https://blog.csdn.net/qq_41656020/article/details/142617669  浏览:    关键词:fmql之Linux内核定时器

内容依然来自于正点原子。

Linux内核时间管理

内容包括:

  • 系统频率设置
  • 节拍率:高节拍率的优缺点
  • 全局变量jiffies
  • 绕回的概念(溢出)
  • API函数(处理绕回)

HZ为每秒的节拍数

Linux内核定时器

内容包括:

  • 内核定时器的使用:设置超时时间
  • 内核定时器特点:超时后会自动关闭
  • timer_list结构体表示内核定时器,expires成员变量为超时时间(单位为节拍数),function为定时处理函数
  • 初始化定时器的API函数
  • 内核定时器的使用流程代码

Linux内核短延时函数

代码

timer.c

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/cdev.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/kern_levels.h>
// #include <linux/semaphore.h>#define LED_COUNT 		1			// 设备个数
#define LED_NAME		"led"		// 设备名称/* ioctl函数命令定义 */
#define CMD_LED_CLOSE	(_IO(0xEF,0x1))		/* turn off led */
#define CMD_LED_OPEN	(_IO(0xEF,0x2))		/* turn on led */
#define CMD_SET_PERIOD	(_IO(0xEF,0x3))		/* set LED闪烁频率 */struct led_dev {dev_t	devid;				// 设备号struct	cdev	cdev;		// cdevstruct	class	*class;		// classstruct	device	*device;	// devieint		major;				// majorint		minor;				// minorstruct	device_node	*nd;	// device_nodeint		led_gpio;			// led_gpioint			period;				/* period (ms) */struct		timer_list	timer;	/* timer */spinlock_t	spinlock;			/* spinlock */
};static struct led_dev led;static int led_open(struct inode * inode, struct file *filp){return 0;
}static ssize_t led_read(struct file *filp, char __user *buf,size_t cnt, loff_t *offt){return 0;
}static ssize_t led_write(struct file *filp, char __user *buf,size_t cnt, loff_t *offt){return 0;
}static int led_release(struct inode * inode, struct file *filp){return 0;
}/* ioctl函数 */
static long led_unlocked_ioctl(struct file *filp, unsigned int cmd,unsigned long arg){unsigned long flags;spin_lock_irqsave(&led.spinlock, flags);		// 自旋锁上锁switch(cmd){	// 应用程序发来的命令case CMD_LED_CLOSE:del_timer_sync(&led.timer);gpio_set_value(led.led_gpio, 0);break;case CMD_LED_OPEN:del_timer_sync(&led.timer);gpio_set_value(led.led_gpio, 1);break;case CMD_SET_PERIOD:led.period = arg;mod_timer(&led.timer, jiffies + msecs_to_jiffies(arg));break;default:break;}spin_unlock_irqrestore(&led.spinlock, flags);	// 自旋锁解锁return 0;
}static struct file_operations led_fops = {		// 设备操作函数.owner		= THIS_MODULE,.open		= led_open,.release	= led_release,.read		= led_read,// .write		= led_write,.unlocked_ioctl	= led_unlocked_ioctl,		/* ioctl函数 */
};/*  定时器回调函数 */
static void led_timer_function(struct timer_list *unused){static bool on = 1;unsigned long flags;on = !on;		/* 取反,实现LED反转 */spin_lock_irqsave(&led.spinlock, flags);	// 上锁gpio_set_value(led.led_gpio, on);			// 设置led-gpio电平状态/* 重启timer */mod_timer(&led.timer, jiffies + msecs_to_jiffies(led.period));spin_unlock_irqrestore(&led.spinlock, flags);	// 解锁
}static int __init led_init(void){int ret = 0;int val;const char *str;spin_lock_init(&led.spinlock);				// 初始化自旋锁led.nd = of_find_node_by_path("/led3");		// 获取设备节点if(led.nd == NULL){printk(KERN_ERR "key: Failed to get led node\r\n");return -EINVAL;} ret = of_property_read_string(led.nd, "status", &str);		// 获取status属性if(!ret){if(strcmp(str, "okay"))return -EINVAL;}ret = of_property_read_string(led.nd, "compatible", &str);	// 获取compatible属性if(ret < 0){printk(KERN_ERR "led: Failed to get compatible property\r\n");return -EINVAL;}if(strcmp(str, "fmql,led")){		// 匹配compatible属性printk(KERN_ERR "led: compatible math failed\r\n");return -EINVAL;}printk(KERN_INFO "led: device matches succeed\r\n");led.led_gpio = of_get_named_gpio(led.nd, "led-gpio", 0);	// 获取led使用的gpio编号if(!gpio_is_valid(led.led_gpio)){printk(KERN_ERR "led: Failed to get led-gpio\r\n");return -EINVAL;}printk(KERN_INFO "led: led-gpio num = %d\r\n", led.led_gpio);ret = gpio_request(led.led_gpio, "LED GPIO");	// 向GPIO子系统申请使用GPIOif(ret){printk(KERN_ERR "led: Failed to request led-gpio\r\n");return ret;}ret = of_property_read_string(led.nd, "default-state", &str);	// 设置led初始状态if(!ret){if(!strcmp(str, "on"))val = 1;elseval = 0;} else val = 0;gpio_direction_output(led.led_gpio, val);/* 注册字符设备驱动 */if(led.major){		// 创建设备号led.devid = MKDEV(led.major, 0);ret = register_chrdev_region(led.devid, LED_COUNT, LED_NAME);if(ret)goto out1;} else {ret = alloc_chrdev_region(&led.devid, 0, LED_COUNT, LED_NAME);if(ret)goto out1;led.major = MAJOR(led.devid);led.minor = MINOR(led.devid);}printk(KERN_INFO "led: major = %d, minor = %d\r\n", led.major, led.minor);led.cdev.owner = THIS_MODULE;cdev_init(&led.cdev, &led_fops);	// 初始化cdevret = cdev_add(&led.cdev, led.devid, LED_COUNT);	// 添加cdevif(ret)goto out2;led.class = class_create(THIS_MODULE, LED_NAME);	// 创建类if(IS_ERR(led.class)){ret = PTR_ERR(led.class);goto out3;}led.device = device_create(led.class, NULL, led.devid, NULL, LED_NAME);	//创建设备if(IS_ERR(led.device)){ret = PTR_ERR(led.device);goto out4;}/* 初始化timer* 绑定function函数* 未设置周期:不会激活timer*/timer_setup(&led.timer, led_timer_function, 0);return 0;out4:class_destroy(led.class);
out3:cdev_del(&led.cdev);
out2:unregister_chrdev_region(led.devid, LED_COUNT);
out1:gpio_free(led.led_gpio);return ret;
}static void __exit led_exit(void){/* delete timer */del_timer_sync(&led.timer);// 注销: 设备,类,cdev,设备号// 释放GPIOdevice_destroy(led.class, led.devid);class_destroy(led.class);cdev_del(&led.cdev);unregister_chrdev_region(led.devid, LED_COUNT);gpio_free(led.led_gpio);
}module_init(led_init);
module_exit(led_exit);MODULE_AUTHOR("Skylar <Skylar@33.com>");
MODULE_DESCRIPTION("FMQL Timer");
MODULE_LICENSE("GPL");

timerAPP.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>/* ioctl命令 */
#define CMD_LED_CLOSE	(_IO(0xEF,0x1))
#define CMD_LED_OPEN	(_IO(0xEF,0x2))
#define CMD_SET_PERIOD	(_IO(0xEF,0x3))/** @description         : main主程序* @param - argc        : argv数组元素个数* @param - argv        : 具体参数* @return              : 0 成功;其他 失败*/
int main(int argc, char *argv[])
{int fd, ret;unsigned int cmd;unsigned int period;/* 传递两个参数 */if(argc != 2){printf("Usage:\n""\t.timerAPP /dev/key @ open LED device\n");return -1;}fd = open(argv[1], O_RDWR);if(fd < 0){printf("ERROR: %s file open failed\r\n", argv[1]);return -1;}/* 通过命令控制LED设备 */for(;;){printf("Input CMD:");scanf("%d", &cmd);switch(cmd){case 0:cmd = CMD_LED_CLOSE; break;case 1:cmd = CMD_LED_OPEN;break;case 2:cmd = CMD_SET_PERIOD;printf("Input Timer Period:");scanf("%d",&period);break;case 3:close(fd);return 0;default://cmd = CMD_LED_CLOSE;break;}ioctl(fd, cmd, period);}//close(fd);//return 0;
}

运行结果

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词