Advertisement
skizziks_53

Optical Rotary Encoder v1

May 18th, 2018
220
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.19 KB | None | 0 0
  1. /*
  2.    18 May 2018
  3.    This sketch is to monitor a gray-code incremental rotary encoder with an Arduino board.
  4.    This sketch does not use interrupts; instead it lets you set a time interval in milliseconds to check the encoder.
  5.    It also does not use significant delay() statements, so that it allows other code to run in the time it is not active.
  6.  
  7.    Every time that the encoder state changes, a message giving the new encoder value is printed to the serial monitor window.
  8.  
  9.    For this example, the encoder used is gray code (incremental) 400 pulses-per-turn generic Chinese optical type.
  10.    The sketch is set to count from zero to 399, and to roll over both directions (above 399 goes back to zero, and less-than-zero goes to 399).
  11.  
  12.    The sketch will also work with HID (control panel) knob-type encoders as well. HID-type encoders are usually just mechanical switches.
  13.    Since HID encoders don't have nearly as many pulses per turn (maybe 36) and they are rotated by hand,
  14.    the monitoring interval can be set much longer than for a motor-style encoder.
  15.    Setting the monitoring interval to only 10 times a second is good enough.  
  16. */
  17.  
  18.  
  19.  
  20. int phaseA_pin = A2;
  21. int phaseB_pin = A3;
  22. // Incremental encoders have two output pins.
  23.  
  24. bool encoder_enable = true; // This is a flag that allows disabling the encoder checking when you don't need it to work.
  25. int encoder_minimum_value = 0; // This is the minimum value that you want the encoder to read.
  26. int encoder_maximum_value = 12; // This is the maximum value that you want the encoder to produce.
  27. // The optical / motor encoder that I used for the initial sketch was a 400-pulse-per-turn model, so I used 399 as the maximum.
  28. // You can set the maximum value to whatever you want though; it doesn't need to match the actual encoder's specs.
  29. // Since an incremental incoder only generates positive and negative pulses, it can count up or down to any value.
  30.  
  31. bool allow_high_rollover = true; // This is to control if the encoder is allowed to roll over from the maximum value back to the minimum value or not.
  32. bool allow_low_rollover = true; // This is to control if the encoder is allowed to roll over from less-than-minimum value back to the maximum value or not.
  33. // Note: this sketch uses the int type for the encoder value, that is limited to ~32K.
  34.  
  35. bool flip_encoder_directon = false; // This is a vairable that allows you to flip the direction (rotation) of the encoder values in code,
  36. //                                     without needing to change around the actual input pins.
  37.  
  38. int encoder_current_value = 0; // This is where the encoder value is stored. You can re-set this to any value you want, at any time.
  39.  
  40. int encoder_monitor_interval = 50; // This is the time in milliseconds to check the encoder pins.
  41. // For a HID-style (control panel) knob encoder you could set this to ~10 - 20 times a second and it would work perfectly fine.
  42. // ,,,,,,
  43. // For a motor-style encoder the sampling speed depends on the encoder resolution
  44. // and the maximum speed that the encoder is expected to be turning when you want to get its position.
  45. // For higher-speed sampling you would need to switch the millisecond timing to microsecond values,
  46. // and also get rid of the serial.print() statements on every value change,
  47. // since the serial messages would take long enough for the encoder to miss values.
  48.  
  49. unsigned long encoderCheck_previous_time = 0; // These two variables are for timing when to re-check the encoder pins.
  50. unsigned long encoderCheck_current_time = 0;
  51.  
  52. int phaseA_value = 0; // used for saving the pin states into.
  53. int phaseB_value = 0;
  54.  
  55. int encoder_previous_state = 1; // This is a number 1 to 4, indicating the condition of both pins.
  56. int encoder_current_state = 1;// This is a number 1 to 4, indicating the condition of both pins.
  57. // state #1: (A = low, B = low)
  58. // state #2: (A = high, B = low)
  59. // state #3: (A = high, B = high)
  60. // state #4: (A = low, B = high)
  61.  
  62.  
  63. // Function prototypes:
  64. int check_for_rollover(int); // This (optionally) re-sets the encoder value if it rolls over the top or bottom value.
  65. void display_encoder_value(); // This prints the encoder value to the serial monitor.
  66.  
  67.  
  68. void setup() {
  69.  
  70.   Serial.begin(57600); // Since the encoder value can change fast, it is advised to use a faster serial baud rate...
  71.  
  72.   pinMode(phaseA_pin, INPUT_PULLUP);
  73.   pinMode(phaseB_pin, INPUT_PULLUP);
  74.   /*
  75.      For the optical motor encoders that use open-collector output lines,
  76.      you can either use a separate voltage source with a 50K - 200K resistor to pull them up to the pin voltage,
  77.      or you can use the Arduino's INPUT_PULLUP pinmode.
  78.   */
  79.  
  80.   Serial.println("[OK] exiting setup.");
  81. }
  82.  
  83.  
  84. void loop() {
  85.  
  86.   if (encoder_enable) {
  87.     // The encoder is only checked if it is enabled.
  88.     encoderCheck_current_time = millis();
  89.     if (encoderCheck_current_time > encoderCheck_previous_time) {
  90.       // The encoder is only checked at the specified time interval.
  91.       if (encoderCheck_current_time >= (encoderCheck_previous_time + encoder_monitor_interval)) {
  92.         encoder_current_state = get_phase_state();
  93.         if (encoder_current_state != encoder_previous_state) {
  94.           // The encoder is only updated if the current state is different than the last known state.
  95.           if (encoder_current_state == 4) {
  96.             if (encoder_previous_state == 3) {
  97.               // encoder turning foward
  98.               if (flip_encoder_directon) {
  99.                 encoder_current_value--;
  100.               }
  101.               else {
  102.                 encoder_current_value++;
  103.               }
  104.               encoder_current_value = check_for_rollover(encoder_current_value);
  105.               encoder_previous_state = encoder_current_state;
  106.             }
  107.             else if (encoder_previous_state == 1) {
  108.               // encoder turning backward
  109.               if (flip_encoder_directon) {
  110.                 encoder_current_value++;
  111.               }
  112.               else {
  113.                 encoder_current_value--;
  114.               }
  115.               encoder_current_value = check_for_rollover(encoder_current_value);
  116.               encoder_previous_state = encoder_current_state;
  117.             }
  118.           }
  119.           else if (encoder_current_state == 1) {
  120.             if (encoder_previous_state == 4) {
  121.               // encoder turning foward
  122.               if (flip_encoder_directon) {
  123.                 encoder_current_value--;
  124.               }
  125.               else {
  126.                 encoder_current_value++;
  127.               }
  128.               encoder_current_value = check_for_rollover(encoder_current_value);
  129.               encoder_previous_state = encoder_current_state;
  130.             }
  131.             else if (encoder_previous_state == 2) {
  132.               // encoder turning backward
  133.               if (flip_encoder_directon) {
  134.                 encoder_current_value++;
  135.               }
  136.               else {
  137.                 encoder_current_value--;
  138.               }
  139.               encoder_current_value = check_for_rollover(encoder_current_value);
  140.               encoder_previous_state = encoder_current_state;
  141.             }
  142.           }
  143.           else {
  144.             if (encoder_current_state > encoder_previous_state) {
  145.               // encoder turning forward
  146.               if (flip_encoder_directon) {
  147.                 encoder_current_value--;
  148.               }
  149.               else {
  150.                 encoder_current_value++;
  151.               }
  152.               encoder_current_value = check_for_rollover(encoder_current_value);
  153.               encoder_previous_state = encoder_current_state;
  154.             }
  155.             else {
  156.               // encoder turning backward
  157.               if (flip_encoder_directon) {
  158.                 encoder_current_value++;
  159.               }
  160.               else {
  161.                 encoder_current_value--;
  162.               }
  163.               encoder_current_value = check_for_rollover(encoder_current_value);
  164.               encoder_previous_state = encoder_current_state;
  165.             }
  166.           }
  167.           display_encoder_value();
  168.         }
  169.         encoderCheck_previous_time = millis(); // reset the timer to check again.
  170.       }
  171.     }
  172.     else {
  173.       // If the millis() clock has rolled over, this line is to make sure that it will keep working normally
  174.       // by re-setting the encoderCheck_previous_time() again.
  175.       encoderCheck_previous_time = millis(); // millis() rollover condition.
  176.     }
  177.   }
  178.  
  179.  
  180. } // end of main program loop()
  181.  
  182.  
  183.  
  184. int get_phase_state() {
  185.   phaseA_value = digitalRead(phaseA_pin);
  186.   delayMicroseconds(100);
  187.   phaseA_value = digitalRead(phaseA_pin);
  188.   phaseB_value = digitalRead(phaseB_pin);
  189.   delayMicroseconds(100);
  190.   phaseB_value = digitalRead(phaseB_pin);
  191.   if (phaseA_value) {
  192.     if (phaseB_value) {
  193.       return 3;
  194.     }
  195.     else {
  196.       return 2;
  197.     }
  198.   }
  199.   else {
  200.     if (phaseB_value) {
  201.       return 4;
  202.     }
  203.     else {
  204.       return 1;
  205.     }
  206.   }
  207. }
  208.  
  209.  
  210.  
  211. int check_for_rollover(int currentValue) {
  212.   // This function checks for rollover values and resets the encoder value as needed.
  213.   int checkedValue = 0;
  214.   if (currentValue == (encoder_minimum_value - 1)) {
  215.     // if the encoder value is {less than the minimum value}:
  216.     if (allow_low_rollover == true) {
  217.       // and you want it to reset to the maximum value:
  218.       checkedValue = encoder_maximum_value;
  219.     }
  220.     else {
  221.       // If you dont want it to reset, then leave it as it is (this will allow values below the stated minimum).
  222.       checkedValue = currentValue;
  223.     }
  224.   }
  225.   else if (currentValue == (encoder_maximum_value + 1)) {
  226.     // If the encoder value is {over the maximum value}:
  227.     if (allow_high_rollover == true) {
  228.       // and you want it to reset to the minimum value:
  229.       checkedValue = encoder_minimum_value;
  230.     }
  231.     else {
  232.       // If you dont want it to reset, then leave it as it is (this will allow values above the stated maximum).
  233.       checkedValue = currentValue;
  234.     }
  235.   }
  236.   else {
  237.     // If the current encoder value is not over the maximum or under the minimum,
  238.     // then leave it as the same value because there is no reason to change it:
  239.     checkedValue = currentValue;
  240.   }
  241.   return checkedValue;
  242. }
  243.  
  244.  
  245.  
  246. void display_encoder_value() {
  247.   Serial.print("end value = ");
  248.   Serial.println(encoder_current_value);
  249. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement