对比一段ADC键值读取的代码

最近接触到的一个代码,这个代码看起来很简单,但是却蕴藏了人类的智慧与结晶。正是这些不断产生的智慧与结晶,让我们的电子产品越来越稳定,越来越智能。

周五了,评论文章,选两个同学赠送书籍《Linux内核完全剖析》基于0.12。

#功能

通过ADC值的不同来判断是哪个按键按下,这种方案应该是很常见了,而且这种方案可以节省GPIO口。实现起来的难度也不是特别大。

#硬件连接

#原来的旧代码

static void adc_key_poll(struct work_struct *work)
{struct rk_keys_drvdata *ddata;int i, result = -1;ddata = container_of(work, struct rk_keys_drvdata, adc_poll_work.work);if (!ddata->in_suspend) {result = rk_key_adc_iio_read(ddata);/**读取SARADC值*/if (result > INVALID_ADVALUE &&┊   result < (EMPTY_DEFAULT_ADVALUE - ddata->drift_advalue))ddata->result = result;for (i = 0; i < ddata->nbuttons; i++) {struct rk_keys_button *button = &ddata->button[i];if (!button->adc_value)continue;if (result < button->adc_value + ddata->drift_advalue &&┊   result > button->adc_value - ddata->drift_advalue)button->adc_state = 1;elsebutton->adc_state = 0;if (button->state != button->adc_state)mod_timer(&button->timer,┊ jiffies + DEBOUNCE_JIFFIES);}}schedule_delayed_work(&ddata->adc_poll_work, ADC_SAMPLE_JIFFIES);
}

#升级代码

static void adc_keys_poll(struct input_polled_dev *dev)
{struct adc_keys_state *st = dev->private;int i, value, ret;u32 diff, closest = 0xffffffff;int keycode = 0;ret = iio_read_channel_processed(st->channel, &value);if (unlikely(ret < 0)) {/* Forcibly release key if any was pressed */value = st->keyup_voltage;} else {/*先把电压值与所有按键列表的值比较,找出最接近的一个,以及找出最接近的差值。*/for (i = 0; i < st->num_keys; i++) {diff = abs(st->map[i].voltage - value);if (diff < closest) {closest = diff;keycode = st->map[i].keycode;}}}//printk("adc_keys_poll value:%d keycode:%d\n",value,keycode);/*然后把如果发现当前电压值与按键弹起的电压值很接近,(标准是小于上面找出的最小差值),那么认为没有按键按下,所以设置keycode为0,不上报。*/if (abs(st->keyup_voltage - value) < closest)keycode = 0;if (st->last_key && st->last_key != keycode)input_report_key(dev->input, st->last_key, 0);if (keycode){input_report_key(dev->input, keycode, 1);printk("adc_key_poll keycode:%d\n",keycode);}/*他这么做有个好处,就是只要硬件设计合理的情况下,电阻不同批料有误差的情况下,也不至于需要驱动工程师去修改电压值或者误差范围才能识别按键。*//*这个做法肯定是在量产出现了很多问题后作出的改善。*/input_sync(dev->input);st->last_key = keycode;
}

完整的驱动代码可以看下面这段,我觉得这小段代码的意义非常大。很有意思,通过一个for循环找到一个最接近的数值,判断为按下的这个键值。而且如果按下和 抬起来的数值接近,就判断为没有按键按下。

这就不需要再去考虑一个问题,那就误差范围的问题了。之前的那套旧代码使用的是误差范围,如果ADC值设定为 2000 ,误差范围设定为100,那么读取的ADC值在1900~2100范围内都可以认为是这个按键按下的。

但是存在一个情况,就是不同批次,不同物料的硬件,误差总是不能令人满意,软件需要不断的调整这个误差范围。在不断的调整过程中,发现调整误差范围已经不能解决当下的问题了,所以就产生了新的算法。而我们现在看到的这个新的算法就这样应运而生了。当然,实际情况可能还要复杂化,可能需要加上一些滤波算法先过滤等等。

总之,各位可以保存下来这段代码,在需要的时候拿来使用。展现自己的码农魅力。

#完整升级代码


