doc: updated readme
This commit is contained in:
1 parent
4de0443b35
commit
f2f3030ee7
1 file changed
+220
-49
@@ -1,23 +1,20 @@
|
|||||||
# ESP32 ESP-IDF component for rotary encoder using PCNT peripheral
|
# ESP32 ESP-IDF component for rotary encoder (PCNT peripheral)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
1. Quadrature decoding via PCNT peripheral.
|
1. Quadrature decoding through the PCNT peripheral hardware.
|
||||||
2. Configurable min/max/step values with float precision.
|
2. Configurable value range and step with float precision.
|
||||||
3. Push-button support with debouncing.
|
3. Push-button support with software debouncing timer.
|
||||||
4. Multiple simultaneous encoders (up to 8).
|
4. Multiple encoders sharing a single processing task (limited by PCNT units and GPIOs).
|
||||||
5. Event-based notification via esp_event (ISR context).
|
5. Asynchronous rotation and button notifications through esp_event.
|
||||||
6. Error statistics tracking for diagnostics.
|
6. Built-in error statistics with queue overflow and stack watermark counters.
|
||||||
|
|
||||||
## Note
|
## Attention
|
||||||
|
|
||||||
Enable the following settings in menuconfig:
|
1. Encoder number must be unique across all initialized encoders and greater than zero.
|
||||||
|
2. Task priority, stack size and queue size of the first initialized encoder are used by the shared processing task.
|
||||||
```text
|
3. Position is initialized to the midpoint of the configured range.
|
||||||
GPIO_CTRL_FUNC_IN_IRAM
|
4. Position is clamped to the configured minimum and maximum values.
|
||||||
PCNT_CTRL_FUNC_IN_IRAM
|
|
||||||
PCNT_ISR_IRAM_SAFE
|
|
||||||
```
|
|
||||||
|
|
||||||
## Using
|
## Using
|
||||||
|
|
||||||
@@ -34,62 +31,236 @@ In the application, add the component:
|
|||||||
#include "zh_encoder.h"
|
#include "zh_encoder.h"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example
|
## Examples
|
||||||
|
|
||||||
|
### Basic Example: Init and Get Position
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#include "zh_encoder.h"
|
#include "zh_encoder.h"
|
||||||
|
|
||||||
#define ENCODER_NUMBER 0x01
|
|
||||||
|
|
||||||
zh_encoder_handle_t *encoder_handle = NULL;
|
zh_encoder_handle_t *encoder_handle = NULL;
|
||||||
|
|
||||||
void zh_encoder_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
|
||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
esp_log_level_set("zh_encoder", ESP_LOG_ERROR);
|
esp_log_level_set("zh_encoder", ESP_LOG_ERROR);
|
||||||
esp_event_loop_create_default();
|
|
||||||
esp_event_handler_instance_register(ZH_ENCODER, ESP_EVENT_ANY_ID, &zh_encoder_event_handler, NULL, NULL);
|
|
||||||
zh_encoder_init_config_t config = ZH_ENCODER_INIT_CONFIG_DEFAULT();
|
zh_encoder_init_config_t config = ZH_ENCODER_INIT_CONFIG_DEFAULT();
|
||||||
config.task_priority = 5;
|
|
||||||
config.stack_size = configMINIMAL_STACK_SIZE;
|
|
||||||
config.queue_size = 5;
|
|
||||||
config.a_gpio_number = GPIO_NUM_4;
|
config.a_gpio_number = GPIO_NUM_4;
|
||||||
config.b_gpio_number = GPIO_NUM_16;
|
config.b_gpio_number = GPIO_NUM_16;
|
||||||
config.s_gpio_number = GPIO_NUM_15;
|
|
||||||
config.encoder_min_value = -10;
|
config.encoder_min_value = -10;
|
||||||
config.encoder_max_value = 10;
|
config.encoder_max_value = 10;
|
||||||
config.encoder_step = 0.001;
|
config.encoder_step = 1;
|
||||||
config.encoder_number = ENCODER_NUMBER;
|
config.encoder_number = 1;
|
||||||
zh_encoder_init(&config, &encoder_handle);
|
esp_err_t ret = zh_encoder_init(&config, &encoder_handle);
|
||||||
float encoder_position = 0;
|
if (ret != ESP_OK)
|
||||||
zh_encoder_get(&encoder_handle, &encoder_position);
|
|
||||||
printf("Encoder position %0.3f.\n", encoder_position);
|
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
const zh_encoder_stats_t *stats = zh_encoder_get_stats();
|
printf("Encoder initialization error: %s\n", esp_err_to_name(ret));
|
||||||
printf("Number of event post error: %ld.\n", stats->event_post_error);
|
return;
|
||||||
printf("Number of queue overflow error: %ld.\n", stats->queue_overflow_error);
|
}
|
||||||
printf("Minimum free stack size: %ld.\n", stats->min_stack_size);
|
float position = 0;
|
||||||
vTaskDelay(60000 / portTICK_PERIOD_MS);
|
ret = zh_encoder_get(&encoder_handle, &position);
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Encoder position: %0.3f\n", position);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Error getting position: %s\n", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
ret = zh_encoder_deinit(&encoder_handle);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Error deinitializing encoder: %s\n", esp_err_to_name(ret));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Set and Reset Position Example
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "zh_encoder.h"
|
||||||
|
|
||||||
|
zh_encoder_handle_t *encoder_handle = NULL;
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
esp_log_level_set("zh_encoder", ESP_LOG_ERROR);
|
||||||
|
zh_encoder_init_config_t config = ZH_ENCODER_INIT_CONFIG_DEFAULT();
|
||||||
|
config.a_gpio_number = GPIO_NUM_4;
|
||||||
|
config.b_gpio_number = GPIO_NUM_16;
|
||||||
|
config.encoder_min_value = -100;
|
||||||
|
config.encoder_max_value = 100;
|
||||||
|
config.encoder_step = 0.5;
|
||||||
|
config.encoder_number = 1;
|
||||||
|
esp_err_t ret = zh_encoder_init(&config, &encoder_handle);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Encoder initialization error: %s\n", esp_err_to_name(ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
float position = 25.0f;
|
||||||
|
ret = zh_encoder_set(&encoder_handle, position);
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Position set to %0.3f\n", position);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Error setting position: %s\n", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
float current = 0;
|
||||||
|
ret = zh_encoder_get(&encoder_handle, ¤t);
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Current position: %0.3f\n", current);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Error getting position: %s\n", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
ret = zh_encoder_reset(&encoder_handle);
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Position reset to midpoint\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Error resetting position: %s\n", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
zh_encoder_deinit(&encoder_handle);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reinit Range Example
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "zh_encoder.h"
|
||||||
|
|
||||||
|
zh_encoder_handle_t *encoder_handle = NULL;
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
esp_log_level_set("zh_encoder", ESP_LOG_ERROR);
|
||||||
|
zh_encoder_init_config_t config = ZH_ENCODER_INIT_CONFIG_DEFAULT();
|
||||||
|
config.a_gpio_number = GPIO_NUM_4;
|
||||||
|
config.b_gpio_number = GPIO_NUM_16;
|
||||||
|
config.encoder_min_value = -10;
|
||||||
|
config.encoder_max_value = 10;
|
||||||
|
config.encoder_step = 1;
|
||||||
|
config.encoder_number = 1;
|
||||||
|
esp_err_t ret = zh_encoder_init(&config, &encoder_handle);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Encoder initialization error: %s\n", esp_err_to_name(ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ret = zh_encoder_reinit(&encoder_handle, 0, 255, 1);
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Encoder range changed to 0..255\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Error reinitializing encoder: %s\n", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
float position = 0;
|
||||||
|
ret = zh_encoder_get(&encoder_handle, &position);
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Position after reinit: %0.3f\n", position);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Error getting position: %s\n", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
zh_encoder_deinit(&encoder_handle);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Button Event Example
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "zh_encoder.h"
|
||||||
|
|
||||||
|
zh_encoder_handle_t *encoder_handle = NULL;
|
||||||
|
|
||||||
void zh_encoder_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
void zh_encoder_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
||||||
{
|
{
|
||||||
(void)arg;
|
(void)arg;
|
||||||
switch (event_id)
|
(void)event_base;
|
||||||
|
if (event_id == ZH_BUTTON_EVENT)
|
||||||
{
|
{
|
||||||
case ZH_BUTTON_EVENT:
|
zh_encoder_button_event_on_isr_t *button_event = (zh_encoder_button_event_on_isr_t *)event_data;
|
||||||
zh_encoder_button_event_on_isr_t *button_event = event_data;
|
printf("Encoder %d button %s\n", button_event->encoder_number, button_event->button_status ? "released" : "pressed");
|
||||||
printf("Encoder number %d button was %s.\n", button_event->encoder_number, (button_event->button_status == true) ? "released" : "pressed");
|
}
|
||||||
break;
|
else if (event_id == ZH_ENCODER_EVENT)
|
||||||
case ZH_ENCODER_EVENT:
|
{
|
||||||
zh_encoder_event_on_isr_t *encoder_event = event_data;
|
zh_encoder_event_on_isr_t *encoder_event = (zh_encoder_event_on_isr_t *)event_data;
|
||||||
printf("Encoder number %d position %0.3f was %s.\n", encoder_event->encoder_number, encoder_event->encoder_position, (encoder_event->encoder_status == true) ? "increased" : "reduced");
|
printf("Encoder %d position %0.3f %s\n", encoder_event->encoder_number, encoder_event->encoder_position, encoder_event->encoder_status ? "increased" : "reduced");
|
||||||
break;
|
}
|
||||||
default:
|
}
|
||||||
break;
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
esp_log_level_set("zh_encoder", ESP_LOG_ERROR);
|
||||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(ZH_ENCODER, ESP_EVENT_ANY_ID, &zh_encoder_event_handler, NULL, NULL));
|
||||||
|
zh_encoder_init_config_t config = ZH_ENCODER_INIT_CONFIG_DEFAULT();
|
||||||
|
config.a_gpio_number = GPIO_NUM_4;
|
||||||
|
config.b_gpio_number = GPIO_NUM_16;
|
||||||
|
config.s_gpio_number = GPIO_NUM_15;
|
||||||
|
config.s_gpio_debounce_time = 50000;
|
||||||
|
config.encoder_min_value = 0;
|
||||||
|
config.encoder_max_value = 100;
|
||||||
|
config.encoder_step = 1;
|
||||||
|
config.encoder_number = 1;
|
||||||
|
esp_err_t ret = zh_encoder_init(&config, &encoder_handle);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Encoder initialization error: %s\n", esp_err_to_name(ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Error Statistics Example
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "zh_encoder.h"
|
||||||
|
|
||||||
|
zh_encoder_handle_t *encoder_handle = NULL;
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
esp_log_level_set("zh_encoder", ESP_LOG_ERROR);
|
||||||
|
zh_encoder_init_config_t config = ZH_ENCODER_INIT_CONFIG_DEFAULT();
|
||||||
|
config.a_gpio_number = GPIO_NUM_4;
|
||||||
|
config.b_gpio_number = GPIO_NUM_16;
|
||||||
|
config.encoder_min_value = -10;
|
||||||
|
config.encoder_max_value = 10;
|
||||||
|
config.encoder_step = 1;
|
||||||
|
config.encoder_number = 1;
|
||||||
|
esp_err_t ret = zh_encoder_init(&config, &encoder_handle);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Encoder initialization error: %s\n", esp_err_to_name(ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const zh_encoder_stats_t *stats = zh_encoder_get_stats();
|
||||||
|
printf("Event post errors: %lu\n", (unsigned long)stats->event_post_error);
|
||||||
|
printf("Queue overflow errors: %lu\n", (unsigned long)stats->queue_overflow_error);
|
||||||
|
printf("Minimum free stack: %lu\n", (unsigned long)stats->min_stack_size);
|
||||||
|
zh_encoder_reset_stats();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(60000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Reference in new issue
Block a user