# Pulse Encoder Devices

### [Pulse Encoder Introduction](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/pulse_encoder/pulse_encoder?id=%e8%84%89%e5%86%b2%e7%bc%96%e7%a0%81%e5%99%a8%e7%ae%80%e4%bb%8b) <a href="#mai-chong-bian-ma-qi-jian-jie" id="mai-chong-bian-ma-qi-jian-jie"></a>

A pulse encoder is a sensor that senses position using optical, magnetic or mechanical contacts and converts the position information into an electronic signal for output. The electronic signal it outputs is generally used as a feedback signal when controlling the position.

Pulse encoders can be divided into two categories according to their working principles: incremental and absolute. Incremental encoders convert displacement into periodic electrical signals, and then convert the electrical signals into counting pulses, using the number of pulses to represent the magnitude of displacement. Each position of an absolute encoder corresponds to a certain digital code, so its indication is only related to the starting and ending positions of the measurement, and has nothing to do with the intermediate process of the measurement. Most contemporary microcontrollers provide encoder peripherals for receiving and storing pulse encoder signals.

### [Accessing the Pulse Encoder Device](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/pulse_encoder/pulse_encoder?id=%e8%ae%bf%e9%97%ae%e8%84%89%e5%86%b2%e7%bc%96%e7%a0%81%e5%99%a8%e8%ae%be%e5%a4%87) <a href="#fang-wen-mai-chong-bian-ma-qi-she-bei" id="fang-wen-mai-chong-bian-ma-qi-she-bei"></a>

The application accesses the pulse encoder device through the I/O device management interface provided by RT-Thread. The relevant interface is as follows:

| **function**          | **describe**                                                                                          |
| --------------------- | ----------------------------------------------------------------------------------------------------- |
| rt\_device\_find()    | Find Pulse Encoder Devices                                                                            |
| rt\_device\_open()    | Open the pulse encoder device (read-only mode only)                                                   |
| rt\_device\_control() | Control the pulse encoder device, you can clear the count value, get the type, and enable the device. |
| rt\_device\_read()    | Get the current value of the pulse encoder                                                            |
| rt\_device\_close()   | Turn off the pulse encoder device                                                                     |

#### [Find Pulse Encoder Devices](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/pulse_encoder/pulse_encoder?id=%e6%9f%a5%e6%89%be%e8%84%89%e5%86%b2%e7%bc%96%e7%a0%81%e5%99%a8%e8%ae%be%e5%a4%87) <a href="#cha-zhao-mai-chong-bian-ma-qi-she-bei" id="cha-zhao-mai-chong-bian-ma-qi-she-bei"></a>

The application obtains the device handle according to the device name of the pulse encoder, and then can operate the pulse encoder device. The device search function is as follows:

```c
rt_device_t rt_device_find(const char* name);copymistakeCopy Success
```

| **parameter**               | **describe**                                                                            |
| --------------------------- | --------------------------------------------------------------------------------------- |
| name                        | Device name of pulse encoder                                                            |
| **return**                  | ——                                                                                      |
| Pulse encoder device handle | If the corresponding device is found, the corresponding device handle will be returned. |
| RT\_NULL                    | No device found                                                                         |

Generally, the device names of the pulse encoders registered to the system are pulse1, pulse2, etc. The usage examples are as follows:

```c
#define PULSE_ENCODER_DEV_NAME    "pulse1"    /* 脉冲编码器名称 */
rt_device_t pulse_encoder_dev;                /* 脉冲编码器设备句柄 */
/* 查找脉冲编码器设备 */
pulse_encoder_dev = rt_device_find(PULSE_ENCODER_DEV_NAME);copymistakeCopy Success
```

#### [Open the pulse encoder device](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/pulse_encoder/pulse_encoder?id=%e6%89%93%e5%bc%80%e8%84%89%e5%86%b2%e7%bc%96%e7%a0%81%e5%99%a8%e8%ae%be%e5%a4%87) <a href="#da-kai-mai-chong-bian-ma-qi-she-bei" id="da-kai-mai-chong-bian-ma-qi-she-bei"></a>

Through the device handle, the application can open the device. When opening the device, it will detect whether the device has been initialized. If it has not been initialized, the initialization interface will be called by default to initialize the device. Open the device through the following function:

```c
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags);copymistakeCopy Success
```

