开发环境

ubeMX
MDK5 IDE
STM32F103C8T6 芯片
Stm32最小系统板
RT-Thread操作系统

硬件条件

  • LPD3806-400BM-G5-24C 脉冲AB相增量式光电旋转编码器
  • AB相线需要分别连接单片机的具有编码器功能的定时器通道1和通道2两个引脚
  • 两引脚需要内部上拉

image.png

  • 使用开发板等引脚电路复杂读取数据会失败
  • 需要使用直接引脚引出的单片机设备(如Stm32最小系统板)

    Cube

    image.png

  • 这里用的是TIM多少,后面的RTT编码器设备就要配置Encoder多少,程序中使用pulse多少

    Kconfig

    1. menuconfig BSP_USING_PULSE_ENCODER
    2. bool "Enable Pulse Encoder"
    3. default n
    4. select RT_USING_PULSE_ENCODER
    5. if BSP_USING_PULSE_ENCODER
    6. config BSP_USING_PULSE_ENCODER4
    7. bool "Enable Pulse Encoder4"
    8. default n
    9. endif

    Env

    image.pngimage.png

  • scons —target=mdk5

生成工程

MDK

image.png
即配置成功

  • 也可修改设备名称,不使用默认的”pulse4”
  • pulse_encoder_config.h

    1. #ifdef BSP_USING_PULSE_ENCODER4
    2. #ifndef PULSE_ENCODER4_CONFIG
    3. #define PULSE_ENCODER4_CONFIG \
    4. { \
    5. .tim_handler.Instance = TIM4, \
    6. .encoder_irqn = TIM4_IRQn, \
    7. .name = "pulse4" \
    8. }
    9. #endif /* PULSE_ENCODER4_CONFIG */
    10. #endif /* BSP_USING_PULSE_ENCODER4 */
  • 修改.name即可,但建议保持默认命名

    接口函数

    查找设备

    1. rt_device_t rt_device_find(const char* name);

    | 参数 | 描述 | | —- | —- | | name | 脉冲编码器的设备名称 | | 返回 | —— | | 脉冲编码器设备句柄 | 查找到对应设备将返回相应的设备句柄 | | RT_NULL | 没有找到设备 |

  • 一般情况下,注册到系统的脉冲编码器的设备名称为 pulse1,pulse2等

    打开设备

    1. rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags);

    | 参数 | 描述 | | —- | —- | | dev | 脉冲编码器设备句柄 | | oflags | 设备打开模式,一般以只读方式打开,即取值:RT_DEVICE_OFLAG_RDONLY | | 返回 | —— | | RT_EOK | 设备打开成功 | | 其他错误码 | 设备打开失败 |

控制设备

  1. rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg);
参数 描述
dev 设备句柄
cmd 命令控制字
arg 控制的参数
返回 ——
RT_EOK 函数执行成功
-RT_ENOSYS 执行失败,dev 为空
其他错误码 执行失败
  • 控制字如下 | 控制字 | 描述 | | —- | —- | | PULSE_ENCODER_CMD_GET_TYPE | 获取脉冲编码器类型 | | PULSE_ENCODER_CMD_ENABLE | 使能脉冲编码器 | | PULSE_ENCODER_CMD_DISABLE | 失能脉冲编码器 | | PULSE_ENCODER_CMD_CLEAR_COUNT | 清空编码器计数值 |

  • 注:打开设备时,默认设备已使能

    读取计数

    1. rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size);

    | 参数 | 描述 | | —- | —- | | dev | 设备句柄 | | pos | 固定值为 0 | | buffer | rt_int32_t 类型变量的地址,用于存放脉冲编码器的值。 | | size | 固定值为 1 | | 返回 | —— | | 固定返回值 | 返回 1 |

关闭设备

  1. rt_err_t rt_device_close(rt_device_t dev);
参数 描述
dev 脉冲编码器设备句柄
返回 ——
RT_EOK 关闭设备成功
-RT_ERROR 设备已经完全关闭,不能重复关闭设备
其他错误码 关闭设备失败

实验例程

  1. #include <rtthread.h>
  2. #include <rtdevice.h>
  3. #include <board.h>
  4. #define PULSE_ENCODER_DEV_NAME "pulse4" /* 脉冲编码器名称 */
  5. int main(void)
  6. {
  7. rt_err_t ret = RT_EOK;
  8. rt_device_t pulse_encoder_dev = RT_NULL; /* 脉冲编码器设备句柄 */
  9. /* 查找脉冲编码器设备 */
  10. pulse_encoder_dev = rt_device_find(PULSE_ENCODER_DEV_NAME);
  11. if (pulse_encoder_dev == RT_NULL)
  12. {
  13. rt_kprintf("pulse encoder sample run failed! can't find %s device!\n", PULSE_ENCODER_DEV_NAME);
  14. return RT_ERROR;
  15. }
  16. /* 以只读方式打开设备 */
  17. ret = rt_device_open(pulse_encoder_dev, RT_DEVICE_OFLAG_RDONLY);
  18. if (ret != RT_EOK)
  19. {
  20. rt_kprintf("open %s device failed!\n", PULSE_ENCODER_DEV_NAME);
  21. return ret;
  22. }
  23. /* 设置上拉两个引脚 */
  24. rt_pin_mode(GET_PIN(B, 6), PIN_MODE_INPUT_PULLUP);
  25. rt_pin_mode(GET_PIN(B, 7), PIN_MODE_INPUT_PULLUP);
  26. rt_int32_t count;
  27. while(1)
  28. {
  29. rt_thread_mdelay(1);
  30. /* 读取脉冲编码器计数值 */
  31. rt_device_read(pulse_encoder_dev, 0, &count, 1);
  32. rt_kprintf("%d",count);
  33. }
  34. }

