エンコーダー拡張
前回作ったパルスカウンタは低速では特に問題ないのですが、高速では取りこぼしが有るようです。
カウントの取りこぼしは無いようですが、時々出力値が乱れます(対策を考え中)
#include "driver/pcnt.h"
#define PULSE_INPUT_PIN_X 4 //パルスの入力ピン 今回はエンコーダのA相を接続
#define PULSE_CTRL_PIN_X 2 //制御ピン 今回はエンコーダのB相を接続
#define PULSE_INPUT_PIN_Y 35 //パルスの入力ピン 今回はエンコーダのA相を接続
#define PULSE_CTRL_PIN_Y 34 //制御ピン 今回はエンコーダのB相を接続
#define PULSE_INPUT_PIN_Z 36 //パルスの入力ピン 今回はエンコーダのA相を接続
#define PULSE_CTRL_PIN_Z 39 //制御ピン 今回はエンコーダのB相を接続
#define PCNT_H_LIM_VAL 30000 //カウンタの上限
#define PCNT_L_LIM_VAL -30000 //カウンタの下限
int16_t count_x; //カウント数
int16_t count_y; //カウント数
int16_t count_z; //カウント数
int32_t prev_count_x = 0;
int32_t current_count_x = 0;
int32_t overflow_count_x = 0;
int32_t prev_count_y = 0;
int32_t current_count_y = 0;
int32_t overflow_count_y = 0;
int32_t prev_count_z = 0;
int32_t current_count_z = 0;
int32_t overflow_count_z = 0;
void ScaleInit_x() {
pcnt_config_t pcnt_config_x;//設定用の構造体の宣言
pcnt_config_x.pulse_gpio_num = PULSE_INPUT_PIN_X;
pcnt_config_x.ctrl_gpio_num = PULSE_CTRL_PIN_X;
pcnt_config_x.lctrl_mode = PCNT_MODE_REVERSE;
pcnt_config_x.hctrl_mode = PCNT_MODE_KEEP;
pcnt_config_x.channel = PCNT_CHANNEL_1;
pcnt_config_x.unit = PCNT_UNIT_2;
pcnt_config_x.pos_mode = PCNT_COUNT_INC;
pcnt_config_x.neg_mode = PCNT_COUNT_DEC;
pcnt_config_x.counter_h_lim = PCNT_H_LIM_VAL;
pcnt_config_x.counter_l_lim = PCNT_L_LIM_VAL;
pcnt_unit_config(&pcnt_config_x);//ユニット初期化
pcnt_counter_pause(PCNT_UNIT_2);//カウンタ一時停止
pcnt_counter_clear(PCNT_UNIT_2);//カウンタ初期化
pcnt_counter_resume(PCNT_UNIT_2);//カウント開始
}
void ScaleInit_y() {
pcnt_config_t pcnt_config_y;//設定用の構造体の宣言
pcnt_config_y.pulse_gpio_num = PULSE_INPUT_PIN_Y;
pcnt_config_y.ctrl_gpio_num = PULSE_CTRL_PIN_Y;
pcnt_config_y.lctrl_mode = PCNT_MODE_REVERSE;
pcnt_config_y.hctrl_mode = PCNT_MODE_KEEP;
pcnt_config_y.channel = PCNT_CHANNEL_1;
pcnt_config_y.unit = PCNT_UNIT_3;
pcnt_config_y.pos_mode = PCNT_COUNT_INC;
pcnt_config_y.neg_mode = PCNT_COUNT_DEC;
pcnt_config_y.counter_h_lim = PCNT_H_LIM_VAL;
pcnt_config_y.counter_l_lim = PCNT_L_LIM_VAL;
pcnt_unit_config(&pcnt_config_y);//ユニット初期化
pcnt_counter_pause(PCNT_UNIT_3);//カウンタ一時停止
pcnt_counter_clear(PCNT_UNIT_3);//カウンタ初期化
pcnt_counter_resume(PCNT_UNIT_3);//カウント開始
}
void ScaleInit_z() {
pcnt_config_t pcnt_config_z;//設定用の構造体の宣言
pcnt_config_z.pulse_gpio_num = PULSE_INPUT_PIN_Z;
pcnt_config_z.ctrl_gpio_num = PULSE_CTRL_PIN_Z;
pcnt_config_z.lctrl_mode = PCNT_MODE_REVERSE;
pcnt_config_z.hctrl_mode = PCNT_MODE_KEEP;
pcnt_config_z.channel = PCNT_CHANNEL_1;
pcnt_config_z.unit = PCNT_UNIT_4;
pcnt_config_z.pos_mode = PCNT_COUNT_INC;
pcnt_config_z.neg_mode = PCNT_COUNT_DEC;
pcnt_config_z.counter_h_lim = PCNT_H_LIM_VAL;
pcnt_config_z.counter_l_lim = PCNT_L_LIM_VAL;
pcnt_unit_config(&pcnt_config_z);//ユニット初期化
pcnt_counter_pause(PCNT_UNIT_4);//カウンタ一時停止
pcnt_counter_clear(PCNT_UNIT_4);//カウンタ初期化
pcnt_counter_resume(PCNT_UNIT_4);//カウント開始
}
void CountReset_x(void) {
ScaleInit_x();
overflow_count_x = 0;
prev_count_x = 0;
}
void CountReset_y(void) {
ScaleInit_y();
overflow_count_y = 0;
prev_count_y = 0;
}
void CountReset_z(void) {
ScaleInit_z();
overflow_count_z = 0;
prev_count_z = 0;
}
int ret_count_x(void) {
char i;
pcnt_get_counter_value(PCNT_UNIT_2, &count_x);
current_count_x = (int32_t)count_x;
if ((abs(prev_count_x) - abs(current_count_x)) > PCNT_H_LIM_VAL / 2 ) {
if (current_count_x < prev_count_x) {
overflow_count_x++;
i = 1;
} else {
overflow_count_x--;
i = -1;
}
}
prev_count_x = current_count_x;
return int32_t((current_count_x + overflow_count_x * (int32_t(PCNT_H_LIM_VAL + i))) * (int32_t)2);
}
int32_t ret_count_y(void) {
char i;
pcnt_get_counter_value(PCNT_UNIT_3, &count_y);
current_count_y = (int32_t)count_y;
if ((abs(prev_count_y) - abs(current_count_y)) > PCNT_H_LIM_VAL / 2 ) {
if (current_count_y < prev_count_y) {
overflow_count_y++;
i = 1;
} else {
overflow_count_y--;
i = -1;
}
}
prev_count_y = current_count_y;
return int32_t((current_count_y + overflow_count_y * (int32_t(PCNT_H_LIM_VAL + i))) * (int32_t)2);
}
int ret_count_z(void) {
char i;
pcnt_get_counter_value(PCNT_UNIT_4, &count_z);
current_count_z = (int32_t)count_z;
if ((abs(prev_count_z) - abs(current_count_z)) > PCNT_H_LIM_VAL / 2 ) {
if (current_count_z < prev_count_z) {
overflow_count_z++;
i = 1;
} else {
overflow_count_z--;
i = -1;
}
}
prev_count_z = current_count_z;
return int32_t((current_count_z + overflow_count_z * (int32_t(PCNT_H_LIM_VAL + i))) * (int32_t)2);
}
void setup() {
//エンコーダー初期化
ScaleInit_x();
ScaleInit_y();
ScaleInit_z();
Serial.begin(115200);
}
//エンコーダーカウント値を出力
Serial.printf("S:%10d:%10d:%10d:\n", (int)ret_count_x(),(int)ret_count_y(), (int)ret_count_z() / 5);
//エンコーダーカウントリセット
if (###) {//ボタンやシリアル通信からのリセット条件
CountReset_x();
}
if (###) {
CountReset_y();
}
if (####) {
CountReset_z();
}
}
こちらの記事を参考にほぼコピーしています。