| **parameter**     | **describe**                                                                                            |
| ----------------- | ------------------------------------------------------------------------------------------------------- |
| dev               | Pulse encoder device handle                                                                             |
| oflags            | Device opening mode, usually opened in read-only mode, that is, the value is: RT\_DEVICE\_OFLAG\_RDONLY |
| **return**        | ——                                                                                                      |
| RT\_EOK           | Device opened successfully                                                                              |
| Other error codes | Device open failed                                                                                      |

The usage examples are as follows:

```c
#define PULSE_ENCODER_DEV_NAME    "pulse1"    /* 脉冲编码器名称 */
rt_device_t pulse_encoder_dev;                /* 脉冲编码器设备句柄 */
/* 查找脉冲编码器设备 */
pulse_encoder_dev = rt_device_find(PULSE_ENCODER_DEV_NAME);
/* 以只读方式打开设备 */
rt_device_open(pulse_encoder_dev, RT_DEVICE_OFLAG_RDONLY);copymistakeCopy Success
```

#### [Control pulse encoder equipment](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/pulse_encoder/pulse_encoder?id=%e6%8e%a7%e5%88%b6%e8%84%89%e5%86%b2%e7%bc%96%e7%a0%81%e5%99%a8%e8%ae%be%e5%a4%87) <a href="#kong-zhi-mai-chong-bian-ma-qi-she-bei" id="kong-zhi-mai-chong-bian-ma-qi-she-bei"></a>

Through the command control word, the application can set the pulse encoder device through the following function:

```c
rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg);copymistakeCopy Success
```

| **parameter**     | **describe**                   |
| ----------------- | ------------------------------ |
| dev               | Device handle                  |
| cmd               | Command control word           |
| arg               | Controlled Parameters          |
| **return**        | ——                             |
| RT\_EOK           | Function execution successful  |
| -RT\_ENOSYS       | Execution failed, dev is empty |
| Other error codes | Execution failed               |

The command control words supported by the pulse encoder device are as follows:

| **Control Word**                  | **describe**               |
| --------------------------------- | -------------------------- |
| PULSE\_ENCODER\_CMD\_GET\_TYPE    | Get the pulse encoder type |
| PULSE\_ENCODER\_CMD\_ENABLE       | Enable pulse encoder       |
| PULSE\_ENCODER\_CMD\_DISABLE      | Disable pulse encoder      |
| PULSE\_ENCODER\_CMD\_CLEAR\_COUNT | Clear encoder count value  |

#### [Read the pulse encoder count value](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/pulse_encoder/pulse_encoder?id=%e8%af%bb%e5%8f%96%e8%84%89%e5%86%b2%e7%bc%96%e7%a0%81%e5%99%a8%e8%ae%a1%e6%95%b0%e5%80%bc) <a href="#du-qu-mai-chong-bian-ma-qi-ji-shu-zhi" id="du-qu-mai-chong-bian-ma-qi-ji-shu-zhi"></a>

The pulse encoder count value can be read through the following function:

```c
rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size);copymistakeCopy Success
```

| **parameter**      | **describe**                                                                                  |
| ------------------ | --------------------------------------------------------------------------------------------- |
| dev                | Device handle                                                                                 |
| pos                | Fixed value is 0                                                                              |
| buffer             | The address of a variable of type rt\_int32\_t, used to store the value of the pulse encoder. |
| size               | Fixed value is 1                                                                              |
| **return**         | ——                                                                                            |
| Fixed return value | Return 1                                                                                      |

The usage examples are as follows:

```c
#define PULSE_ENCODER_DEV_NAME    "pulse1"    /* 脉冲编码器名称 */
rt_device_t pulse_encoder_dev;                /* 脉冲编码器设备句柄 */
rt_int32_t count;
/* 查找脉冲编码器设备 */
pulse_encoder_dev = rt_device_find(PULSE_ENCODER_DEV_NAME);
/* 以只读方式打开设备 */
rt_device_open(pulse_encoder_dev, RT_DEVICE_OFLAG_RDONLY);
/* 读取脉冲编码器计数值 */
rt_device_read(pulse_encoder_dev, 0, &count, 1);copymistakeCopy Success
```

