How to boil down analog input to just three cases?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
1
down vote

favorite












I am investigating the use of a 3-position-switch of rone of my projects to switch between different settings using just one analog input pin. For the three positions I am using ground/0V, ~2.5V (via 2x10k voltage divider) and full 5V. I am doing this also because I am planning to use a 5-position rotary switch in a similar way in the future.



Due to tolerances and noise the readings on the analog pin of course are not precisely 0, 511, 1023, but rather 0-1, 509-512 and 1021-1023. To take this into account I am using the map function like this:



const byte alarmSwitchPin = A0;
int alrmSwState;
byte alrmSet;
byte alrmPrevSet;

void setup()
Serial.begin(9600);
pinMode(alarmSwitchPin, INPUT);



void loop()

alrmSwState = analogRead(alarmSwitchPin); // Read input

byte alrmSet = map(alrmSwState, 0, 1023, 0, 2); // Boil input down to three cases

if (alrmSet != alrmPrevSet) // Only if state of switch has changed
switch (alrmSet)
case 0:
Serial.println("Low");
break;
case 1:
Serial.println("Medium");
break;
case 2:
Serial.println("High");
break;

alrmPrevSet = alrmSet;
delay(200); // For testing purposes




I only want the setting to change (or, in this case, the console to print) when the state has actually changed. This does not work, though, because the map function is doing its math in integer, which fails in mapping the Hugh position (in this case).



What are my options if I want to stick with the switch method? I am curious if it is possible to get this done without if statements and conditions or, as a more general question, what the best option is to properly map the 10 bit analog input to just 3 cases/numbers.



PS: I thought analogReadResolution() might be an option but I am working with Arduino UNO where this is unavailable.










share|improve this question



















  • 1




    Solve it with the analog value, not with the map function. The tilting points are at 256 and 768. Below 256 is 0, between 256 and 768 is 1 and above 768 is 2.
    – Jot
    8 hours ago










  • You have chosen a tricky method. Likely you will need to use both hysteresis and averaging. Averaging will slow down the response - no matter how fast the processor is. If dead set on using a rotary input device, most would choose a rotary encoder which is digital in nature.
    – st2000
    8 hours ago










  • map will do alrmSwState/512, returning 2 only for 1023
    – Juraj
    7 hours ago














up vote
1
down vote

favorite












I am investigating the use of a 3-position-switch of rone of my projects to switch between different settings using just one analog input pin. For the three positions I am using ground/0V, ~2.5V (via 2x10k voltage divider) and full 5V. I am doing this also because I am planning to use a 5-position rotary switch in a similar way in the future.



Due to tolerances and noise the readings on the analog pin of course are not precisely 0, 511, 1023, but rather 0-1, 509-512 and 1021-1023. To take this into account I am using the map function like this:



const byte alarmSwitchPin = A0;
int alrmSwState;
byte alrmSet;
byte alrmPrevSet;

void setup()
Serial.begin(9600);
pinMode(alarmSwitchPin, INPUT);



void loop()

alrmSwState = analogRead(alarmSwitchPin); // Read input

byte alrmSet = map(alrmSwState, 0, 1023, 0, 2); // Boil input down to three cases

if (alrmSet != alrmPrevSet) // Only if state of switch has changed
switch (alrmSet)
case 0:
Serial.println("Low");
break;
case 1:
Serial.println("Medium");
break;
case 2:
Serial.println("High");
break;

alrmPrevSet = alrmSet;
delay(200); // For testing purposes




I only want the setting to change (or, in this case, the console to print) when the state has actually changed. This does not work, though, because the map function is doing its math in integer, which fails in mapping the Hugh position (in this case).



What are my options if I want to stick with the switch method? I am curious if it is possible to get this done without if statements and conditions or, as a more general question, what the best option is to properly map the 10 bit analog input to just 3 cases/numbers.



PS: I thought analogReadResolution() might be an option but I am working with Arduino UNO where this is unavailable.










