宫腔粘连有什么危害| 一行是什么意思| 为什么会血脂高| 热气是什么意思| 端午节应该吃什么| 姨妈疼吃什么止疼药| 腊肉炒什么| 高危行为是什么意思| 止血敏又叫什么| 螺蛳粉有什么危害| 三级医院是什么意思| 什么中药能降血压| 新生儿什么时候可以喝水| 心梗是什么原因引起的| 什么花适合送老师| 血管没有弹性是什么原因| 王禹读什么| 孕妇地中海贫血对胎儿有什么影响| 腔隙脑梗吃什么药最好| 玄牝是什么意思| sakose是什么牌子| 酱油什么时候发明的| 霍山黄芽属于什么茶| 劲酒加什么好喝| 副军长是什么军衔| 例假提前来是什么原因| 什么背什么腰| 吃杏子有什么好处| 肌酐高是什么意思| 签注什么意思| 车牌颜色代表什么| 磋商是什么意思| 冲正什么意思| 高同型半胱氨酸血症吃什么药| 什么年龄割双眼皮最好| 一般什么人戴江诗丹顿| 冠状ct能查什么| 996什么意思| mcm中文叫什么牌子| 出马仙是什么意思| 花椒有什么功效| 水煮鱼一般用什么鱼| 寸脉弱是什么原因| 姓卢的男孩起什么名字好| 肛门指检能查出什么| 法式刘海适合什么脸型| 悬饮是什么意思| 色弱什么意思| 吃牛肉对身体有什么好处| 警察是什么生肖| 斑秃吃什么药| 大肠杆菌属于什么菌| 阿迪达斯和三叶草有什么区别| 阿甘正传珍妮得了什么病| 大盘是什么意思| 右耳鸣是什么原因| 纯色是什么颜色| hbo什么意思| 鸡蛋补充什么营养| 三教九流代表什么生肖| 韭菜什么时候种最好| 背痛是什么原因引起的| 指甲起层是什么原因| 做梦掉牙齿是什么意思| 军国主义是什么意思| 名称是什么意思| 肉苁蓉是什么| 大便带血是什么原因男| 为什么体检要空腹| 出海什么意思| 尿多吃什么药| alt什么意思| 肾气亏虚吃什么中成药| 滴虫性阴道炎用什么药好| 10.28是什么星座| ala是什么| 三个羊念什么| 平板支撑练什么| 白开水是什么意思| 淋巴细胞比率低是什么意思| 上海话册那是什么意思| 尿毒症是什么症状| 蚊子讨厌什么气味| 痉挛什么意思| 夫妻分床睡意味着什么| 开颌是什么意思| hw是什么牌子| 农家一碗香是什么菜| 脸上突然长斑是什么原因引起的| 丙三醇是什么东西| 为什么会长湿疹| 金色和什么颜色搭配好看| 清明节的习俗有什么| 人乳头瘤病毒感染是什么意思| 乌豆是什么| 手比脸白是什么原因| 光年是什么单位| 缺钙吃什么食物| 移植后要注意什么| psc是什么病| 长公主是什么意思| 人参补什么| 星星是什么的眼睛| 怀孕一个月有什么症状| 什么是蜘蛛痣图片| 单核细胞高是什么感染| 女人性高潮是什么感觉| 讲究是什么意思| 梦到绿色的蛇是什么意思| 峰会什么时候开| 豇豆是什么| 鼻窦炎用什么药效果最好| 一月14号是什么星座| 上午10点半是什么时辰| 老是打喷嚏是什么原因| 海市蜃楼为什么可怕| 出片是什么意思| 12月4日是什么日子| 吴五行属什么| 大是什么意思| 背上长毛是什么原因引起的| 猎奇什么意思| 浅表性胃炎吃什么中成药最好| 肌炎是什么病| 揩油是什么意思| 睡醒后口苦是什么原因| 悉如外人的悉是什么意思| 子宫前位什么姿势易孕| 感受是什么意思| 为什么蛋皮会痒| 胃胀吃什么好| pass掉是什么意思| 感冒为什么会鼻塞| vod是什么意思| 气血两虚是什么意思| 水煎是什么意思| 龙王庙是指什么生肖| 桑叶长什么样子图片| 水晶粉是什么粉| 脑缺血灶是什么意思| 医保卡是什么样子的| 推崇是什么意思| 浮尘是什么意思| 一个月一个非念什么| 脑病科是看什么病的| 右手臂酸痛是什么前兆| 干事是什么职务| 胃溃疡不能吃什么食物| 圆形脸适合什么样的发型| 爱是什么| 什么瓜不能吃脑筋急转弯| 男人吃韭菜有什么好处| sg比重是什么意思| 付之一炬是什么意思| 结扎是什么| 什么水果汁减肥效果好| 男士感染霉菌用什么药| ys是什么意思| 胃不舒服想吐是什么原因| hpv45型阳性是什么意思| 男人割了皮包什么样子| 六月十八是什么星座| 虚岁28岁属什么生肖| 喝什么茶能降血压| 什么是病毒| 大便粘马桶是什么原因| 不孕吐的人说明什么| 腊肠和什么菜炒最佳| 竖心旁的字有什么| 特别的意思是什么| 拉肚子应该挂什么科| 降压药什么时候吃最好| 女人有腰窝意味着什么| 老人经常头晕是什么原因引起的| 鹅口疮有什么症状| 后期是什么意思| 烂苹果气味的是什么病| 月经颜色暗红色是什么原因| 腹泻吃什么食物| 取其轻前一句是什么| 积聚病什么意思| 瘢痕体质是什么意思| 什么是早恋| 应收账款在贷方表示什么| 鲈鱼是什么鱼| 胰尾显示不清什么意思| 汗疱疹用什么药| 放下是什么意思| 江小白是什么酒| 转移什么意思| 肺部结节是什么意思| uniqlo是什么牌子| 说风就是雨什么意思| 根是什么意思| 舌头上有齿痕是什么原因| 脚上长水泡是什么原因| 大人睡觉流口水是什么原因引起的| 53年属什么生肖| 胰腺癌晚期什么症状| 抗性糊精是什么| mrd是什么| 口干舌燥喝水也不解渴是什么原因| 什么动物没有心脏| 小孩子发烧抽搐是什么原因| 猴戏是什么意思| 福禄是什么意思| 爱被蚊子咬是什么体质| 骶髂关节炎吃什么药| hpv是什么引起的| 什么水果去火效果最好| 七月初一是什么日子| 听佛歌有什么好处| 女性肝囊肿要注意什么| 西柚是什么水果| 最后一个出场叫什么| 冠冕堂皇是什么意思| 中筋面粉适合做什么| 小腿骨头疼是什么原因| 高泌乳素血症是什么原因引起的| 什么叫同人文| 茶花什么时候开花| 梦见陌生人死了是什么意思| 血糖高不能吃什么| 一唱一和是什么生肖| 右侧肋骨下面是什么器官| 这是什么字| 百福骈臻是什么意思| 子宫直肠陷凹什么意思| 塑料是用什么做的| 庆生是什么意思| 外婆的妈妈叫什么| 眼睛痒用什么滴眼液| 在干什么| 廉洁奉公是什么意思| 乙状结肠腺瘤是什么病| 男人左眼下有痣代表什么| 白醋和陈醋有什么区别| 人为什么会说梦话| 大腿疼是什么原因| prc是什么意思| 电视开不了机是什么原因| 做梦梦见下大雨是什么意思| 婴儿增强免疫力吃什么| 义愤填膺是什么意思| 口舌生疮吃什么药| gi什么意思| 拔智齿第二天可以吃什么| 褪黑素是什么东西| 地心引力是什么意思| 打狗看主人打虎看什么答案| 吃什么长头发| 1月10号是什么星座| 丝瓜和什么相克| 11五行属什么| 休学是什么意思| 分别心是什么意思| 盆腔炎是什么引起的| 尿液检查能查出什么病| 看乳腺挂什么科| 因果关系是什么意思| 运交华盖是什么意思| 发烧42度是什么概念| 憨是什么意思| 是故是什么意思| 百度
这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 ? 论坛首页 ? 嵌入式开发 ? 软件与操作系统 ? rtthread脉冲编码器框架解析

