Sin descripción
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /*
  2. * encoder.c
  3. *
  4. * Based on https://github.com/mathertel/RotaryEncoder/blob/master/src/RotaryEncoder.cpp
  5. *
  6. * Copyright (c) 2024 Thomas Buck (thomas@xythobuz.de)
  7. *
  8. * Copyright (c) by Matthias Hertel, http://www.mathertel.de
  9. * This work is licensed under a BSD 3-Clause style license
  10. * https://www.mathertel.de/License.aspx.
  11. */
  12. #include <stdio.h>
  13. #include "pico/stdlib.h"
  14. #include "main.h"
  15. #include "log.h"
  16. #include "encoder.h"
  17. #define LATCH0 0
  18. #define LATCH3 3
  19. #define FOUR3 1 // 4 steps, Latch at position 3 only (compatible to older versions)
  20. #define FOUR0 2 // 4 steps, Latch at position 0 (reverse wirings)
  21. #define TWO03 3 // 2 steps, Latch at position 0 and 3
  22. #define ENCODER_MODE FOUR3
  23. static const uint gpio_num_proto[2] = {
  24. 17, 18
  25. };
  26. static const uint gpio_num_v2[2] = {
  27. 19, 18
  28. };
  29. static const int8_t KNOBDIR[] = {
  30. 0, -1, 1, 0,
  31. 1, 0, 0, -1,
  32. -1, 0, 0, 1,
  33. 0, 1, -1, 0
  34. };
  35. static int8_t oldState;
  36. static int32_t position;
  37. static int32_t positionExt;
  38. static int32_t positionExtPrev;
  39. static uint32_t positionExtTime;
  40. static uint32_t positionExtTimePrev;
  41. void encoder_init(void) {
  42. for (uint i = 0; i < 2; i++) {
  43. if (hw_type == HW_PROTOTYPE) {
  44. gpio_init(gpio_num_proto[i]);
  45. gpio_set_dir(gpio_num_proto[i], GPIO_IN);
  46. gpio_pull_up(gpio_num_proto[i]);
  47. } else if (hw_type == HW_V2) {
  48. gpio_init(gpio_num_v2[i]);
  49. gpio_set_dir(gpio_num_v2[i], GPIO_IN);
  50. gpio_pull_up(gpio_num_v2[i]);
  51. }
  52. }
  53. if (hw_type == HW_PROTOTYPE) {
  54. oldState = gpio_get(gpio_num_proto[0]) | (gpio_get(gpio_num_proto[1]) << 1);
  55. } else if (hw_type == HW_V2) {
  56. oldState = gpio_get(gpio_num_v2[0]) | (gpio_get(gpio_num_v2[1]) << 1);
  57. }
  58. position = 0;
  59. positionExt = 0;
  60. positionExtPrev = 0;
  61. positionExtTime = 0;
  62. positionExtTimePrev = 0;
  63. }
  64. int32_t encoder_pos(void) {
  65. return positionExt;
  66. }
  67. // TODO should be adaptive depending on value range to be changed
  68. #define ENCODER_RPM_VALUE_FACTOR 100.0f
  69. int32_t encoder_get_diff(void) {
  70. int32_t diff = positionExt - positionExtPrev;
  71. positionExtPrev = positionExt;
  72. #ifdef ENCODER_RPM_VALUE_FACTOR
  73. if (diff != 0) {
  74. uint32_t rpm = encoder_get_rpm();
  75. float f = 1.0f + ((float)rpm / ENCODER_RPM_VALUE_FACTOR);
  76. //debug("diff=%"PRIi32" rpm=%"PRIu32" result=%.1f", diff, rpm, diff * f);
  77. return diff * f;
  78. }
  79. #endif
  80. return diff;
  81. }
  82. uint32_t encoder_get_rpm(void) {
  83. // calculate max of difference in time between last position changes or last change and now.
  84. uint32_t timeBetweenLastPositions = positionExtTime - positionExtTimePrev;
  85. uint32_t timeToLastPosition = to_ms_since_boot(get_absolute_time()) - positionExtTime;
  86. uint32_t t = MAX(timeBetweenLastPositions, timeToLastPosition);
  87. return (60.0f * 1000.0f) / ((float)(t * 20));
  88. }
  89. void encoder_run(void) {
  90. int8_t thisState = 0;
  91. if (hw_type == HW_PROTOTYPE) {
  92. thisState = gpio_get(gpio_num_proto[0]) | (gpio_get(gpio_num_proto[1]) << 1);
  93. } else if (hw_type == HW_V2) {
  94. thisState = gpio_get(gpio_num_v2[0]) | (gpio_get(gpio_num_v2[1]) << 1);
  95. }
  96. if (oldState != thisState) {
  97. position += KNOBDIR[thisState | (oldState << 2)];
  98. oldState = thisState;
  99. switch (ENCODER_MODE) {
  100. case FOUR3:
  101. if (thisState == LATCH3) {
  102. // The hardware has 4 steps with a latch on the input state 3
  103. positionExt = position >> 2;
  104. positionExt = -positionExt;
  105. positionExtTimePrev = positionExtTime;
  106. positionExtTime = to_ms_since_boot(get_absolute_time());
  107. }
  108. break;
  109. case FOUR0:
  110. if (thisState == LATCH0) {
  111. // The hardware has 4 steps with a latch on the input state 0
  112. positionExt = position >> 2;
  113. positionExt = -positionExt;
  114. positionExtTimePrev = positionExtTime;
  115. positionExtTime = to_ms_since_boot(get_absolute_time());
  116. }
  117. break;
  118. case TWO03:
  119. if ((thisState == LATCH0) || (thisState == LATCH3)) {
  120. // The hardware has 2 steps with a latch on the input state 0 and 3
  121. positionExt = position >> 1;
  122. positionExt = -positionExt;
  123. positionExtTimePrev = positionExtTime;
  124. positionExtTime = to_ms_since_boot(get_absolute_time());
  125. }
  126. break;
  127. }
  128. }
  129. }