share|improve this question



















  • 1




    Solve it with the analog value, not with the map function. The tilting points are at 256 and 768. Below 256 is 0, between 256 and 768 is 1 and above 768 is 2.
    – Jot
    8 hours ago










  • You have chosen a tricky method. Likely you will need to use both hysteresis and averaging. Averaging will slow down the response - no matter how fast the processor is. If dead set on using a rotary input device, most would choose a rotary encoder which is digital in nature.
    – st2000
    8 hours ago










  • map will do alrmSwState/512, returning 2 only for 1023
    – Juraj
    7 hours ago












up vote
1
down vote

favorite









up vote
1
down vote

favorite











I am investigating the use of a 3-position-switch of rone of my projects to switch between different settings using just one analog input pin. For the three positions I am using ground/0V, ~2.5V (via 2x10k voltage divider) and full 5V. I am doing this also because I am planning to use a 5-position rotary switch in a similar way in the future.



Due to tolerances and noise the readings on the analog pin of course are not precisely 0, 511, 1023, but rather 0-1, 509-512 and 1021-1023. To take this into account I am using the map function like this:



const byte alarmSwitchPin = A0;
int alrmSwState;
byte alrmSet;
byte alrmPrevSet;

void setup()
Serial.begin(9600);
pinMode(alarmSwitchPin, INPUT);



void loop()

alrmSwState = analogRead(alarmSwitchPin); // Read input

byte alrmSet = map(alrmSwState, 0, 1023, 0, 2); // Boil input down to three cases

if (alrmSet != alrmPrevSet) // Only if state of switch has changed
switch (alrmSet)
case 0:
Serial.println("Low");
break;
case 1:
Serial.println("Medium");
break;
case 2:
Serial.println("High");
break;

alrmPrevSet = alrmSet;
delay(200); // For testing purposes




I only want the setting to change (or, in this case, the console to print) when the state has actually changed. This does not work, though, because the map function is doing its math in integer, which fails in mapping the Hugh position (in this case).



What are my options if I want to stick with the switch method? I am curious if it is possible to get this done without if statements and conditions or, as a more general question, what the best option is to properly map the 10 bit analog input to just 3 cases/numbers.



PS: I thought analogReadResolution() might be an option but I am working with Arduino UNO where this is unavailable.










share|improve this question















I am investigating the use of a 3-position-switch of rone of my projects to switch between different settings using just one analog input pin. For the three positions I am using ground/0V, ~2.5V (via 2x10k voltage divider) and full 5V. I am doing this also because I am planning to use a 5-position rotary switch in a similar way in the future.



Due to tolerances and noise the readings on the analog pin of course are not precisely 0, 511, 1023, but rather 0-1, 509-512 and 1021-1023. To take this into account I am using the map function like this:



const byte alarmSwitchPin = A0;
int alrmSwState;
byte alrmSet;
byte alrmPrevSet;

void setup()
Serial.begin(9600);
pinMode(alarmSwitchPin, INPUT);



void loop()

alrmSwState = analogRead(alarmSwitchPin); // Read input

byte alrmSet = map(alrmSwState, 0, 1023, 0, 2); // Boil input down to three cases

if (alrmSet != alrmPrevSet) // Only if state of switch has changed
switch (alrmSet)
case 0:
Serial.println("Low");
break;
case 1:
Serial.println("Medium");
break;
case 2:
Serial.println("High");
break;

alrmPrevSet = alrmSet;
delay(200); // For testing purposes




I only want the setting to change (or, in this case, the console to print) when the state has actually changed. This does not work, though, because the map function is doing its math in integer, which fails in mapping the Hugh position (in this case).



What are my options if I want to stick with the switch method? I am curious if it is possible to get this done without if statements and conditions or, as a more general question, what the best option is to properly map the 10 bit analog input to just 3 cases/numbers.



PS: I thought analogReadResolution() might be an option but I am working with Arduino UNO where this is unavailable.







analogread switch map






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 8 hours ago

























asked 8 hours ago









fertchen

155