共5条 1/1 1 跳转至

rtthread脉冲编码器框架解析

高工
2025-08-04 20:25:22     打赏
百度 但难题也摆在眼前:村集体账户上那6000元,连个零头都不够。

背景

   脉冲编码器,在硬件上最常见的就是旋钮,在旋钮旋转时,对外接出的两个管脚依次产生低电平并依次返回高电平,电平下降或上升的先后顺序,代表旋钮旋转的方向。由于管脚中断间隔时间一般都比较长(ms级别),因此可以通过GPIO中断检测的方式去实现脉冲检测。也有一部分mcu厂商(已知的有nxp,st,新塘半导体,华大)把这种检测做到单独的硬件脉冲检测单元中,具体配置就得看厂商规格了,但不管怎么配置,对于软件来说,无非就是使能脉冲检测,然后在产生中断时读取脉冲计数,判断后续需要的操作,另外在不使用的时候调用关闭接口禁用模块。

RTT适配的脉冲检测框架

   源码路径:components/drivers/misc/pulse_encoder.c

驱动注册入口

#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops pulse_encoder_ops =
{
    rt_pulse_encoder_init,
    rt_pulse_encoder_open,
    rt_pulse_encoder_close,
    rt_pulse_encoder_read,
    RT_NULL,
    rt_pulse_encoder_control
};
#endif

