De-bouncing a (Gray) Rotary Encoder Switch in C












1












$begingroup$


I would like feedback on the correctness and performance of this code.



My priorities are also are readability, simplicity and self-documenting code - but I'm happy with those as they are.



I know I've used C pretty poorly as far as factoring out common code between the two input lines - but I'm brushing up my C and will do that.



RA2 and RA3 are the two digital input lines. My algorithm is not dissimilar to how debouncing would be done with a low pass capacitor and resistor followed by a schmitt trigger. This function is called by the ISR every 0.5ms, and the rotary switch produces transitions as short as 5-10ms.



I am curious how to deal with situations where the rotary switch is turned a bit faster than the algorithm can process. Can further information be deduced from the Gray encoding, even when a step is missed because of the low pass delay and limited sample rate? I suppose this could be taken as far as using neural networks?!



I'm mainly asking this question because I think the running time and the amount of code of the below can both be reduced by a factor of two at least. And I'd just prefer not to get out the logic analyzer and completely reinvent the wheel.



rotsw.h



#define ROTSW_AVG_SIZE 8
#define ROTSW_MAX 7
#define ROTSW_UPPER 5
#define ROTSW_LOWER 2
#define ROTSW_MIN 0

void rotsw_sample_avg_schmitt_count();

extern volatile int rotsw_count_steps;


rotsw.c



unsigned int rotsw_samples[ROTSW_AVG_SIZE];
unsigned char rotsw_write_idx = 0;

int rotsw_avg_ra2 = 0;
int rotsw_avg_ra3 = 0;

int ra2 = 0;
int ra3 = 0;

volatile int rotsw_count = 0;

void rotsw_sample_avg_schmitt_count()
{
int sample, old_sample, ra2_changed, ra3_changed, count = rotsw_count;

// Sample RA2 and RA3
old_sample = rotsw_samples[rotsw_write_idx];
rotsw_samples[rotsw_write_idx] = sample = PORTA & 0b00001100;
if (++rotsw_write_idx >= ROTSW_AVG_SIZE) rotsw_write_idx = 0;

// Moving average, turning digital sample to "analogue"
if (old_sample & 0x04) rotsw_avg_ra2--;
if (old_sample & 0x08) rotsw_avg_ra3--;
if (sample & 0x04) rotsw_avg_ra2++;
if (sample & 0x08) rotsw_avg_ra3++;

// 3. Do limit for Schmitt trigger
if (rotsw_avg_ra2 < ROTSW_MIN) rotsw_avg_ra2 = ROTSW_MIN;
else if (rotsw_avg_ra2 > ROTSW_MAX) rotsw_avg_ra2 = ROTSW_MAX;
if (rotsw_avg_ra3 < ROTSW_MIN) rotsw_avg_ra3 = ROTSW_MIN;
else if (rotsw_avg_ra3 > ROTSW_MAX) rotsw_avg_ra3 = ROTSW_MAX;

// Do Schmitt trigger
if (rotsw_avg_ra2 > ROTSW_UPPER){
ra2_changed = !ra2;
ra2 = 1;
} else if (rotsw_avg_ra2 < ROTSW_LOWER){
ra2_changed = ra2;
ra2 = 0;
}
if (rotsw_avg_ra3 > ROTSW_UPPER){
ra3_changed = !ra3;
ra3 = 1;
} else if (rotsw_avg_ra3 < ROTSW_LOWER){
ra3_changed = ra3;
ra3 = 0;
}

// Do rotsw state change count.
if (ra2_changed){
if (ra2 == ra3) count++;
else count--;
}
if (ra3_changed){
if(ra2 == ra3) count--;
else count++;
}
rotsw_count = count;
}









share|improve this question











