当前位置: 首页 > news >正文

嵌入式linux学习记录十,定时器

  1. 定时器去抖:

    1. 数据结构

      struct gpio_key { int gpio; struct gpio_desc *gpiod; int flag; int irq; struct timer_list key_timer; };

      每个按键独立一个定时器,设计合理。

    2. 定时器初始化
      /* 原代码 */ setup_timer(&gpio_keys_100ask[i].key_timer, key_timer_expire, &gpio_keys_100ask[i]); gpio_keys_100ask[i].key_timer.expires = ~0; add_timer(&gpio_keys_100ask[i].key_timer);

      setup_timer是内核 4.15 之前的旧接口,新内核已废弃。回调函数参数是unsigned long,类型不安全。

      改进:

      /* 使用新接口 */ timer_setup(&gpio_keys_100ask[i].key_timer, key_timer_expire, 0); gpio_keys_100ask[i].key_timer.expires = ~0; add_timer(&gpio_keys_100ask[i].key_timer); /* 回调函数改为 */ static void key_timer_expire(struct timer_list *t) { struct gpio_key *gpio_key = from_timer(gpio_key, t, key_timer); ... }
    3. 中断处理
      /* 原代码 */ static irqreturn_t gpio_key_isr(int irq, void *dev_id) { struct gpio_key *gpio_key = dev_id; printk("gpio_key_isr key %d irq happened\n", gpio_key->gpio); mod_timer(&gpio_key->key_timer, jiffies + HZ/5); return IRQ_HANDLED; }

      HZ/5 = 200ms去抖时间太长,正常按键响应会有明显延迟。printk在中断里频繁打印影响性能。

      改进:

      static irqreturn_t gpio_key_isr(int irq, void *dev_id) { struct gpio_key *gpio_key = dev_id; /* 去抖时间改为 20ms */ mod_timer(&gpio_key->key_timer, jiffies + msecs_to_jiffies(20)); return IRQ_HANDLED; }
    4. 定时器回调
      /* 原代码 */ static void key_timer_expire(unsigned long data) { struct gpio_key *gpio_key = data; int val; int key; val = gpiod_get_value(gpio_key->gpiod); printk("key_timer_expire key %d %d\n", gpio_key->gpio, val); key = (gpio_key->gpio << 8) | val; put_key(key); wake_up_interruptible(&gpio_key_wait); kill_fasync(&button_fasync, SIGIO, POLL_IN); }

      使用旧接口unsigned long data接收参数,不安全。没有区分按下和松开,两个事件都会放入缓冲区,用户需要自己判断。

      改进:

      static void key_timer_expire(struct timer_list *t) { struct gpio_key *gpio_key = from_timer(gpio_key, t, key_timer); int val; int key; val = gpiod_get_value(gpio_key->gpiod); /* 低电平有效:val=0 按下,val=1 松开,更直观 */ key = (gpio_key->gpio << 8) | (val ? 0 : 1); put_key(key); wake_up_interruptible(&gpio_key_wait); kill_fasync(&button_fasync, SIGIO, POLL_IN); }
    5. read 函数
      /* 原代码 */ static ssize_t gpio_key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { int err; int key; if (is_key_buf_empty() && (file->f_flags & O_NONBLOCK)) return -EAGAIN; wait_event_interruptible(gpio_key_wait, !is_key_buf_empty()); key = get_key(); err = copy_to_user(buf, &key, 4); return 4; }

      wait_event_interruptible返回值没有判断,被信号打断时应返回-EINTRcopy_to_user返回值没有判断,拷贝失败时应报错。size参数没有检查,用户传入小于4字节时会越界。

      改进:

      static ssize_t gpio_key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { int err; int key; /* 检查size */ if (size < 4) return -EINVAL; if (is_key_buf_empty() && (file->f_flags & O_NONBLOCK)) return -EAGAIN; /* 判断是否被信号打断 */ err = wait_event_interruptible(gpio_key_wait, !is_key_buf_empty()); if (err) return -EINTR; key = get_key(); /* 判断拷贝是否成功 */ if (copy_to_user(buf, &key, 4)) return -EFAULT; return 4; }
    6. remove 函数
      /* 原代码 */ static int gpio_key_remove(struct platform_device *pdev) { ... for (i = 0; i < count; i++) { free_irq(gpio_keys_100ask[i].irq, &gpio_keys_100ask[i]); del_timer(&gpio_keys_100ask[i].key_timer); // 不安全 } kfree(gpio_keys_100ask); return 0; }

      del_timer不等待回调执行完就删除,可能导致回调还在执行时内存已被释放。

      改进:

      static int gpio_key_remove(struct platform_device *pdev) { ... for (i = 0; i < count; i++) { free_irq(gpio_keys_100ask[i].irq, &gpio_keys_100ask[i]); del_timer_sync(&gpio_keys_100ask[i].key_timer); // 等回调结束再删 } kfree(gpio_keys_100ask); return 0; }
http://www.rkmt.cn/news/1474416.html

相关文章:

  • 别再死记硬背公式了!用Python+Matplotlib动画演示三相异步电动机的旋转磁场
  • 2026年6月6日博客精选
  • ThinkPad终极散热指南:3个简单步骤实现智能风扇控制与噪音优化
  • 从手机热点到复杂环境:一份给网络工程师的RSSI测量实战避坑指南
  • 为什么你的爆款文在AI分发后“消失”于后台?揭秘CSDN数据聚合逻辑中的4层过滤机制
  • Codeforces Round 1060
  • D2DX:让经典暗黑破坏神2在现代电脑上流畅运行的3个关键方案
  • Anthropic语义压缩层蒸发:模型可控性向应用层迁移
  • Sunshine游戏串流服务器:从零搭建到专业优化的完整指南
  • 嵌入式Linux实战:手把手教你为RX8025芯片编写RTC驱动(基于I2C接口)
  • 站外引流转化率失真预警!CSDN AI数字营销后台未统计的点击量,正在悄悄吃掉你30%+ROI
  • 26年嘉兴市黄金回收靠谱门店推荐 黄金+K金+白银+铂金回收门店TOP5排行榜+联系方式推荐 - 奢金汇
  • 告别轮询!用STM32 HAL库中断优雅处理CT117E-M4开发板的四个按键
  • 别急着破解!用javassist动态修改Aspose.Words 21.1,深入理解Java字节码操作
  • 嵌入式linux学习记录十一,tasklet、workqueue、中断下半部分线程化处理
  • 035、液态镜头技术探索:电压驱动对焦与手机差异化应用的可行性
  • 技术人如何应对职业文化迁徙:从硅谷到本土的适应策略
  • 明日方舟终极自动化助手:MAA助手的完整使用指南
  • FramePack:如何用13B模型在笔记本GPU上实现超长AI视频生成
  • ESP32蓝牙音频终极指南:快速构建蓝牙音乐接收器和发送器
  • Deep-Live-Cam:3分钟学会实时人脸替换的终极指南
  • S4.3创造而非替代——AI产品的价值主张重构
  • Colmap vs OpenMVG实战:用手机拍鞋子和恐龙,谁的三维重建效果更靠谱?
  • 医用超声图像模拟系统探头建模详细设计
  • 成都西装定制专业权威榜:5 家顶级店铺深度测评 - 西装爱好者
  • AIoT软硬协同新范式:从智能边缘到生态共建的实战解析
  • 为什么你的小红书/知乎引流在CSDN后台“凭空消失”?深度拆解AI数字营销后台的4层数据过滤机制
  • 如何通过WBS(工作分解结构)分解项目任务?
  • 034、微距镜头:近摄对焦范围、工作距离与景深的工程平衡
  • 如何快速定制macOS光标:5分钟学会系统美化技巧