rt_err_t rt_device_pulse_encoder_register(struct rt_pulse_encoder_device *pulse_encoder, const char *name, void *user_data)
{
    struct rt_device *device;

    RT_ASSERT(pulse_encoder != RT_NULL);
    RT_ASSERT(pulse_encoder->ops != RT_NULL);

    device = &(pulse_encoder->parent);

    device->type        = RT_Device_Class_Miscellaneous;
    device->rx_indicate = RT_NULL;
    device->tx_complete = RT_NULL;

#ifdef RT_USING_DEVICE_OPS
    device->ops         = &pulse_encoder_ops;
#else
    device->init        = rt_pulse_encoder_init;
    device->open        = rt_pulse_encoder_open;
    device->close       = rt_pulse_encoder_close;
    device->read        = rt_pulse_encoder_read;
    device->write       = RT_NULL;
    device->control     = rt_pulse_encoder_control;
#endif
    device->user_data   = user_data;

    return rt_device_register(device, name, RT_DEVICE_FLAG_RDONLY | RT_DEVICE_FLAG_STANDALONE);
}

   由注册接口可以知道,脉冲编码器框架并不需要实现写接口,因为实际上也没啥可写的,因为这种模块就是检测模块,不是输出模块。

初始化接口

static rt_err_t rt_pulse_encoder_init(struct rt_device *dev)
{
    struct rt_pulse_encoder_device *pulse_encoder;

    pulse_encoder = (struct rt_pulse_encoder_device *)dev;
    if (pulse_encoder->ops->init)
    {
        return pulse_encoder->ops->init(pulse_encoder);
    }
    else
    {
        return -RT_ENOSYS;
    }
}

   从接口实现上来看,初始化接口也没什么好设置的,仅仅是要求驱动把资源初始化好就行,没有任何附带参数。

打开接口

static rt_err_t rt_pulse_encoder_open(struct rt_device *dev, rt_uint16_t oflag)
{
    struct rt_pulse_encoder_device *pulse_encoder;

    pulse_encoder = (struct rt_pulse_encoder_device *)dev;
    if (pulse_encoder->ops->control)
    {
        return pulse_encoder->ops->control(pulse_encoder, PULSE_ENCODER_CMD_ENABLE, RT_NULL);
    }
    else
    {
        return -RT_ENOSYS;
    }
}

   与初始化接口一样,但传入的参数是RT_NULL让人觉得有些奇怪,因为其实常见的旋钮工作方式有两种,一种叫全波旋钮,从波形上来说,这种旋钮旋转一格,两个管脚的电平会先后下降后再先后上升。另一种叫半波旋钮,在旋转一格时,两个管脚的波形要么先后下降,要么先后上升。这里指定乘RT_NULL,我只能猜可能是维持当前设置的目的,个人理解上换成pulse_encoder->type会更加合适。

控制接口

