[首页]
[文章]
[教程]
首页
Web开发
Windows开发
编程语言
数据库技术
移动平台
系统服务
微信
设计
布布扣
其他
数据分析
首页
>
系统服务
> 详细
Linux_arm驱动之按键模拟脉冲实现定时器的精确计时
时间:
2016-12-30 01:46:32
阅读:
480
评论:
0
收藏:
0
[点我收藏+]
http://wenku.baidu.com/link?url=-9_IHk-7BFRSAxPAeutaQ8Ifhs0Rs9Qg3yAG9LxsqYqRauQRBwjVJ_xnmQ6R-CKbwVDSVmbr4vDJcDyUpbj_Y2RD75J1iLjQonsHywjECRW
[cpp]
view plain
copy
/*****************************************************************
内核驱动部分button_ker.c
*****************************************************************/
/*
*应用内核定时器简单实现计时的功能
*但是内核定时器精确度最小就为50ms
*较4_button_timer完善功能:利用硬件的定时器计时
*精确度提高
*应用linux-2.6.32.2内核里arch/arm/plat_s3/timer.c
*实现对定时器的精确提高问题
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include <linux/sched.h>
//*****///
#include <linux/clk.h>
#include <plat/regs-timer.h>
#include <asm/io.h>
///****///
#include <linux/miscdevice.h>
#include <mach/regs-irq.h>
//#include <linux/platform_device.h>
//#include <linux/miscdevice.h>
//#include <mach/regs-gpio.h>
#include <linux/wait.h>
#define DEVICE_NAME "timer_test"
#define BUTTON_MAJOR 240
#define TIMER_IOCTL_SET_FREQ 1
#define TIMER_IOCTL_STOP 0
static
struct semaphore lock;
struct button_irq_desc{
int irq;
unsigned
long flags;
int num;
char *name;
};
//用来指定按键所有的外部中断引脚以及中断出发方式和名字
static
struct button_irq_desc button_irqs[] = {
{IRQ_EINT0,IRQF_TRIGGER_FALLING,1,
"KEY1"},
{IRQ_EINT1,IRQF_TRIGGER_FALLING,2,
"KEY2"},
{IRQ_EINT2,IRQF_TRIGGER_FALLING,3,
"KEY3"},
{IRQ_EINT4,IRQF_TRIGGER_FALLING,4,
"KEY4"},
};
static
volatile
char key_values[4]={
‘0‘,
‘0‘,
‘0‘,
‘0‘};
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static
volatile
int ev_press =0;
static
void timer_open(
void);
static
void timer_stop(
void);
static
inline
int timer_interrupt_pending(
void);
static unsigned
long get_timer_offset(
void);
///********************************////
static
volatile
bool value=
false;
static
volatile unsigned
long count = 0;
static
volatile unsigned
long freq_value = 500;
static
volatile unsigned
long tcnt_value = 50625;
//定时器中断函数
static irqreturn_t timer_interrupt_function(
int irq,
void *dev_id)
{
count++;
//printk("timer_interrupt occur!\n");
return IRQ_HANDLED;
}
//时间处理函数
static
void timer_second_manage(unsigned
long second_value)
{
static
volatile unsigned
long ss_value1 = 0;
static
volatile unsigned
long ms_value2 = 0;
static
volatile unsigned
long us_value3 = 0;
us_value3 =
//(second_value*10000/tcnt_value)*1000/freq_value/10;
(second_value*1000/freq_value)*10000/tcnt_value/10;
ms_value2 = (count%freq_value)*1000/freq_value + us_value3/1000;
ss_value1 = count/freq_value + ms_value2/1000;
printk(
"++++++++++++++++++++++++\n");
printk(
"used time:%lu n\n",count);
printk(
"the second_value :%lu n\n",second_value);
printk(
"used time:%lu.%03lu %03lu s\n",ss_value1,
ms_value2%1000,us_value3%1000);
printk(
"++++++++++++++++++++++++\n");
}
//外部中断函数
static irqreturn_t button_interrupt(
int irq,
void *dev_id){
unsigned
long second_value = 0;
int num= ((
struct button_irq_desc *)dev_id)->num;
switch(num){
case 2:
//17
value=
false;
timer_stop();
printk(
"key1 press\n");
break;
case 4:
//48
if(!value) {
value=
true; count=0;
timer_open();
}
else {
timer_stop();
second_value=get_timer_offset();
timer_second_manage(second_value);
value=
false;
}
printk(
"key2 press\n");
break;
case 3:
//18
value=
false;
timer_stop();
printk(
"key3 press\n");
break;
case 1:
//16
value=
false;
timer_stop();
printk(
"key4 press\n");
break;
default:
printk(
"num error,nothing to do!\n");
}
//ev_press=1;
//wake_up_interruptible(&button_waitq);
return IRQ_HANDLED;
}
//频率设置函数
//freq: pclk/50/16/65536~pclk/50/16
//if : pclk=50mhz freq is 1Hz~62500Hz
//human ear : 20Hz~20000Hz
//
static
void timer_set_freq(unsigned
long freq)
{
unsigned
long tcon;
unsigned
long tcnt;
unsigned
long tcfg0;
unsigned
long tcfg1;
struct clk *clk_p;
unsigned
long pclk;
tcon = __raw_readl(S3C2410_TCON);
tcfg0 = __raw_readl(S3C2410_TCFG0);
tcfg1 = __raw_readl(S3C2410_TCFG1);
tcfg0 &= ~(255<<0);
//tcfg0 |= (50-1);
tcfg0 |= 0;
tcfg1 &= ~(15<<0);
tcfg1 |= (0<<0);
__raw_writel(tcfg0,S3C2410_TCFG0);
__raw_writel(tcfg1,S3C2410_TCFG1);
clk_p = clk_get(NULL,
"pclk");
pclk = clk_get_rate(clk_p);
printk(
"the pclk is : %ld\n",pclk);
//tcnt = (pclk/50/16)/freq;
tcnt = (pclk/2)/freq;
tcnt_value = tcnt;
printk(
"the tcnt is %ld\n",tcnt);
__raw_writel(tcnt,S3C2410_TCNTB(0));
__raw_writel(0,S3C2410_TCMPB(0));
//tcon &= ~0x1f;
tcon &= ~0x1e;
tcon |=0xb;
__raw_writel(tcon,S3C2410_TCON);
tcon &= ~2;
__raw_writel(tcon,S3C2410_TCON);
}
static
void timer_open(
void)
{
unsigned
long tcon = 0;
//printk("***1>tcnto is :%u\n",__raw_readl(S3C2410_TCNTO(0)));
tcon = __raw_readl(S3C2410_TCON);
tcon |= 1;
__raw_writel(tcon,S3C2410_TCON);
//printk("***2>tcnto is :%u\n",__raw_readl(S3C2410_TCNTO(0)));
}
static
void timer_stop(
void)
{
unsigned
long tcon;
tcon = __raw_readl(S3C2410_TCON);
tcon &= ~1;
__raw_writel(tcon,S3C2410_TCON);
}
#define SRCPND_TIMER0 (1<<(IRQ_TIMER0 - IRQ_TIMER0))
//中断识别函数 查看在按键产生中断时,定时器是否也在中断中
static
inline
int timer_interrupt_pending(
void)
{
return __raw_readl(S3C2410_SRCPND) & SRCPND_TIMER0;
}
//计算中断寄存器中TCNTO0中的偏移量
static unsigned
long get_timer_offset (
void)
{
unsigned
long tdone;
unsigned
long tval;
tdone = (tcnt_value -__raw_readl(S3C2410_TCNTO(0)));
if(timer_interrupt_pending()) {
tval = __raw_readl(S3C2410_TCNTO(0));
tdone = tcnt_value - tval;
if(!tval)
tdone += tcnt_value;
}
return tdone;
}
static
struct irqaction timer_irq = {
.name =
"S3C2410 Timer Tick",
.flags = IRQF_DISABLED |IRQF_TIMER|IRQF_IRQPOLL,
.handler = timer_interrupt_function,
.dev_id = NULL
};
static
int button_open(
struct inode *inode,
struct file *file)
{
int i,err;
if(down_trylock(&lock)){
printk(
"down_trylock failed!\n");
return -EBUSY;
}
if(setup_irq(IRQ_TIMER0,&timer_irq)){
printk(
"setup_irq failed!\n");
return -EBUSY;
}
for(i=0;i<
sizeof(button_irqs)/
sizeof(button_irqs[0]);i++) {
err=request_irq(button_irqs[i].irq,button_interrupt,button_irqs[i].flags,
button_irqs[i].name,(
void*)&(button_irqs[i]));
if(err)
break;
}
if(err) {
for(--i;i>=0;i--)
free_irq(button_irqs[i].irq,(
void *)&button_irqs[i].num);
printk(
"request_irq error!\n");
return -1;
}
disable_irq(IRQ_EINT0);
disable_irq(IRQ_EINT1);
disable_irq(IRQ_EINT2);
disable_irq(IRQ_EINT4);
set_irq_type(IRQ_EINT0,IRQ_TYPE_LEVEL_LOW);
//key4
set_irq_type(IRQ_EINT1,IRQ_TYPE_EDGE_RISING);
//key1
set_irq_type(IRQ_EINT2,IRQ_TYPE_EDGE_FALLING);
//key3
//set_irq_type(IRQ_EINT4,IRQ_TYPE_EDGE_BOTH);//key2
set_irq_type(IRQ_EINT4,IRQ_TYPE_EDGE_FALLING);
//key2
enable_irq(IRQ_EINT0);
enable_irq(IRQ_EINT1);
enable_irq(IRQ_EINT2);
enable_irq(IRQ_EINT4);
return 0;
}
static
int button_close(
struct inode *inode,
struct file *file)
{
int i;
for(i=0;i<
sizeof(button_irqs)/
sizeof(button_irqs[0]);i++) {
free_irq(button_irqs[i].irq,(
void *)&button_irqs[i]);
}
remove_irq(IRQ_TIMER0,&timer_irq);
up(&lock);
return 0;
}
static
int button_read(
struct file *filp,
char __user *buff,
size_t count,loff_t *offp)
{
unsigned
long err;
if(filp->f_flags & O_NONBLOCK)
return -EAGAIN;
else {
wait_event_interruptible(button_waitq,ev_press);
}
ev_press=0;
err=copy_to_user(buff,(
const
void*)key_values,
min(
sizeof(key_values),count));
return err ? -EFAULT : min(
sizeof(key_values),count);
}
static
int timer_ioctl(
struct inode *inode,
struct file *file,
unsigned
int cmd,unsigned
long arg)
{
switch (cmd) {
case TIMER_IOCTL_SET_FREQ:
printk(
"timer_ioctl_set_freq\n");
if(arg==0)
return -EINVAL;
timer_set_freq(arg);
freq_value = arg;
break;
case TIMER_IOCTL_STOP:
printk(
"timer_ioctl_stop\n");
timer_stop();
break;
}
return 0;
}
static
struct file_operations button_fops = {
.owner = THIS_MODULE,
.open = button_open,
.read = button_read,
.release = button_close,
.ioctl = timer_ioctl,
};
static
struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &button_fops,
};
//初始化函数
static
int __init button_init(
void)
{
init_MUTEX(&lock);
/*
if(register_chrdev(BUTTON_MAJOR,DEVICE_NAME,&button_fops)<0) {
printk(DEVICE_NAME"can‘t register major number!\n");
return -1;
}
printk(DEVICE_NAME"register sucess!\n");
*/
if(misc_register(&misc)<0) {
printk(DEVICE_NAME
"can‘t register major number!\n");
return -1;
}
printk(DEVICE_NAME
"register sucess!\n");
return 0;
}
static
void __exit button_exit(
void)
{
timer_stop();
//unregister_chrdev(BUTTON_MAJOR,DEVICE_NAME);
misc_deregister(&misc);
}
module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE(
"GPL");
[cpp]
view plain
copy
/**********************************************************************
应用程序部分button_app.c
**********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define msleep(x) usleep(x*1000);
#define TIMER_IOCTL_SET_FREQ 1
#define TIMER_IOCTL_STOP 0
int main(
int argc,
char **argv)
{
int fd;
int ioarg=500;
int press_cnt[4]={0};
if((fd=open(
"/dev/timer_test",0))<0){
printf(
"Can‘t open /dev/timer_test~!");
return -1;
}
printf(
"sleep begin...\n");
ioctl(fd,TIMER_IOCTL_SET_FREQ,ioarg);
//msleep(70000);
while(1)
usleep(11111);
ioctl(fd,TIMER_IOCTL_STOP);
printf(
"sleep end...\n");
close(fd);
return 0;
}
[cpp]
view plain
copy
/***************************************************************
makefile部分
****************************************************************/
ifneq ($(KERNELRELEASE),)
obj-m := button_ker.o
else
KDIR :=/home/kernel/linux-2.6.32.2
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
arm-linux-gcc button_app.c -o button_app
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers modul*
Linux_arm驱动之按键模拟脉冲实现定时器的精确计时
原文:http://www.cnblogs.com/zym0805/p/6235353.html
踩
(
0
)
赞
(
0
)
举报
评论
一句话评论(
0
)
登录后才能评论!
分享档案
更多>
2021年09月23日 (328)
2021年09月24日 (313)
2021年09月17日 (191)
2021年09月15日 (369)
2021年09月16日 (411)
2021年09月13日 (439)
2021年09月11日 (398)
2021年09月12日 (393)
2021年09月10日 (160)
2021年09月08日 (222)
最新文章
更多>
2021/09/28 scripts
2022-05-27
vue自定义全局指令v-emoji限制input输入表情和特殊字符
2022-05-27
9.26学习总结
2022-05-27
vim操作
2022-05-27
深入理解计算机基础 第三章
2022-05-27
C++ string 作为形参与引用传递(转)
2022-05-27
python 加解密
2022-05-27
JavaScript-对象数组里根据id获取name,对象可能有children属性
2022-05-27
SQL语句——保持现有内容在后面增加内容
2022-05-27
virsh命令文档
2022-05-27
教程昨日排行
更多>
1.
list.reverse()
2.
Django Admin 管理工具
3.
AppML 案例模型
4.
HTML 标签列表(功能排序)
5.
HTML 颜色名
6.
HTML 语言代码
7.
jQuery 事件
8.
jEasyUI 创建分割按钮
9.
jEasyUI 创建复杂布局
10.
jEasyUI 创建简单窗口
友情链接
汇智网
PHP教程
插件网
关于我们
-
联系我们
-
留言反馈
- 联系我们:wmxa8@hotmail.com
© 2014
bubuko.com
版权所有
打开技术之扣,分享程序人生!