0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于Sensor API如何添加增量型旋转编码器的驱动

ZephyrProject 来源:HalfCoder 作者:lgl88911 2021-07-28 09:55 次阅读

增量型旋转编码器作为输入器件广泛用于各种设备,例如汽车音响的音量调节,收音机频率调节,示波器上的旋钮。但遗憾的是在Zephyr中并没有增量型旋转编码器的驱动,本文将基于现有的Sensor API, 说明如何添加增量型旋转编码器的驱动,本文不对驱动操作硬件的实现细节进行说明。

增量型旋转编码器硬件要点

本文使用的是KY-040旋转编码器,详细信息见文末参考

button引脚是一个对地的开关,按压时接地

旋转时A/B输出有相差的正交脉冲。

旋转一圈产生固定数量的脉冲

旋转时一个脉冲内旋转轴可以有多个停留位置,例如1,2,4.

驱动

驱动API选择

比较好的做法是为旋转编码器抽象新的驱动API,但新的API要进入Zephyr的主分支过程是非常漫长的,同时旋转编码器抽象API需要涵盖众多类型。因此我选用了现有的Senser API来对增量类型旋转编码器的API。

增量类型旋转编码器的按压就是一个简单的button,用gpio就可以处理,因此旋转编码器的驱动就只处理旋转。编码器的旋转理解为是一个角度的传感器,正反转为转动方向,转动的距离就是角度,这里使用sensor API的SENSOR_CHAN_ROTATION来对其进行操控。

设备树绑定

设备树绑定是对旋转编码器的硬件进行抽象,一个增量式旋转编码器与旋转相关的的硬件特性有如下信息:

输入引脚A/B

旋转一圈产生的脉冲

一个脉冲周期的稳妥数量

创建dts/bindings/sensor/rotary-encoder.yaml内容如下

description: |

Sensor driver for the relative-axis rotary encoder

compatible: “rotary-encoder”

properties:

label:

type: string

required: true

a-gpios:

type: phandle-array

required: true

description: A pin for the encoder

b-gpios:

type: phandle-array

required: true

description: B pin for the encoder

ppr:

type: int

description: Pulse Per Revolution

required: false

spp:

type: int

description: |

Number of steps (stable states) per period

1: Full-period mode (default)

2: Half-period mode

4: Quarter-period mode

required: false

驱动代码

从设备树中获取硬件信息

创建管理数据变量和读取硬件信息

struct encoder_config {

const char *a_label;

const uint8_t a_pin;

const uint8_t a_flags;

const char *b_label;

const uint8_t b_pin;

const uint8_t b_flags;

const uint8_t ppr;

const uint8_t spp;

};

//创建管理数据和配置数据的宏

#define ENCODER_INST(n)

struct encoder_data encoder_data_##n;

const struct encoder_config encoder_cfg_##n = {

.a_label = DT_INST_GPIO_LABEL(n, a_gpios),

.a_pin = DT_INST_GPIO_PIN(n, a_gpios),

.a_flags = DT_INST_GPIO_FLAGS(n, a_gpios),

.b_label = DT_INST_GPIO_LABEL(n, b_gpios),

.b_pin = DT_INST_GPIO_PIN(n, b_gpios),

.b_flags = DT_INST_GPIO_FLAGS(n, b_gpios),

COND_CODE_0(DT_INST_NODE_HAS_PROP(n, ppr), (1), (DT_INST_PROP(n, ppr))),

COND_CODE_0(DT_INST_NODE_HAS_PROP(n, spp), (SPP_FULL), (DT_INST_PROP(n, spp))),

};

//根据设备树对node进行初始化,会从设备树中读取硬件信息放在struct encoder_config变量中

DT_INST_FOREACH_STATUS_OKAY(ENCODER_INST)

驱动初始化

在启动的POST_KERNEL阶段会调用encoder_init对驱动进行初始化

int encoder_init(const struct device *dev)

{

// GPIO的配置

// GPIO中断安装

// 旋转编码器GPIO初始化状态读取

// 驱动初始化状态设置

// 驱动线程创建

// 使能中断

}

//注册驱动

DEVICE_AND_API_INIT(encoder_##n, DT_INST_LABEL(n), encoder_init, &encoder_data_##n, &encoder_cfg_##n,

POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &encoder_driver_api);

驱动流程

旋转编码器依靠脉冲触发GPIO中断,中断通知thread进行处理

static void encoder_a_gpio_callback(const struct device *dev, struct gpio_callback *cb,

uint32_t pins)

{

struct encoder_data *drv_data = CONTAINER_OF(cb, struct encoder_data, a_gpio_cb);

enable_int(drv_data-》dev, false);

drv_data-》intpin = 0b10;

//通知发生中断

k_sem_give(&drv_data-》gpio_sem);

}

static void encoder_b_gpio_callback(const struct device *dev, struct gpio_callback *cb,

uint32_t pins)