/** Input driver for resistor ladder connected on ADC** Copyright (c) 2016 Alexandre Belloni** This program is free software; you can redistribute it and/or modify it* under the terms of the GNU General Public License version 2 as published by* the Free Software Foundation.*/
#include <linux/err.h>
#include <linux/iio/consumer.h>
#include <linux/iio/types.h>
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
struct adc_keys_button {u32 voltage;u32 keycode;
};
struct adc_keys_state {struct iio_channel *channel;u32 num_keys;u32 last_key;u32 keyup_voltage;const struct adc_keys_button *map;
};
static void adc_keys_poll(struct input_polled_dev *dev)
{struct adc_keys_state *st = dev->private;int i, value, ret;u32 diff, closest = 0xffffffff;int keycode = 0;ret = iio_read_channel_processed(st->channel, &value);if (unlikely(ret < 0)) {/* Forcibly release key if any was pressed */value = st->keyup_voltage;} else {/*先把电压值与所有按键列表的值比较,找出最接近的一个,以及找出最接近的差值。*/for (i = 0; i < st->num_keys; i++) {diff = abs(st->map[i].voltage - value);if (diff < closest) {closest = diff;keycode = st->map[i].keycode;}}}//printk("adc_keys_poll value:%d keycode:%d\n",value,keycode);/*然后把如果发现当前电压值与按键弹起的电压值很接近,(标准是小于上面找出的最小差值),那么认为没有按键按下,所以设置keycode为0,不上报。*/if (abs(st->keyup_voltage - value) < closest)keycode = 0;if (st->last_key && st->last_key != keycode)input_report_key(dev->input, st->last_key, 0);if (keycode){input_report_key(dev->input, keycode, 1);printk("adc_key_poll keycode:%d\n",keycode);}/*他这么做有个好处,就是只要硬件设计合理的情况下,电阻不同批料有误差的情况下,也不至于需要驱动工程师去修改电压值或者误差范围才能识别按键。*//*这个做法肯定是在量产出现了很多问题后作出的改善。*/input_sync(dev->input);st->last_key = keycode;
}
static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
{struct adc_keys_button *map;struct fwnode_handle *child;int i;st->num_keys = device_get_child_node_count(dev);if (st->num_keys == 0) {dev_err(dev, "keymap is missing\n");return -EINVAL;}map = devm_kmalloc_array(dev, st->num_keys, sizeof(*map), GFP_KERNEL);if (!map)return -ENOMEM;i = 0;device_for_each_child_node(dev, child) {if (fwnode_property_read_u32(child, "press-threshold-microvolt",&map[i].voltage)) {dev_err(dev, "Key with invalid or missing voltage\n");fwnode_handle_put(child);return -EINVAL;}map[i].voltage /= 1000;if (fwnode_property_read_u32(child, "linux,code",&map[i].keycode)) {dev_err(dev, "Key with invalid or missing linux,code\n");fwnode_handle_put(child);return -EINVAL;}i++;}st->map = map;return 0;
}
static int adc_keys_probe(struct platform_device *pdev)
{struct device *dev = &pdev->dev;struct adc_keys_state *st;struct input_polled_dev *poll_dev;struct input_dev *input;enum iio_chan_type type;int i, value;int error;st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);if (!st)return -ENOMEM;st->channel = devm_iio_channel_get(dev, "buttons");if (IS_ERR(st->channel))return PTR_ERR(st->channel);if (!st->channel->indio_dev)return -ENXIO;error = iio_get_channel_type(st->channel, &type);if (error < 0)return error;if (type != IIO_VOLTAGE) {dev_err(dev, "Incompatible channel type %d\n", type);return -EINVAL;}if (device_property_read_u32(dev, "keyup-threshold-microvolt",&st->keyup_voltage)) {dev_err(dev, "Invalid or missing keyup voltage\n");return -EINVAL;}st->keyup_voltage /= 1000;error = adc_keys_load_keymap(dev, st);if (error)return error;platform_set_drvdata(pdev, st);poll_dev = devm_input_allocate_polled_device(dev);if (!poll_dev) {dev_err(dev, "failed to allocate input device\n");return -ENOMEM;}if (!device_property_read_u32(dev, "poll-interval", &value))poll_dev->poll_interval = value;poll_dev->poll = adc_keys_poll;poll_dev->private = st;input = poll_dev->input;input->name = pdev->name;input->phys = "adc-keys/input0";input->id.bustype = BUS_HOST;input->id.vendor = 0x0001;input->id.product = 0x0001;input->id.version = 0x0100;__set_bit(EV_KEY, input->evbit);for (i = 0; i < st->num_keys; i++)__set_bit(st->map[i].keycode, input->keybit);if (device_property_read_bool(dev, "autorepeat"))__set_bit(EV_REP, input->evbit);error = input_register_polled_device(poll_dev);if (error) {dev_err(dev, "Unable to register input device: %d\n", error);return error;}return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id adc_keys_of_match[] = {{ .compatible = "adc-keys", },{ }
};
MODULE_DEVICE_TABLE(of, adc_keys_of_match);
#endif
static struct platform_driver __refdata adc_keys_driver = {.driver = {.name = "adc_keys",.of_match_table = of_match_ptr(adc_keys_of_match),},.probe = adc_keys_probe,
};
module_platform_driver(adc_keys_driver);
MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
MODULE_DESCRIPTION("Input driver for resistor ladder connected on ADC");
MODULE_LICENSE("GPL v2");