#### [Turn off the pulse encoder device](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/pulse_encoder/pulse_encoder?id=%e5%85%b3%e9%97%ad%e8%84%89%e5%86%b2%e7%bc%96%e7%a0%81%e5%99%a8%e8%ae%be%e5%a4%87) <a href="#guan-bi-mai-chong-bian-ma-qi-she-bei" id="guan-bi-mai-chong-bian-ma-qi-she-bei"></a>

The pulse encoder device can be turned off by the following function:

```c
rt_err_t rt_device_close(rt_device_t dev);copymistakeCopy Success
```

| **parameter**     | **describe**                                                                     |
| ----------------- | -------------------------------------------------------------------------------- |
| dev               | Pulse encoder device handle                                                      |
| **return**        | ——                                                                               |
| RT\_EOK           | Shut down the device successfully                                                |
| -RT\_ERROR        | The device has been completely shut down. You cannot shut down the device again. |
| Other error codes | Failed to shut down the device                                                   |

Closing the device interface and opening the device interface must be used in pairs. Each time you open the device, you must close it once. Only in this way can the device be completely closed. Otherwise, the device will still be in an open state.

The usage examples are as follows:

```c
#define PULSE_ENCODER_DEV_NAME    "pulse1"    /* 脉冲编码器名称 */
rt_device_t pulse_encoder_dev;                /* 脉冲编码器设备句柄 */
/* 查找定时器设备 */
pulse_encoder_dev = rt_device_find(PULSE_ENCODER_DEV_NAME);
... ...
rt_device_close(pulse_encoder_dev);copymistakeCopy Success
```

### [Pulse encoder device usage examples](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/pulse_encoder/pulse_encoder?id=%e8%84%89%e5%86%b2%e7%bc%96%e7%a0%81%e5%99%a8%e8%ae%be%e5%a4%87%e4%bd%bf%e7%94%a8%e7%a4%ba%e4%be%8b) <a href="#mai-chong-bian-ma-qi-she-bei-shi-yong-shi-li" id="mai-chong-bian-ma-qi-she-bei-shi-yong-shi-li"></a>

The specific usage of the pulse encoder device can refer to the following sample code. The main steps of the sample code are as follows:

1. First, find the device and obtain the device handle based on the device name of the pulse encoder "pulse1".
2. Open device 'pulse1' as read-only.
3. Read the count value of the pulse encoder device.
4. Clear the count value of the pulse encoder. (Optional step)

```c
/*
 * 程序清单：这是一个脉冲编码器设备使用例程
 * 例程导出了 pulse_encoder_sample 命令到控制终端
 * 命令调用格式：pulse_encoder_sample
 * 程序功能：每隔 500 ms 读取一次脉冲编码器外设的计数值，然后清空计数值，将读取到的计数值打印出来。
*/

#include <rtthread.h>
#include <rtdevice.h>

#define PULSE_ENCODER_DEV_NAME    "pulse1"    /* 脉冲编码器名称 */

static int pulse_encoder_sample(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    rt_device_t pulse_encoder_dev = RT_NULL;   /* 脉冲编码器设备句柄 */
    rt_uint32_t index;
    rt_int32_t count;

    /* 查找脉冲编码器设备 */
    pulse_encoder_dev = rt_device_find(PULSE_ENCODER_DEV_NAME);
    if (pulse_encoder_dev == RT_NULL)
    {
        rt_kprintf("pulse encoder sample run failed! can't find %s device!\n", PULSE_ENCODER_DEV_NAME);
        return RT_ERROR;
    }

    /* 以只读方式打开设备 */
    ret = rt_device_open(pulse_encoder_dev, RT_DEVICE_OFLAG_RDONLY);
    if (ret != RT_EOK)
    {
        rt_kprintf("open %s device failed!\n", PULSE_ENCODER_DEV_NAME);
        return ret;
    }

    for (index = 0; index <= 10; index ++)
    {
        rt_thread_mdelay(500);
        /* 读取脉冲编码器计数值 */
        rt_device_read(pulse_encoder_dev, 0, &count, 1);
        /* 清空脉冲编码器计数值 */
        rt_device_control(pulse_encoder_dev, PULSE_ENCODER_CMD_CLEAR_COUNT, RT_NULL);
        rt_kprintf("get count %d\n",count);
    }

    rt_device_close(pulse_encoder_dev);
    return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(pulse_encoder_sample, pulse encoder sample);copymistakeCopy Success
```

<br>