{

struct encoder_data *drv_data = CONTAINER_OF(cb, struct encoder_data, b_gpio_cb);

enable_int(drv_data-》dev, false);

drv_data-》intpin = 0b01;

//通知发生中断

k_sem_give(&drv_data-》gpio_sem);

}

static void encoder_thread(void *dev_ptr, void *p2, void *p3)

{

while (1) {

//等待中断通知

k_sem_take(&drv_data-》gpio_sem, K_FOREVER);

//根据A/B GPIO level情况判断正反旋转

//更新旋转数据

//通过trigger handle通过应用层

if (drv_data-》handler) {

drv_data-》handler(dev, drv_data-》trigger);

}

//使能中断

enable_int(dev, true);

}

}

驱动接口实现

sensor的接口有5个, 详细参考旋转编码器只用实现其中的2个既可以。

旋转编码器是主动输出型设备,无需软件触发,因此可以不必实现channel_fetch,只用实现trigger_set用于注册触发时的callback,实现channel_get用于在callback时从driver获取旋转的角度既可以。

12static int encoder_trigger_set(const struct device *dev, const struct sensor_trigger *trig,

sensor_trigger_handler_t handler)

{

struct encoder_data *drv_data = dev-》data;

enable_int(dev, false);

drv_data-》trigger = trig;

drv_data-》handler = handler;

enable_int(dev, true);

return 0;

}

static int encoder_channel_get(const struct device *dev, enum sensor_channel chan,

struct sensor_value *val)

{

struct encoder_data *drv_data = dev-》data;

const struct encoder_config *drv_cfg = dev-》config;

int32_t acc;

if (chan != SENSOR_CHAN_ROTATION) {

return -ENOTSUP;

}

acc = drv_data-》pulses;

val-》val1 = acc * FULL_ANGLE / (drv_cfg-》ppr * drv_cfg-》spp);

val-》val2 = acc * FULL_ANGLE - val-》val1 * (drv_cfg-》ppr * drv_cfg-》spp);

if (val-》val2) {

val-》val2 *= 1000000;

val-》val2 /= (drv_cfg-》ppr * drv_cfg-》spp);

}

return 0;

}

static const struct sensor_driver_api encoder_driver_api = {

.trigger_set = encoder_trigger_set,

.channel_get = encoder_channel_get,

};

驱动使用

添加设备树节点

在板子的dts中添加旋转编码器的设备树节点:

gpio1.22和gpio1.23是旋转编码器连接旋转编码器的A/B引脚。旋转编码器旋转一圈有15个脉冲,每个脉冲下有2个稳定状态。

input_encoder: rotary_encoder {

compatible = “rotary-encoder”;

status = “okay”;

label = “INPUT_ENCODER”;

a-gpios = 《&gpio1 22 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)》;

b-gpios = 《&gpio1 23 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)》;

ppr = 《15》;

spp = 《2》;

};

使用代码

void encoder_callback(const struct device *dev,

struct sensor_trigger *trigger)

{

struct sensor_value val;

//旋转编码器旋转发生,从驱动读出旋转过的角度

sensor_channel_get(dev, SENSOR_CHAN_ROTATION, &val);

printk(“current %d.%d

”, val.val1, val.val2);

}

void main(void)

{

struct device *dev;

//获取旋转编码器device

dev = device_get_binding(“INPUT_ENCODER”);

//注册trigger callback,当旋转发生时将调用encoder_callback

sensor_trigger_set(dev, NULL, encoder_callback);

}

以上测试测序编译完后跑起来的效果

current 12.0

current 24.0

current 36.0

current 48.0

current 36.0

current 24.0

current 12.0

current 0.0

current -12.0

current -24.0

current -36.0

current -48.0

参考

https://zh.wikipedia.org/wiki/%E6%97%8B%E8%BD%89%E7%B7%A8%E7%A2%BC%E5%99%A8

https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/input/rotary-encoder.txt

https://www.epitran.it/ebayDrive/datasheet/25.pdf

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Zephyr
    +关注

    关注

    0

    文章

    15

    浏览量

    5887

原文标题:Zephyr添加旋转编码器驱动