推荐阅读:

Linux内核0.12完全注释

  回复「 篮球的大肚子」进入技术群聊

回复「1024」获取1000G学习资料

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/467817.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML5权威指南 11.通信API

1 <!DOCTYPE html>2 <html>3 4 <head>5 <meta charset"UTF-8">6 <title></title>7 <script type"text/javascript">8 //&#xff08;1&#xff09;监听message事件9 window.addEve…

在线登记系统代码 php_PHP框架实现WebSocket在线聊天通讯系统

ThinkPHP使用Swoole需要安装think-swooleComposer包&#xff0c;前提系统已经安装好了SwoolePECL拓展tp5的项目根目录下执行composer命令安装think-swoole&#xff1a;composerrequiretopthink/think-swoole话不多说&#xff0c;直接上代码&#xff1a;新建WebSocket.php控制器…

机器学习数据包之numpy

numpy 属性 import numpy as np#矩阵运算arraynp.array([[1,2,3],[2,3,4]])print (array)[[1 2 3][2 3 4]]维度 print(number of dim,array.ndim)number of dim 2形状 print(shape,array.shape)shape (2, 3)大小 print(size,array.size)size 6创建 创建类型 anp.array([…

RK 利用SARADC 来做多个按键

#DTS配置#配置DTS节点#驱动文件中匹配 DTS 节点#驱动说明#获取ADC通道#获取ADC值#计算采集到的电压#接口说明#调试方法#节点ADC值RK3399开发板上的 AD 接口有两种&#xff0c;分别为&#xff1a;温度传感器 (Temperature Sensor)、逐次逼近ADC (Successive Approximation Regis…

概率论之pandas

快速入门 1 import numpy as npspd.series([1,3,5,np.nan,8,4])Series spd.Series([1,3,5,np.nan,8,4])sOut[6]: 0 1.01 3.02 5.03 NaN4 8.05 4.0dtype: float64date_range datespd.date_range(20190301,periods6)datesOut[10]: DatetimeIndex([2019-03-…

学习,一定是脱“贫”致富的捷径

周末加班&#xff0c;加班后觉得有点无聊&#xff0c;到公司阳台坐了坐&#xff0c;想到最近的工作和生活&#xff0c;也理了理最近的状态&#xff0c;然后分享了一段话在知识星球里。如下:我平时很少静下来想东西&#xff0c;其中一个原因是因为我害怕安静&#xff0c;晚上睡觉…

人应该活成什么样子?该以什么方式活着?

“您幸福吗&#xff1f;”“我是外地打工的&#xff0c;不要问我。”“您幸福吗&#xff1f;”“我姓曾。”相信大家还记得这段央视走基层采访的经典问答。“幸福是什么”是一个人类社会中被广泛讨论的话题&#xff0c;人要怎么生活才能获得幸福&#xff0c;一直是众生要追寻的…

MIPI白皮书

#mipi 5G中优势#5G手机中的mipi#mipi#背景2020年 是5G元年&#xff0c;很多行业因5g重新定义。显示行业也不例外&#xff0c;针对5G&#xff0c;mipi联盟发表了对应的白皮书 描述了现有的MIPI规范如何能够支持第一代5G智能手机以及其他新兴的5G移动平台&#xff0c;包括互联/自…

redis rdb aof区别_Redis 持久化之 RDB 与 AOF 详解

走过路过不要错过点击蓝字关注我们文章出处&#xff1a;https://www.cnblogs.com/jojop/p/13941195.htmlRedis 持久化我们知道Redis的数据是全部存储在内存中的&#xff0c;如果机器突然GG&#xff0c;那么数据就会全部丢失&#xff0c;因此需要有持久化机制来保证数据不会因为…

块设备驱动初探

前言研究IO也很久了&#xff0c;一直无法串联bio和块设备驱动&#xff0c;只知道bio经过IO调度算法传递到块设备驱动&#xff0c;怎么过去的&#xff0c;IO调度算法在哪里发挥作用&#xff0c;一直没有完全搞明白&#xff0c;查看了很多资料&#xff0c;终于对块设备驱动有所理…

Linux 块设备,Block Layer层架构演变

前言Block Layer层在整个I/O中负责承上启下&#xff0c;上接文件系统&#xff0c;下接块驱动。我不想直接讨论代码&#xff0c;希望从一个架构的演变来初探一下Block Layer层。一、1.0版本首先我们来了解几个重要的数据结构1.1 biobio代表了一次I/0请求&#xff0c;代表一个块设…

matalotlib(2)

文章目录注释文字Tex公式区域填充极坐标注释 import matplotlib.pyplot as plt import numpy as np xnp.arange(-10,11,1) yx*x plt.plot(x,y)plt.annotate(this is the bottom,xy(0,1),xytext(0,20),arrowpropsdict(facecolorr,frac0.2)) plt.show()文字 import matplotlib…

去华为吗?

昨晚的这条朋友圈很多人给我回复&#xff0c;支持去华为的人很多&#xff0c;但是也有几个反对的&#xff0c;一个说&#xff0c;怕是有命赚钱&#xff0c;没命花钱吧。还有一个说&#xff0c;自己拿到了华为offer&#xff0c;但是拒绝了&#xff0c;去了一个做开关电源的公司做…

实例

文章目录函数积分图散点条形图球员能力值函数积分图 import matplotlib.pyplot as plt import numpy as np from matplotlib.pyplot import Polygon def func(x):return -(x-2)*(x-8)40 xnp.linspace(0,10) yfunc(x) axplt.subplot() plt.plot(x,y,r,linewidth2)a2 b9 ax.set_…

闲来无事,拆个示波器玩玩。

首先要解释一下何为混合域示波器&#xff0c;既然说到这个话题就不得不说一下示波器进化史了&#xff0c;接下来大概讲一下示波器进化简史。第一代示波器——模拟示波器(ART-analog real time oscilloscope )纯模拟机器&#xff0c;使用示波管显示X-Y扫描成像显示波形&#xff…

机器算法1)

SKLEARN Scikit-learn与特征工程 “数据决定了机器学习的上限&#xff0c;而算法只是尽可能逼近这个上限”&#xff0c;这句话很好的阐述了数据在机器学习中的重要性。大部分直接拿过来的数据都是特征不明显的、没有经过处理的或者说是存在很多无用的数据&#xff0c;那么需要…

老罗直播——只要给你一个机会,你就伸双手去接!

昨天&#xff0c;4月1日&#xff0c;罗永浩在抖音上直播卖货。一时间舆论纷纷&#xff0c;有吐槽老罗状况频出的&#xff0c;也有感叹老罗为了挣钱能屈能伸的。总之&#xff0c;有人讨论&#xff0c;有人关注&#xff0c;这个事件已经成功了一大半。老罗与抖音签约费是6000万&a…

我在MTK平台下调试音频ALSA

#前言前言我就随便写了&#xff0c;因为是项目的需要&#xff0c;我需要在我们的MTK8167S平台上面调试音频。包括录音和播放。#硬件原理图因为是我们公司的项目&#xff0c;我就不能把完整的原理图给出来。因为两个MIC不涉及机密&#xff0c;跟MTK的公版是一样的。可以给出来大…

一切不怕从零开始

不知道大家有没有看过吴京题为<<一切不怕从零开始>>的演讲。我曾经刷微博的时候看到过,印象和触动最深的是他的那句"我走过很多的路,换过很多的方向,不敢说有什么成就,到今天我觉得唯一能够让我拿出来炫耀的可能就是,我不害怕从头开始"。这样的话,对年龄…

机器学习算法3

文章目录转换器与估计器分类算法-K近邻算法一个例子弄懂k-近邻计算距离公式sklearn.neighborsMethodk近邻实例k-近邻算法案例分析对Iris数据集进行分割对特征数据进行标准化朴素贝叶斯概率论基础联合概率与条件概率联合概率条件概率如果每个事件相互独立拉普拉斯平滑sklearn朴素…