$endgroup$

















    1












    $begingroup$


    I would like feedback on the correctness and performance of this code.



    My priorities are also are readability, simplicity and self-documenting code - but I'm happy with those as they are.



    I know I've used C pretty poorly as far as factoring out common code between the two input lines - but I'm brushing up my C and will do that.



    RA2 and RA3 are the two digital input lines. My algorithm is not dissimilar to how debouncing would be done with a low pass capacitor and resistor followed by a schmitt trigger. This function is called by the ISR every 0.5ms, and the rotary switch produces transitions as short as 5-10ms.



    I am curious how to deal with situations where the rotary switch is turned a bit faster than the algorithm can process. Can further information be deduced from the Gray encoding, even when a step is missed because of the low pass delay and limited sample rate? I suppose this could be taken as far as using neural networks?!



    I'm mainly asking this question because I think the running time and the amount of code of the below can both be reduced by a factor of two at least. And I'd just prefer not to get out the logic analyzer and completely reinvent the wheel.



    rotsw.h



    #define ROTSW_AVG_SIZE 8
    #define ROTSW_MAX 7
    #define ROTSW_UPPER 5
    #define ROTSW_LOWER 2
    #define ROTSW_MIN 0

    void rotsw_sample_avg_schmitt_count();

    extern volatile int rotsw_count_steps;


    rotsw.c



    unsigned int rotsw_samples[ROTSW_AVG_SIZE];
    unsigned char rotsw_write_idx = 0;

    int rotsw_avg_ra2 = 0;
    int rotsw_avg_ra3 = 0;

    int ra2 = 0;
    int ra3 = 0;

    volatile int rotsw_count = 0;

    void rotsw_sample_avg_schmitt_count()
    {
    int sample, old_sample, ra2_changed, ra3_changed, count = rotsw_count;

    // Sample RA2 and RA3
    old_sample = rotsw_samples[rotsw_write_idx];
    rotsw_samples[rotsw_write_idx] = sample = PORTA & 0b00001100;
    if (++rotsw_write_idx >= ROTSW_AVG_SIZE) rotsw_write_idx = 0;

    // Moving average, turning digital sample to "analogue"
    if (old_sample & 0x04) rotsw_avg_ra2--;
    if (old_sample & 0x08) rotsw_avg_ra3--;
    if (sample & 0x04) rotsw_avg_ra2++;
    if (sample & 0x08) rotsw_avg_ra3++;

    // 3. Do limit for Schmitt trigger
    if (rotsw_avg_ra2 < ROTSW_MIN) rotsw_avg_ra2 = ROTSW_MIN;
    else if (rotsw_avg_ra2 > ROTSW_MAX) rotsw_avg_ra2 = ROTSW_MAX;
    if (rotsw_avg_ra3 < ROTSW_MIN) rotsw_avg_ra3 = ROTSW_MIN;
    else if (rotsw_avg_ra3 > ROTSW_MAX) rotsw_avg_ra3 = ROTSW_MAX;

    // Do Schmitt trigger
    if (rotsw_avg_ra2 > ROTSW_UPPER){
    ra2_changed = !ra2;
    ra2 = 1;
    } else if (rotsw_avg_ra2 < ROTSW_LOWER){
    ra2_changed = ra2;
    ra2 = 0;
    }
    if (rotsw_avg_ra3 > ROTSW_UPPER){
    ra3_changed = !ra3;
    ra3 = 1;
    } else if (rotsw_avg_ra3 < ROTSW_LOWER){
    ra3_changed = ra3;
    ra3 = 0;
    }

    // Do rotsw state change count.
    if (ra2_changed){
    if (ra2 == ra3) count++;
    else count--;
    }
    if (ra3_changed){
    if(ra2 == ra3) count--;
    else count++;
    }
    rotsw_count = count;
    }









    share|improve this question











    $endgroup$















      1












      1








      1





      $begingroup$


      I would like feedback on the correctness and performance of this code.



      My priorities are also are readability, simplicity and self-documenting code - but I'm happy with those as they are.



      I know I've used C pretty poorly as far as factoring out common code between the two input lines - but I'm brushing up my C and will do that.



      RA2 and RA3 are the two digital input lines. My algorithm is not dissimilar to how debouncing would be done with a low pass capacitor and resistor followed by a schmitt trigger. This function is called by the ISR every 0.5ms, and the rotary switch produces transitions as short as 5-10ms.



      I am curious how to deal with situations where the rotary switch is turned a bit faster than the algorithm can process. Can further information be deduced from the Gray encoding, even when a step is missed because of the low pass delay and limited sample rate? I suppose this could be taken as far as using neural networks?!



      I'm mainly asking this question because I think the running time and the amount of code of the below can both be reduced by a factor of two at least. And I'd just prefer not to get out the logic analyzer and completely reinvent the wheel.



      rotsw.h



      #define ROTSW_AVG_SIZE 8
      #define ROTSW_MAX 7
      #define ROTSW_UPPER 5
      #define ROTSW_LOWER 2
      #define ROTSW_MIN 0

      void rotsw_sample_avg_schmitt_count();

      extern volatile int rotsw_count_steps;


      rotsw.c



      unsigned int rotsw_samples[ROTSW_AVG_SIZE];
      unsigned char rotsw_write_idx = 0;

      int rotsw_avg_ra2 = 0;
      int rotsw_avg_ra3 = 0;

      int ra2 = 0;
      int ra3 = 0;

      volatile int rotsw_count = 0;

      void rotsw_sample_avg_schmitt_count()
      {
      int sample, old_sample, ra2_changed, ra3_changed, count = rotsw_count;

      // Sample RA2 and RA3
      old_sample = rotsw_samples[rotsw_write_idx];
      rotsw_samples[rotsw_write_idx] = sample = PORTA & 0b00001100;
      if (++rotsw_write_idx >= ROTSW_AVG_SIZE) rotsw_write_idx = 0;

      // Moving average, turning digital sample to "analogue"
      if (old_sample & 0x04) rotsw_avg_ra2--;
      if (old_sample & 0x08) rotsw_avg_ra3--;
      if (sample & 0x04) rotsw_avg_ra2++;
      if (sample & 0x08) rotsw_avg_ra3++;

      // 3. Do limit for Schmitt trigger
      if (rotsw_avg_ra2 < ROTSW_MIN) rotsw_avg_ra2 = ROTSW_MIN;
      else if (rotsw_avg_ra2 > ROTSW_MAX) rotsw_avg_ra2 = ROTSW_MAX;
      if (rotsw_avg_ra3 < ROTSW_MIN) rotsw_avg_ra3 = ROTSW_MIN;
      else if (rotsw_avg_ra3 > ROTSW_MAX) rotsw_avg_ra3 = ROTSW_MAX;

      // Do Schmitt trigger
      if (rotsw_avg_ra2 > ROTSW_UPPER){
      ra2_changed = !ra2;
      ra2 = 1;
      } else if (rotsw_avg_ra2 < ROTSW_LOWER){
      ra2_changed = ra2;
      ra2 = 0;
      }
      if (rotsw_avg_ra3 > ROTSW_UPPER){
      ra3_changed = !ra3;
      ra3 = 1;
      } else if (rotsw_avg_ra3 < ROTSW_LOWER){
      ra3_changed = ra3;
      ra3 = 0;
      }

      // Do rotsw state change count.
      if (ra2_changed){
      if (ra2 == ra3) count++;
      else count--;
      }
      if (ra3_changed){
      if(ra2 == ra3) count--;
      else count++;
      }
      rotsw_count = count;
      }









      share|improve this question











      $endgroup$




      I would like feedback on the correctness and performance of this code.



      My priorities are also are readability, simplicity and self-documenting code - but I'm happy with those as they are.



      I know I've used C pretty poorly as far as factoring out common code between the two input lines - but I'm brushing up my C and will do that.



      RA2 and RA3 are the two digital input lines. My algorithm is not dissimilar to how debouncing would be done with a low pass capacitor and resistor followed by a schmitt trigger. This function is called by the ISR every 0.5ms, and the rotary switch produces transitions as short as 5-10ms.



      I am curious how to deal with situations where the rotary switch is turned a bit faster than the algorithm can process. Can further information be deduced from the Gray encoding, even when a step is missed because of the low pass delay and limited sample rate? I suppose this could be taken as far as using neural networks?!



      I'm mainly asking this question because I think the running time and the amount of code of the below can both be reduced by a factor of two at least. And I'd just prefer not to get out the logic analyzer and completely reinvent the wheel.



      rotsw.h



      #define ROTSW_AVG_SIZE 8
      #define ROTSW_MAX 7
      #define ROTSW_UPPER 5
      #define ROTSW_LOWER 2
      #define ROTSW_MIN 0

      void rotsw_sample_avg_schmitt_count();

      extern volatile int rotsw_count_steps;


      rotsw.c



      unsigned int rotsw_samples[ROTSW_AVG_SIZE];
      unsigned char rotsw_write_idx = 0;

      int rotsw_avg_ra2 = 0;
      int rotsw_avg_ra3 = 0;

      int ra2 = 0;
      int ra3 = 0;

      volatile int rotsw_count = 0;

      void rotsw_sample_avg_schmitt_count()
      {
      int sample, old_sample, ra2_changed, ra3_changed, count = rotsw_count;

      // Sample RA2 and RA3
      old_sample = rotsw_samples[rotsw_write_idx];
      rotsw_samples[rotsw_write_idx] = sample = PORTA & 0b00001100;
      if (++rotsw_write_idx >= ROTSW_AVG_SIZE) rotsw_write_idx = 0;

      // Moving average, turning digital sample to "analogue"
      if (old_sample & 0x04) rotsw_avg_ra2--;
      if (old_sample & 0x08) rotsw_avg_ra3--;
      if (sample & 0x04) rotsw_avg_ra2++;
      if (sample & 0x08) rotsw_avg_ra3++;

      // 3. Do limit for Schmitt trigger
      if (rotsw_avg_ra2 < ROTSW_MIN) rotsw_avg_ra2 = ROTSW_MIN;
      else if (rotsw_avg_ra2 > ROTSW_MAX) rotsw_avg_ra2 = ROTSW_MAX;
      if (rotsw_avg_ra3 < ROTSW_MIN) rotsw_avg_ra3 = ROTSW_MIN;
      else if (rotsw_avg_ra3 > ROTSW_MAX) rotsw_avg_ra3 = ROTSW_MAX;

      // Do Schmitt trigger
      if (rotsw_avg_ra2 > ROTSW_UPPER){
      ra2_changed = !ra2;
      ra2 = 1;
      } else if (rotsw_avg_ra2 < ROTSW_LOWER){
      ra2_changed = ra2;
      ra2 = 0;
      }
      if (rotsw_avg_ra3 > ROTSW_UPPER){
      ra3_changed = !ra3;
      ra3 = 1;
      } else if (rotsw_avg_ra3 < ROTSW_LOWER){
      ra3_changed = ra3;
      ra3 = 0;
      }

      // Do rotsw state change count.
      if (ra2_changed){
      if (ra2 == ra3) count++;
      else count--;
      }
      if (ra3_changed){
      if(ra2 == ra3) count--;
      else count++;
      }
      rotsw_count = count;
      }






      performance algorithm c event-handling device-driver






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 13 mins ago







      CL22

















      asked 1 hour ago









      CL22CL22

      233110




      233110






















          0






          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213636%2fde-bouncing-a-gray-rotary-encoder-switch-in-c%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213636%2fde-bouncing-a-gray-rotary-encoder-switch-in-c%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Сан-Квентин

          8-я гвардейская общевойсковая армия

          Алькесар