static rt_err_t rt_pulse_encoder_control(struct rt_device *dev, int cmd, void *args)
{
    rt_err_t result;
    struct rt_pulse_encoder_device *pulse_encoder;

    result = RT_EOK;
    pulse_encoder = (struct rt_pulse_encoder_device *)dev;
    switch (cmd)
    {
    case PULSE_ENCODER_CMD_CLEAR_COUNT:// 计数清零,可能是用于计数异常的时候的恢复操作
        result = pulse_encoder->ops->clear_count(pulse_encoder);
        break;
    case PULSE_ENCODER_CMD_GET_TYPE:
        // 获取目前检测的工作模式,其实个人认为大部分场景下没必要上报此信息。
        // 因为这是和旋钮波形强相关的配置,除非业务需要知道,一般应用不会关注这块
        *(enum rt_pulse_encoder_type *)args = pulse_encoder->type;
        break;
    case PULSE_ENCODER_CMD_ENABLE:
    case PULSE_ENCODER_CMD_DISABLE: // 使能禁用编码器,需要注意的是,args是工作模式
        result = pulse_encoder->ops->control(pulse_encoder, cmd, args);
        break;
    default:
        result = -RT_ENOSYS;
        break;
    }

    return result;
}

读接口

static rt_ssize_t rt_pulse_encoder_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    struct rt_pulse_encoder_device *pulse_encoder;

    pulse_encoder = (struct rt_pulse_encoder_device *)dev;
    if (pulse_encoder->ops->get_count)
    {
        *(rt_int32_t *)buffer = pulse_encoder->ops->get_count(pulse_encoder);
    }
    return 1;
}

   读接口,也比较简单,就是从驱动拿到目前的计数值。

关闭接口

static rt_err_t rt_pulse_encoder_close(struct rt_device *dev)
{
    struct rt_pulse_encoder_device *pulse_encoder;

    pulse_encoder = (struct rt_pulse_encoder_device *)dev;
    if (pulse_encoder->ops->control)
    {
        return pulse_encoder->ops->control(pulse_encoder, PULSE_ENCODER_CMD_DISABLE, RT_NULL);
    }
    else
    {
        return -RT_ENOSYS;
    }
}

   关闭上,其实没啥好区分的,不管工作在什么模式,关闭后都是禁用了脉冲编码器的检测模块,因此没必要指定传递什么模式。

Add on

   分析了这么多,其实会发现,好像还漏了一个接口,脉冲编码中断上报好像没有。从目前开源出来的RTT的脉冲编码实现代码上看,虽然各家在驱动上实现上都有中断处理,但并没有添加向用户层主动上报的接口,也许是驱动适配人员不清楚RTT有一套统一的中断回调函数入口,也许是驱动适配人员认为脉冲编码器,只需要轮询检测就可以做到用户无感了吧。

总结

   总体来说,脉冲编码器的框架算是很简单了。而分析完后,我们也基本上可以获得一个相对标准的驱动实现模板。

struct pulse_encoder_device
{
    struct rt_pulse_encoder_device pulse_encoder;
    // TODO: 驱动内部参数
};
typedef struct pulse_encoder_device pulse_enccoder_device_t;

static pulse_enccoder_device_t pulse_encoder_obj[] =
{
#ifdef BSP_USING_PULSE_ENCODER1
    {
        //驱动内部参数初始值
    },
#endif
#ifdef BSP_USING_PULSE_ENCODER2
    {
    },
#endif
};

rt_err_t pulse_encoder_init(struct rt_pulse_encoder_device *pulse_encoder)
{
    rt_err_t result = RT_EOK;
    
    switch(pulse_encoder->type)
    {
    case SINGLE_PHASE_PULSE_ENCODER:
        // TODO: 半波旋钮使能
        break;
    case AB_PHASE_PULSE_ENCODER:
        // TODO: 全波旋钮使能
        break;
    default:
        result = -RT_ERROR;
        break;
    }
    return result;
}

rt_err_t pulse_encoder_clear_count(struct rt_pulse_encoder_device *pulse_encoder)
{
    // TODO: 清除计数器实现
    return RT_EOK;
}

