基于[海思Hi3516dv300]开发的内核定时器中断

功能1:通过内核定时器中断打印板子时间

驱动入口函数(Hi3516dv300_Timer_Init)

static int __init Hi3516dv300_Timer_Init(void)
{
	//这只是个测试代码,我就不创建设备节点了~~忽略

	//初始化动态定时器
	init_timer(&Hi3516dv300_timer);
	
	//配置动态定时器
	Hi3516dv300_timer.function 	= Hi3516dv300_timer_handler;//处理函数
	Hi3516dv300_timer.expires  	= jiffies + HZ;			//当前时间开始,HZ个jiffies后,会产生超时
	//HZ就是linux内核时钟的频率,HZ是linux系统中的一个常数,当配置内核的时候,
	//HZ的就设好了,如果重新修改HZ的值,重新配置、编译linux内核。
	//jiffies是一个全局的变量,记录了linux内核从启动到现在经过了多少内核时钟周期。1秒钟内,jiffies增加HZ次。
	/*举例说明:
	expires = jiffies + HZ;1秒触发处理函数)
	expires = jiffies + HZ/2;0.5秒触发处理函数)
	expires = jiffies + HZ/1000;1微秒触发处理函数)*/
	Hi3516dv300_timer.data		= NULL;					//传递参数
	
	//动态定时器加到内核
	add_timer(&Hi3516dv300_timer);
	
}

处理函数(Hi3516dv300_timer_handler)

void Hi3516dv300_timer_handler(unsigned long data)
{	
	do_gettimeofday(&(txc.time));
	//功能获取自1970以来的秒数
	rtc_time_to_tm(txc.time.tv_sec,&tm);
	/*功能: 获取当前的UTC时间 
	time:当前自1970以来的秒数
	tm : 转换成的可识别的年月日 时分秒 ,+1900 +1,+8(时区)
	头文件:#include <linux/rtc.h>*/ 
	printk("UTC time :%d-%d-%d %d:%d:%d /n",tm.tm_year+1900,tm.tm_mon, tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec); 
	
	//重新修改超时时间,进行周期性的超时
	mod_timer(&gec6818_timer,jiffies + HZ);
	
}

在这里插入图片描述

功能2:内核定时器中断统计电平持续时间

入口函数(Hi3516dv300_Timer_Init)

//入口函数
static int __init Hi3516dv300_Timer_Init(void)
{
	int ret = misc_register(&Infrare_Control_dev);
	//创建杂项设备
	if (ret)
	{
		printk(KERN_ERR "register misc dev for dooralarm fail!\n");
		goto err_clk;
	}
	gpio_num = 86;//gpio10_6 = 10*8+6

	ret= gpio_request(gpio_num,NULL);//注册gpio
	if(ret < 0)
	{
		printk("gpio_request: fail\n");
		goto gpio_request_fail;
	}

	if (gpio_direction_input(gpio_num)) {//设置gpio复用为输入函数
			printk("[%s %d]gpio_direction_input fail!\n",
							__func__, __LINE__);
			return -EIO;
	}
	
	//初始化动态定时器
	init_timer(&Hi3516dv300_timer);
	
	//配置动态定时器
	Hi3516dv300_timer.function 	= Hi3516dv300_timer_handler;//处理函数
	Hi3516dv300_timer.expires  	= jiffies + HZ/1000;	//当前时间开始,1ms后会触发处理函数
	Hi3516dv300_timer.data		= NULL;					//传递参数
	
	//动态定时器加到内核
	add_timer(&Hi3516dv300_timer);
	
	return 0;
gpio_request_fail:
	gpio_free(gpio_num);
err_clk:
    misc_deregister(&Infrare_Control_dev);
	return 0;
}

响应函数(Hi3516dv300_timer_handler)

void Hi3516dv300_timer_handler(unsigned long data)
{ 
	//重新修改超时时间,进行周期性的超时
	mod_timer(&Hi3516dv300_timer,jiffies + HZ/1000);
	//读出GPIO输入值
	level = gpio_get_value(gpio_num);
	//设置gpio函数就为gpio_set_value()
	if(!level){
		time_cnt++;
	}else{
		if(time_cnt!=0){
			printk("low_level time = %d ms\n",time_cnt);
		}
		time_cnt=0;
	}
}

在这里插入图片描述

特别提醒

  1. 关于精确的延时,建议还是使用高精确的定时器硬件去实现微秒级别延时,因为内核只能提供毫秒级别的定时器中断。
  2. udelay一般适用于一个比较小的delay,如果你填的数大于2000,系统会认为你这个是一个错误的delay函数,因此如果需要2ms以上的delay需要使用mdelay函数。
  3. mdelay() 会占用cpu资源,导致其他功能此时也无法使用cpu资源。msleep() 则不会占住cpu资源,其他模块此时也可以使用cpu资源。
  4. 例:检测一个高电平的持续时间:
________________|------------------|_______________
int data;
int timer_cnt = 0;
do{
    data = gpio_get_value(gpio);
}while(data == 0);

do{
    data = gpio_get_value(gpio);
    timer_cnt ++;
    udelay(1);
}while(data == 1);

得到timer_cnt,就是us的计时值。

中断开发代码研究中待更新

内核定时器代码下载链接

点这~~~

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

I&You

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值