北京好的网站制作,公司网站首页设计,豪禾创意海报设计理念,做的好的大学生旅行有哪些网站好最近接触到的一个代码#xff0c;这个代码看起来很简单#xff0c;但是却蕴藏了人类的智慧与结晶。正是这些不断产生的智慧与结晶#xff0c;让我们的电子产品越来越稳定#xff0c;越来越智能。周五了#xff0c;评论文章#xff0c;选两个同学赠送书籍《Linux内核完全剖… 最近接触到的一个代码这个代码看起来很简单但是却蕴藏了人类的智慧与结晶。正是这些不断产生的智慧与结晶让我们的电子产品越来越稳定越来越智能。周五了评论文章选两个同学赠送书籍《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.bellonifree-electrons.com);
MODULE_DESCRIPTION(Input driver for resistor ladder connected on ADC);
MODULE_LICENSE(GPL v2);推荐阅读Linux内核0.12完全注释 回复「 篮球的大肚子」进入技术群聊回复「1024」获取1000G学习资料