Chinaunix首页 | 论坛 | 博客
  • 博客访问: 498763
  • 博文数量: 223
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2145
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-01 10:23
个人简介

该坚持的时候坚持,该妥协的时候妥协,该放弃的时候放弃

文章分类

全部博文(223)

文章存档

2017年(56)

2016年(118)

2015年(3)

2014年(46)

我的朋友

分类: 嵌入式

2016-11-09 20:56:15

一、中断分层
1.中断嵌套
是指中断系统正在执行一个中断服务时,有另一个优先级更高的中断提出中断请求,这时会暂时终止当前正在执行的级别较低的中断源的服务程序,去处理级别更高的中断源,待处理完毕,再返回到被中断了的中断服务程序继续执行,这个过程就是中断嵌套。

2.中断分层
慢速中断:中断处理时不关闭总的中断开关,中断发生时又有中断可能会被忽略(优先级不高)
快速中断:关闭总中断,中断发生时,不处理新的中断。
>>所以中断处理的过程必须越快越好。中断分层:
上半部:当中断发生时,它进行相应地硬件读写,并“登记”该中断。通常由中断处理程序充当上半部。
下半部:在系统空闲的时候对上半部“登记”的中断进行后续处理。

3.工作队列
工作队列是一种将任务推后执行的形式,他推后的任务交由一个内核线程去执行。这样下半部会在进程上下文执行,它允许重新调度甚至睡眠。 每个被推后的任务叫做“工作”,由这些工作组成的队列称为工作队列


Linux内核使用struct workqueue_struct 来描述一个工作队列:
struct workqueue_struct {
struct cpu_workqueue_struct *cpu_wq;
struct list_head list;
const char *name; /*workqueue name*/
int singlethread;
int freezeable; /* Freeze threads during suspend */
int rt;
};

Linux内核使用struct work_struct来描述一个工作项:
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
};
typedef void (*work_func_t)(struct work_struct *work);
step1. 创建工作队列
create_workqueue
step2. 创建工作
INIT_WORK
step3. 提交工作
queue_work

在大多数情况下, 驱动并不需要自己建立工作
队列,只需定义工作, 然后将工作提交到内核已
经定义好的工作队列keventd_wq中。
1. 提交工作到默认队列
schedule_work
  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/workqueue.h>

  4. struct workqueue_struct *my_wq;
  5. struct work_struct *work1;
  6. struct work_struct *work2;

  7. MODULE_LICENSE("GPL");

  8. void work1_func(struct work_struct *work)
  9. {
  10.     printk("this is work1->\n");
  11. }

  12. void work2_func(struct work_struct *work)
  13. {
  14.     printk("this is work2->\n");
  15. }

  16. int init_que(void)
  17. {
  18.     //1.创建工作队列
  19.     //my_wq = create_workqueue("my_wq");
  20.     
  21.     //2.创建工作
  22.     work1 = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
  23.     work2 = kmalloc(sizeof(struct work_struct), GFP_KERNEL);

  24.     INIT_WORK(work1, work1_func);
  25.     INIT_WORK(work2, work2_func);

  26.     //3.挂载(提交)工作
  27.     //queue_work(my_wq, work1);
  28.     //queue_work(my_wq, work2);
  29.     schedule_work(work1);
  30.     schedule_work(work2);

  31.     return 0;
  32. }

  33. void clean_que(void)
  34. {

  35. }

  36. module_init(init_que);
  37. module_exit(clean_que);


二、按键去抖
1.按键去抖
按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,开关不会马上稳定地接通或断开。因而在闭合及断开的瞬间总是伴随有一连串的抖动。

按键去抖动的方法主要有二种,一种是硬件电路去抖动;另一种就是软件延时去抖。而延时又一般分为二种,一种是for循环等待,另一种是定时器延时。在操作系统中,由于效率方面的原因,一般不允许使用for循环来等
待,只能使用定制器。

2.内核定时器
Linux内核使用struct timer_list来描述一个定时器:
struct timer_list {
struct list_head entry;
unsigned long expires;
void (*function)(unsigned long);
unsigned long data;
struct tvec_base *base;
};

3.定时器使用流程
1.定义定时器
2.初始化定时器
init_timer初始化
设置超时函数
3.add_timer注册定时器
4.mod_timer启动定时器
key.c:
  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/miscdevice.h>
  4. #include <linux/fs.h>
  5. #include <asm/uaccess.h>
  6. #include <linux/io.h>
  7. #include <linux/irqreturn.h>
  8. #include <linux/interrupt.h>

  9. #define GPFCON (volatile unsigned long*) 0x56000050
  10. #define GPFDAT (volatile unsigned long*) 0x56000054

  11. unsigned int *gpio_data;

  12. struct work_struct *work1;
  13. struct timer_list key_timer;

  14. void key_timer_func(unsigned long data)
  15. {
  16.     unsigned int key_val;
  17.     key_val = readw(gpio_data)&0x01;
  18.     if(key_val == 0)
  19.     {
  20.         printk("key down!\n");
  21.     }
  22. }

  23. void work1_func(struct work_struct *work)
  24. {
  25.     mod_timer(&key_timer, jiffies + HZ/10);
  26. }

  27. irqreturn_t key_int(int irq, void *dev_id)
  28. {
  29.     //1.检测是否发生了按键中断
  30.     
  31.     //2.清除已经发生的按键中断
  32.    
  33.     //3.提交下半部
  34.     schedule_work(work1);

  35.     return 0;
  36. }

  37. void key_hw_init()
  38. {
  39.     unsigned int *gpio_config;
  40.     unsigned short data;
  41.     
  42.     gpio_config = ioremap(GPFCON, 4);
  43.     gpio_data = ioremap(GPFDAT, 4);
  44.     data = readw(gpio_config);
  45.     data &= ~0b11;
  46.     data |= 0b10;
  47.     writew(data, gpio_config);
  48. }

  49. int key_open(struct inode *inode, struct file *filp)
  50. {
  51.     return 0;
  52. }

  53. struct file_operations key_fops = {
  54.     .open = key_open,
  55. };

  56. struct miscdevice key_miscdev = {
  57.     .minor = 200,
  58.     .name = "tq2400key",
  59.     .fops = &key_fops,
  60. };

  61. static int button_init()
  62. {
  63.     int ret;
  64.     ret = misc_register(&key_miscdev);
  65.     if(ret != 0)
  66.     {
  67.         printk(KERN_ERR"misc_register failed\n");
  68.     }
  69.     //按键初始化
  70.     key_hw_init();

  71.     //注册中断处理程序
  72.     ret = request_irq(IRQ_EINT0, &key_int, IRQF_TRIGGER_FALLING, "tq2440key", 0);
  73.     if(ret != 0)
  74.     {
  75.         printk(KERN_ERR"request_irq failed,ret is %d\n",ret);
  76.     }

  77.     //创建工作
  78.     work1 = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
  79.     INIT_WORK(work1, work1_func);

  80.     //初始化定时器
  81.     init_timer(&key_timer);
  82.     key_timer.function = key_timer_func;

  83.     //注册定时器
  84.     add_timer(&key_timer);

  85.     return 0;
  86. }

  87. static void button_exit()
  88. {
  89.     misc_deregister(&key_miscdev);
  90.     //注销中断处理函数
  91.     free_irq(IRQ_EINT0, 0);
  92. }

  93. module_init(button_init);
  94. module_exit(button_exit);


阅读(594) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~