文章出处:【微信号:ZephyrProject,微信公众号:ZephyrProject】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    MCSDK霍尔和增量式多编码器同时配置,程序生成后中断函数冲突了怎么解决?

    使用mcsdk配置电机控制编码器如图,能够同时选择hall sensors编码器和 quadrature encoder编码器 并且 可以在传感选择enable auxiliary
    发表于 03-12 08:22

    如何将增量旋转编码器与Arduino连接

    在本教程中,您将学习如何将增量旋转编码器与Arduino连接,以读取旋钮的运动。这对于在机器人和其他应用程序中创建用户界面或读取机械位置非常有用。
    的头像 发表于 02-11 10:00 351次阅读
    如何将<b class='flag-5'>增量</b><b class='flag-5'>旋转</b><b class='flag-5'>编码器</b>与Arduino连接

    拆解编码器增量行业,哪些值得关注?

    编码器主要应用在人形机器人的旋转、直线执行模组和灵巧手,单特斯拉Optimus编码器需求量50+,价值量约为7500元,若在2025年实现100万台目标交付量,有望为编码器带来70亿级
    的头像 发表于 12-08 10:32 816次阅读

    旋转编码器能直接换吗_旋转编码器更换注意事项

    旋转编码器更换步骤第一步,卸开电机后盖,编码器的后盖。第二步,松开编码器安装螺丝。第三步,旋转电机转子轴,使
    的头像 发表于 11-12 08:07 829次阅读
    <b class='flag-5'>旋转</b><b class='flag-5'>编码器</b>能直接换吗_<b class='flag-5'>旋转</b><b class='flag-5'>编码器</b>更换注意事项

    R128开发指南:中断方式驱动旋转编码器

    旋转编码器有两种类型-绝对式和增量式。绝对编码器为我们提供旋钮的精确位置(以度为单位),而增量编码器
    发表于 10-19 17:20 251次阅读
    R128开发指南:中断方式<b class='flag-5'>驱动</b><b class='flag-5'>旋转</b><b class='flag-5'>编码器</b>

    增量编码器和绝对值编码器控制位置一样吗

    增量编码器和绝对值编码器是两种常见的位置控制装置,它们在控制位置方面有着不同的工作原理和特点。虽然它们都可以用于位置控制,但是在某些方面存在差异。首先,增量
    的头像 发表于 08-18 14:43 514次阅读
    <b class='flag-5'>增量</b>型<b class='flag-5'>编码器</b>和绝对值<b class='flag-5'>编码器</b>控制位置一样吗

    选择增量编码器分辨率的方法,影响增量编码器分辨率的因素

    增量编码器的分辨率是以编码器轴转动一周所产生的输出信号基本周期数来表示的,即脉冲数/转(PPR)。本文主要介绍选择增量编码器分辨率的方法以
    的头像 发表于 07-26 09:59 818次阅读

    看看在伺服电机中常用的几种编码器协议

    我们知道编码器的种类有很多,什么增量编码器、绝对值编码器、光电编码器旋转
    发表于 07-13 14:26 5275次阅读
    看看在伺服电机中常用的几种<b class='flag-5'>编码器</b>协议

    增量编码器和绝对值编码器有哪些区别?

    增量编码器和绝对值编码器有哪些区别?增量编码器通过对变化量进行计数来测量位置变化,而绝对值编码器
    的头像 发表于 07-05 13:34 2511次阅读
    <b class='flag-5'>增量</b>式<b class='flag-5'>编码器</b>和绝对值<b class='flag-5'>编码器</b>有哪些区别?

    旋转编码器是什么?浅读旋转编码器工作原理与特点及应用

    旋转编码器是什么?浅读旋转编码器工作原理与特点及应用:旋转编码器是一种常见的传感器,它能够通过检
    的头像 发表于 05-29 09:21 2198次阅读
    <b class='flag-5'>旋转</b><b class='flag-5'>编码器</b>是什么?浅读<b class='flag-5'>旋转</b><b class='flag-5'>编码器</b>工作原理与特点及应用

    虹科干货|绝对式编码器增量编码器的区别

    在不同的工作领域和工作中,需要使用对应的工具和产品。在处理具有旋转角度编码器的工作任务时,了解所需工具的类型是必要的。除了绝对值编码器外,还有增量
    的头像 发表于 05-26 10:51 1764次阅读

    编码器种类及型号

    编码器种类及型号:最常见的编码器类型是旋转编码器和线性编码器旋转
    的头像 发表于 05-18 11:15 3718次阅读
    <b class='flag-5'>编码器</b>种类及型号

    CH32V103基础教程101-旋转编码器

    最近,手上拿到一个360度旋转编码器模块—KY-040 FOR模块,因此就想用它写一个应用教程。本章教程主要用到GPIO和EXTI(外部中断/事件控制)。 1、旋转
    发表于 05-15 16:31

    增量编码器与绝对值编码器

    增量编码器与绝对值型编码器怎么选择?在进行编码器选择时,增量编码器和绝对值型
    的头像 发表于 05-08 11:28 1466次阅读
    <b class='flag-5'>增量</b>型<b class='flag-5'>编码器</b>与绝对值<b class='flag-5'>编码器</b>

    增量旋转编码器的工作原理和特点

    增量编码器旋转一圈提供一个固定数量的脉冲,速度是通过单位时间内测量的脉冲数计算。为了测量角度和位置,通常是从一个起始的参考点开始计数。
    的头像 发表于 04-27 10:20 1990次阅读