模块化实现

Module_PulseEncoder.h

  1. /*
  2. * Copyright (c) 2020 - ~, HIT_HERO Team
  3. *
  4. * PULSE ENCODER MODULE HEAD FILE
  5. * Used in RT-Thread Operate System
  6. *
  7. * Change Logs:
  8. * Date Author Notes Mail
  9. * 2020-09-03 WangXi first version WangXi_chn@foxmail.com
  10. */
  11. #ifndef _MODULE_PULSEENCODER_
  12. #define _MODULE_PULSEENCODER_
  13. #include <rtthread.h>
  14. #include <rtdevice.h>
  15. #include <board.h>
  16. struct _MODULE_PULSEENCODER
  17. {
  18. /* Property */
  19. char * Property_PulseDevName;
  20. rt_base_t Property_CH1_pin;
  21. rt_base_t Property_CH2_pin;
  22. /* Value */
  23. rt_device_t Value_pulse_dev;
  24. rt_int32_t Value_pulseNum;
  25. /* Method */
  26. void (*Method_Init)(struct _MODULE_PULSEENCODER *module);
  27. void (*Method_Read)(struct _MODULE_PULSEENCODER *module);
  28. void (*Method_Clear)(struct _MODULE_PULSEENCODER *module);
  29. };
  30. typedef struct _MODULE_PULSEENCODER MODULE_PULSEENCODER;
  31. rt_err_t Module_PulseEncoder_Config(MODULE_PULSEENCODER *module);
  32. #endif
  33. /************************ (C) COPYRIGHT 2020 WANGXI **************END OF FILE****/

Module_PulseEncoder.c

  1. /*
  2. * Copyright (c) 2020 - ~, HIT_HERO Team
  3. *
  4. * PULSE ENCODER MODULE SOUCE FILE
  5. * Used in RT-Thread Operate System
  6. *
  7. * Change Logs:
  8. * Date Author Notes Mail
  9. * 2020-09-03 WangXi first version WangXi_chn@foxmail.com
  10. */
  11. #include "Module_PulseEncoder.h"
  12. static void Module_PulseEncoderInit(MODULE_PULSEENCODER *module);
  13. static void Module_PulseEncoderRead(MODULE_PULSEENCODER *module);
  14. static void Module_PulseEncoderClear(MODULE_PULSEENCODER *module);
  15. /* Global Method */
  16. rt_err_t Module_PulseEncoder_Config(MODULE_PULSEENCODER *module)
  17. {
  18. if( module->Method_Init ==NULL &&
  19. module->Method_Read ==NULL &&
  20. module->Method_Clear ==NULL
  21. ){
  22. /* Link the Method */
  23. module->Method_Init = Module_PulseEncoderInit;
  24. module->Method_Read = Module_PulseEncoderRead;
  25. module->Method_Clear = Module_PulseEncoderClear;
  26. }
  27. else{
  28. rt_kprintf("Warning: Module BspCommunicate is Configed twice\n");
  29. return RT_ERROR;
  30. }
  31. /* Device Init */
  32. module->Method_Init(module);
  33. return RT_EOK;
  34. }
  35. static void Module_PulseEncoderInit(MODULE_PULSEENCODER *module)
  36. {
  37. rt_err_t ret = RT_EOK;
  38. /* find pulse encode device */
  39. module->Value_pulse_dev = rt_device_find(module->Property_PulseDevName);
  40. if (module->Value_pulse_dev == RT_NULL)
  41. {
  42. rt_kprintf("pulse encoder sample run failed! can't find %s device!\n", module->Property_PulseDevName);
  43. return;
  44. }
  45. /* open the device in readonly mode */
  46. ret = rt_device_open(module->Value_pulse_dev, RT_DEVICE_OFLAG_RDONLY);
  47. if (ret != RT_EOK)
  48. {
  49. rt_kprintf("open %s device failed!\n", module->Property_PulseDevName);
  50. return;
  51. }
  52. rt_pin_mode(module->Property_CH1_pin, PIN_MODE_INPUT_PULLUP);
  53. rt_pin_mode(module->Property_CH2_pin, PIN_MODE_INPUT_PULLUP);
  54. }
  55. static void Module_PulseEncoderRead(MODULE_PULSEENCODER *module)
  56. {
  57. rt_device_read(module->Value_pulse_dev, 0, &(module->Value_pulseNum), 1);
  58. }
  59. static void Module_PulseEncoderClear(MODULE_PULSEENCODER *module)
  60. {
  61. rt_device_control(module->Value_pulse_dev, PULSE_ENCODER_CMD_CLEAR_COUNT, RT_NULL);
  62. module->Value_pulseNum = 0;
  63. }
  64. /************************ (C) COPYRIGHT 2020 WANGXI **************END OF FILE****/
  • 使用时仅需定义使用的RTT标准I2C设备名以及定时器的两个通道引脚即可
  • 调用结构体函数成员使用方法,读取编码器信息

    注意事项

  • 如果没有读数或读数奇怪,可能是最后没有设置定时器的两个引脚上拉,或者是引脚周围有其他电路干扰