rt_int32_t pulse_encoder_get_count(struct rt_pulse_encoder_device *pulse_encoder)
{
    rt_uint32_t count;
    
    // TODO: 获取计数值实现
    // count = ;
    return count;
}


rt_err_t pulse_encoder_control(struct rt_pulse_encoder_device *pulse_encoder, rt_uint32_t cmd, void *args)
{
    rt_err_t result;

    result = RT_EOK;

    switch (cmd)
    {
    case PULSE_ENCODER_CMD_ENABLE:
        result = pulse_encoder->ops->init(pulse_encoder); // 使能入口
        break;
    case PULSE_ENCODER_CMD_DISABLE:
        result = pulse_encoder_close(pulse_encoder); // 关闭入口
        break;
    default:
        result = -RT_ENOSYS;
        break;
    }

    return result;
}

// TODO:个人认为还需要实现中断回调函数,主要是通知应用旋钮事件发生

static const struct rt_pulse_encoder_ops _ops =
{
    .init = pulse_encoder_init,
    .get_count = pulse_encoder_get_count,
    .clear_count = pulse_encoder_clear_count,
    .control = pulse_encoder_control,
};

int rt_hw_pulse_encoder_init(void)
{
    int i;
    int result;

    result = RT_EOK;
    for (i = 0; i < sizeof(pulse_encoder_obj) / sizeof(pulse_encoder_obj[0]); i++)
    {
        pulse_encoder_obj[i].pulse_encoder.type = AB_PHASE_PULSE_ENCODER;
        pulse_encoder_obj[i].pulse_encoder.ops = &_ops;
        pulse_encoder_obj[i].pulse_encoder.parent.user_data = &(pulse_encoder_obj[i]);

        if (rt_device_pulse_encoder_register(&pulse_encoder_obj[i].pulse_encoder, pulse_encoder_obj[i].name, &pulse_encoder_obj[i]) != RT_EOK)
        {
            LOG_E("%s register failed", pulse_encoder_obj[i].name);
            result = -RT_ERROR;
        }
    }

    return result;
}
INIT_BOARD_EXPORT(rt_hw_pulse_encoder_init)





关键词: rtthread     脉冲编码器     框架     解析    

专家
2025-08-04 00:27:43     打赏
2楼

谢谢分享


专家
2025-08-04 06:46:47     打赏
3楼

学习一下


专家
2025-08-04 19:46:39     打赏
4楼

感谢分享


助工
2025-08-04 09:57:44     打赏
5楼

好文,谢谢分享。


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]
高血压是什么 开火念什么 必有近忧是什么意思 飞机什么不能带 咽喉痛吃什么药好得快
夏天做什么菜 纳气是什么意思 海鲜有什么 青春痘用什么药膏擦最好呢 什么是环切手术
夏天可以玩什么 贫血吃什么药 低氧血症是什么意思 7月11日什么星座 婴儿放屁多是什么原因
煎牛排用什么油 阴唇肥大有什么影响 梦见扫墓是什么预兆 阿托品是什么 女人颧骨高有什么说法
甲状腺需要做什么检查hcv9jop3ns0r.cn 美国是什么人种hcv8jop6ns3r.cn 为什么会得尿道炎hcv9jop5ns9r.cn 血糖高能吃什么食物helloaicloud.com mg是什么意思bjhyzcsm.com
湫是什么意思hcv7jop5ns3r.cn 淋巴细胞是什么hcv8jop8ns5r.cn 感光度是什么意思tiangongnft.com 9点是什么时辰hcv8jop5ns5r.cn 淋巴结为什么会肿大hcv8jop8ns8r.cn
血糖是什么hcv8jop5ns8r.cn 袁隆平是什么家hcv9jop4ns5r.cn 希爱力是什么药hcv8jop6ns3r.cn 喝什么缓解痛经最有效gangsutong.com 风水宝地是什么生肖yanzhenzixun.com
空鼻症是什么hcv8jop0ns0r.cn 械字号产品是什么意思hcv9jop5ns6r.cn wing什么意思hcv9jop7ns0r.cn 苏格兰牧羊犬吃什么hcv9jop2ns6r.cn 冷血动物是什么意思1949doufunao.com
百度