155







  • 1




    Solve it with the analog value, not with the map function. The tilting points are at 256 and 768. Below 256 is 0, between 256 and 768 is 1 and above 768 is 2.
    – Jot
    8 hours ago










  • You have chosen a tricky method. Likely you will need to use both hysteresis and averaging. Averaging will slow down the response - no matter how fast the processor is. If dead set on using a rotary input device, most would choose a rotary encoder which is digital in nature.
    – st2000
    8 hours ago










  • map will do alrmSwState/512, returning 2 only for 1023
    – Juraj
    7 hours ago












  • 1




    Solve it with the analog value, not with the map function. The tilting points are at 256 and 768. Below 256 is 0, between 256 and 768 is 1 and above 768 is 2.
    – Jot
    8 hours ago










  • You have chosen a tricky method. Likely you will need to use both hysteresis and averaging. Averaging will slow down the response - no matter how fast the processor is. If dead set on using a rotary input device, most would choose a rotary encoder which is digital in nature.
    – st2000
    8 hours ago










  • map will do alrmSwState/512, returning 2 only for 1023
    – Juraj
    7 hours ago







1




1




Solve it with the analog value, not with the map function. The tilting points are at 256 and 768. Below 256 is 0, between 256 and 768 is 1 and above 768 is 2.
– Jot
8 hours ago




Solve it with the analog value, not with the map function. The tilting points are at 256 and 768. Below 256 is 0, between 256 and 768 is 1 and above 768 is 2.
– Jot
8 hours ago












You have chosen a tricky method. Likely you will need to use both hysteresis and averaging. Averaging will slow down the response - no matter how fast the processor is. If dead set on using a rotary input device, most would choose a rotary encoder which is digital in nature.
– st2000
8 hours ago




You have chosen a tricky method. Likely you will need to use both hysteresis and averaging. Averaging will slow down the response - no matter how fast the processor is. If dead set on using a rotary input device, most would choose a rotary encoder which is digital in nature.
– st2000
8 hours ago












map will do alrmSwState/512, returning 2 only for 1023
– Juraj
7 hours ago




map will do alrmSwState/512, returning 2 only for 1023
– Juraj
7 hours ago










3 Answers
3






active

oldest

votes

















up vote
2
down vote













Replace the line:



byte alrmSet = map(alrmSwState, 0, 1023, 0, 2);



with



byte alrmSet = alrmSwState / 342;



And this should do what you want. Note that in C fractional results are truncated (not rounded)






share|improve this answer








New contributor




Jeff Wahaus is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

















  • this is wrong. it will give 3, 2, 1, 0
    – Juraj
    7 hours ago










  • It is correct. The max value returned is 1023 when divided by 342 = 2.991... which will give the integer division result of 2.
    – Jeff Wahaus
    7 hours ago










  • sorry, I forgot that Calc rounds to the nearest. I upvoted
    – Juraj
    7 hours ago











  • and map will do alrmSwState/512 which is not correct
    – Juraj
    7 hours ago










  • Why 342 and not 343? I like to see comments in the code that explains all the numbers.
    – Jot
    4 hours ago

















up vote
2
down vote













The simplest fix to your problem is to change the map() call to





byte alrmSet = map(alrmSwState, 0, 1024, 0, 3);


In the call above, the mapped intervals are of the semi-open type, e.g.
[a, b), where the start values (namely 0) are understood as being
inclusive and the end values (1024 and 3) are exclusive.



Although not clear from the documentation, this is the proper way to use
the map() function. Otherwise, the truncated division gives you very
uneven intervals. Compare:



 x map(x, 0, 1023, 0, 2)
----------------------------------
0 – 511 0
512 – 1022 1
1023 2

x map(x, 0, 1024, 0, 3)
----------------------------------
0 – 341 0
342 – 682 1
683 – 1023 2


The result you get is very close to Jeff Wahaus’ answer.



What I find annoying about this approach is that a 32-bit integer
division, which map() uses internally, is a very expensive operation
on the small 8-bit Arduinos. If instead of 342 and 683, you use 256 and
768 as thresholds, then you can make the decision by just looking at the
high byte of the analog reading:



uint16_t alrmSwState = analogRead(alarmSwitchPin);

alrmSet = alrmSwState / 256;

if (alrmSet != alrmPrevSet)
switch (alrmSet)
case 0:
Serial.println("Low");
break;
case 1:
case 2:
Serial.println("Medium");
break;
case 3:
Serial.println("High");
break;

alrmPrevSet = alrmSet;
delay(200);



Note that the division by 256 is optimized by the compiler into a much
cheaper bit shift, but this is the case only if alrmSwState is of an
unsigned integer type. That's why it is declared above as uint16_t.






share|improve this answer



























    up vote
    0
    down vote













    You might also consider reading the value several times and summing them, then base your decision on the sum.



    This is equivalent to averaging the values but without dividing by 'n', since you don't care about the actual number, just the band it falls into. This will have the effect of improving the signal to noise ratio, since we assume that high-reading errors are as likely as low-reading errors, so their sum tends toward zero as the sum of the real value, V, tends toward (n*V).



    Use an int or larger variable for the sum, depending on how many readings you choose to take each time.






    share|improve this answer




















      Your Answer





      StackExchange.ifUsing("editor", function ()
      return StackExchange.using("schematics", function ()
      StackExchange.schematics.init();
      );
      , "cicuitlab");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "540"
      ;
      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',
      convertImagesToLinks: false,
      noModals: false,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













       

      draft saved


      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2farduino.stackexchange.com%2fquestions%2f57284%2fhow-to-boil-down-analog-input-to-just-three-cases%23new-answer', 'question_page');

      );

      Post as a guest






























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      2
      down vote













      Replace the line:



      byte alrmSet = map(alrmSwState, 0, 1023, 0, 2);



      with



      byte alrmSet = alrmSwState / 342;



      And this should do what you want. Note that in C fractional results are truncated (not rounded)






      share|improve this answer








      New contributor




      Jeff Wahaus is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.

















      • this is wrong. it will give 3, 2, 1, 0
        – Juraj
        7 hours ago










      • It is correct. The max value returned is 1023 when divided by 342 = 2.991... which will give the integer division result of 2.
        – Jeff Wahaus
        7 hours ago










      • sorry, I forgot that Calc rounds to the nearest. I upvoted
        – Juraj
        7 hours ago











      • and map will do alrmSwState/512 which is not correct
        – Juraj
        7 hours ago










      • Why 342 and not 343? I like to see comments in the code that explains all the numbers.
        – Jot
        4 hours ago














      up vote
      2
      down vote













      Replace the line:



      byte alrmSet = map(alrmSwState, 0, 1023, 0, 2);



      with



      byte alrmSet = alrmSwState / 342;



      And this should do what you want. Note that in C fractional results are truncated (not rounded)






      share|improve this answer








      New contributor




      Jeff Wahaus is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.

















      • this is wrong. it will give 3, 2, 1, 0
        – Juraj
        7 hours ago










      • It is correct. The max value returned is 1023 when divided by 342 = 2.991... which will give the integer division result of 2.
        – Jeff Wahaus
        7 hours ago










      • sorry, I forgot that Calc rounds to the nearest. I upvoted
        – Juraj
        7 hours ago











      • and map will do alrmSwState/512 which is not correct
        – Juraj
        7 hours ago










      • Why 342 and not 343? I like to see comments in the code that explains all the numbers.
        – Jot
        4 hours ago












      up vote
      2
      down vote










      up vote
      2
      down vote









      Replace the line:



      byte alrmSet = map(alrmSwState, 0, 1023, 0, 2);



      with



      byte alrmSet = alrmSwState / 342;



      And this should do what you want. Note that in C fractional results are truncated (not rounded)






      share|improve this answer








      New contributor




      Jeff Wahaus is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      Replace the line:



      byte alrmSet = map(alrmSwState, 0, 1023, 0, 2);



      with



      byte alrmSet = alrmSwState / 342;



      And this should do what you want. Note that in C fractional results are truncated (not rounded)







      share|improve this answer








      New contributor




      Jeff Wahaus is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this answer



      share|improve this answer






      New contributor




      Jeff Wahaus is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      answered 8 hours ago









      Jeff Wahaus

      211




      211




      New contributor




      Jeff Wahaus is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      Jeff Wahaus is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      Jeff Wahaus is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      • this is wrong. it will give 3, 2, 1, 0
        – Juraj
        7 hours ago










      • It is correct. The max value returned is 1023 when divided by 342 = 2.991... which will give the integer division result of 2.
        – Jeff Wahaus
        7 hours ago










      • sorry, I forgot that Calc rounds to the nearest. I upvoted
        – Juraj
        7 hours ago











      • and map will do alrmSwState/512 which is not correct
        – Juraj
        7 hours ago










      • Why 342 and not 343? I like to see comments in the code that explains all the numbers.
        – Jot
        4 hours ago
















      • this is wrong. it will give 3, 2, 1, 0
        – Juraj
        7 hours ago










      • It is correct. The max value returned is 1023 when divided by 342 = 2.991... which will give the integer division result of 2.
        – Jeff Wahaus
        7 hours ago










      • sorry, I forgot that Calc rounds to the nearest. I upvoted
        – Juraj
        7 hours ago











      • and map will do alrmSwState/512 which is not correct
        – Juraj
        7 hours ago










      • Why 342 and not 343? I like to see comments in the code that explains all the numbers.
        – Jot
        4 hours ago















      this is wrong. it will give 3, 2, 1, 0
      – Juraj
      7 hours ago




      this is wrong. it will give 3, 2, 1, 0
      – Juraj
      7 hours ago












      It is correct. The max value returned is 1023 when divided by 342 = 2.991... which will give the integer division result of 2.
      – Jeff Wahaus
      7 hours ago




      It is correct. The max value returned is 1023 when divided by 342 = 2.991... which will give the integer division result of 2.
      – Jeff Wahaus
      7 hours ago












      sorry, I forgot that Calc rounds to the nearest. I upvoted
      – Juraj
      7 hours ago





      sorry, I forgot that Calc rounds to the nearest. I upvoted
      – Juraj
      7 hours ago













      and map will do alrmSwState/512 which is not correct
      – Juraj
      7 hours ago




      and map will do alrmSwState/512 which is not correct
      – Juraj
      7 hours ago












      Why 342 and not 343? I like to see comments in the code that explains all the numbers.
      – Jot
      4 hours ago




      Why 342 and not 343? I like to see comments in the code that explains all the numbers.
      – Jot
      4 hours ago










      up vote
      2
      down vote













      The simplest fix to your problem is to change the map() call to





      byte alrmSet = map(alrmSwState, 0, 1024, 0, 3);


      In the call above, the mapped intervals are of the semi-open type, e.g.
      [a, b), where the start values (namely 0) are understood as being
      inclusive and the end values (1024 and 3) are exclusive.



      Although not clear from the documentation, this is the proper way to use
      the map() function. Otherwise, the truncated division gives you very
      uneven intervals. Compare:



       x map(x, 0, 1023, 0, 2)
      ----------------------------------
      0 – 511 0
      512 – 1022 1
      1023 2

      x map(x, 0, 1024, 0, 3)
      ----------------------------------
      0 – 341 0
      342 – 682 1
      683 – 1023 2


      The result you get is very close to Jeff Wahaus’ answer.



      What I find annoying about this approach is that a 32-bit integer
      division, which map() uses internally, is a very expensive operation
      on the small 8-bit Arduinos. If instead of 342 and 683, you use 256 and
      768 as thresholds, then you can make the decision by just looking at the
      high byte of the analog reading:



      uint16_t alrmSwState = analogRead(alarmSwitchPin);

      alrmSet = alrmSwState / 256;

      if (alrmSet != alrmPrevSet)
      switch (alrmSet)
      case 0:
      Serial.println("Low");
      break;
      case 1:
      case 2:
      Serial.println("Medium");
      break;
      case 3:
      Serial.println("High");
      break;

      alrmPrevSet = alrmSet;
      delay(200);



      Note that the division by 256 is optimized by the compiler into a much
      cheaper bit shift, but this is the case only if alrmSwState is of an
      unsigned integer type. That's why it is declared above as uint16_t.






      share|improve this answer
























        up vote
        2
        down vote













        The simplest fix to your problem is to change the map() call to





        byte alrmSet = map(alrmSwState, 0, 1024, 0, 3);


        In the call above, the mapped intervals are of the semi-open type, e.g.
        [a, b), where the start values (namely 0) are understood as being
        inclusive and the end values (1024 and 3) are exclusive.



        Although not clear from the documentation, this is the proper way to use
        the map() function. Otherwise, the truncated division gives you very
        uneven intervals. Compare:



         x map(x, 0, 1023, 0, 2)
        ----------------------------------
        0 – 511 0
        512 – 1022 1
        1023 2

        x map(x, 0, 1024, 0, 3)
        ----------------------------------
        0 – 341 0
        342 – 682 1
        683 – 1023 2


        The result you get is very close to Jeff Wahaus’ answer.



        What I find annoying about this approach is that a 32-bit integer
        division, which map() uses internally, is a very expensive operation
        on the small 8-bit Arduinos. If instead of 342 and 683, you use 256 and
        768 as thresholds, then you can make the decision by just looking at the
        high byte of the analog reading:



        uint16_t alrmSwState = analogRead(alarmSwitchPin);

        alrmSet = alrmSwState / 256;

        if (alrmSet != alrmPrevSet)
        switch (alrmSet)
        case 0:
        Serial.println("Low");
        break;
        case 1:
        case 2:
        Serial.println("Medium");
        break;
        case 3:
        Serial.println("High");
        break;

        alrmPrevSet = alrmSet;
        delay(200);



        Note that the division by 256 is optimized by the compiler into a much
        cheaper bit shift, but this is the case only if alrmSwState is of an
        unsigned integer type. That's why it is declared above as uint16_t.






        share|improve this answer






















          up vote
          2
          down vote










          up vote
          2
          down vote









          The simplest fix to your problem is to change the map() call to





          byte alrmSet = map(alrmSwState, 0, 1024, 0, 3);


          In the call above, the mapped intervals are of the semi-open type, e.g.
          [a, b), where the start values (namely 0) are understood as being
          inclusive and the end values (1024 and 3) are exclusive.



          Although not clear from the documentation, this is the proper way to use
          the map() function. Otherwise, the truncated division gives you very
          uneven intervals. Compare:



           x map(x, 0, 1023, 0, 2)
          ----------------------------------
          0 – 511 0
          512 – 1022 1
          1023 2

          x map(x, 0, 1024, 0, 3)
          ----------------------------------
          0 – 341 0
          342 – 682 1
          683 – 1023 2


          The result you get is very close to Jeff Wahaus’ answer.



          What I find annoying about this approach is that a 32-bit integer
          division, which map() uses internally, is a very expensive operation
          on the small 8-bit Arduinos. If instead of 342 and 683, you use 256 and
          768 as thresholds, then you can make the decision by just looking at the
          high byte of the analog reading:



          uint16_t alrmSwState = analogRead(alarmSwitchPin);

          alrmSet = alrmSwState / 256;

          if (alrmSet != alrmPrevSet)
          switch (alrmSet)
          case 0:
          Serial.println("Low");
          break;
          case 1:
          case 2:
          Serial.println("Medium");
          break;
          case 3:
          Serial.println("High");
          break;

          alrmPrevSet = alrmSet;
          delay(200);



          Note that the division by 256 is optimized by the compiler into a much
          cheaper bit shift, but this is the case only if alrmSwState is of an
          unsigned integer type. That's why it is declared above as uint16_t.






          share|improve this answer












          The simplest fix to your problem is to change the map() call to





          byte alrmSet = map(alrmSwState, 0, 1024, 0, 3);


          In the call above, the mapped intervals are of the semi-open type, e.g.
          [a, b), where the start values (namely 0) are understood as being
          inclusive and the end values (1024 and 3) are exclusive.



          Although not clear from the documentation, this is the proper way to use
          the map() function. Otherwise, the truncated division gives you very
          uneven intervals. Compare:



           x map(x, 0, 1023, 0, 2)
          ----------------------------------
          0 – 511 0
          512 – 1022 1
          1023 2

          x map(x, 0, 1024, 0, 3)
          ----------------------------------
          0 – 341 0
          342 – 682 1
          683 – 1023 2


          The result you get is very close to Jeff Wahaus’ answer.



          What I find annoying about this approach is that a 32-bit integer
          division, which map() uses internally, is a very expensive operation
          on the small 8-bit Arduinos. If instead of 342 and 683, you use 256 and
          768 as thresholds, then you can make the decision by just looking at the
          high byte of the analog reading:



          uint16_t alrmSwState = analogRead(alarmSwitchPin);

          alrmSet = alrmSwState / 256;

          if (alrmSet != alrmPrevSet)
          switch (alrmSet)
          case 0:
          Serial.println("Low");
          break;
          case 1:
          case 2:
          Serial.println("Medium");
          break;
          case 3:
          Serial.println("High");
          break;

          alrmPrevSet = alrmSet;
          delay(200);



          Note that the division by 256 is optimized by the compiler into a much
          cheaper bit shift, but this is the case only if alrmSwState is of an
          unsigned integer type. That's why it is declared above as uint16_t.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 6 hours ago









          Edgar Bonet

          22.5k22344




          22.5k22344




















              up vote
              0
              down vote













              You might also consider reading the value several times and summing them, then base your decision on the sum.



              This is equivalent to averaging the values but without dividing by 'n', since you don't care about the actual number, just the band it falls into. This will have the effect of improving the signal to noise ratio, since we assume that high-reading errors are as likely as low-reading errors, so their sum tends toward zero as the sum of the real value, V, tends toward (n*V).



              Use an int or larger variable for the sum, depending on how many readings you choose to take each time.






              share|improve this answer
























                up vote
                0
                down vote













                You might also consider reading the value several times and summing them, then base your decision on the sum.



                This is equivalent to averaging the values but without dividing by 'n', since you don't care about the actual number, just the band it falls into. This will have the effect of improving the signal to noise ratio, since we assume that high-reading errors are as likely as low-reading errors, so their sum tends toward zero as the sum of the real value, V, tends toward (n*V).



                Use an int or larger variable for the sum, depending on how many readings you choose to take each time.






                share|improve this answer






















                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  You might also consider reading the value several times and summing them, then base your decision on the sum.



                  This is equivalent to averaging the values but without dividing by 'n', since you don't care about the actual number, just the band it falls into. This will have the effect of improving the signal to noise ratio, since we assume that high-reading errors are as likely as low-reading errors, so their sum tends toward zero as the sum of the real value, V, tends toward (n*V).



                  Use an int or larger variable for the sum, depending on how many readings you choose to take each time.






                  share|improve this answer












                  You might also consider reading the value several times and summing them, then base your decision on the sum.



                  This is equivalent to averaging the values but without dividing by 'n', since you don't care about the actual number, just the band it falls into. This will have the effect of improving the signal to noise ratio, since we assume that high-reading errors are as likely as low-reading errors, so their sum tends toward zero as the sum of the real value, V, tends toward (n*V).



                  Use an int or larger variable for the sum, depending on how many readings you choose to take each time.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 8 hours ago









                  JRobert

                  9,29311035




                  9,29311035



























                       

                      draft saved


                      draft discarded















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2farduino.stackexchange.com%2fquestions%2f57284%2fhow-to-boil-down-analog-input-to-just-three-cases%23new-answer', 'question_page');

                      );

                      Post as a guest













































































                      Comments

                      Popular posts from this blog

                      Long meetings (6-7 hours a day): Being “babysat” by supervisor

                      Is the Concept of Multiple Fantasy Races Scientifically Flawed? [closed]

                      Confectionery