switch/case

Hello,

I had the following code (not complete):

switch (wind_direction)
{
case'30':
Serial.print("ZW");
break;
}

Is it possible to define the '30' as a value of 25 - 35?
The value 30 is in some circumstances a little bit lower or higher, but in all this range he must Serial.print("ZW").

Ideas?

Gr.
Johan

jmnijsse:
Hello,

I had the following code (not complete):

switch (wind_direction)
{
case'30':
Serial.print("ZW");
break;
}

Is it possible to define the '30' as a value of 25 - 35?
The value 30 is in some circumstances a little bit lower or higher, but in all this range he must Serial.print("ZW").

Ideas?

Gr.
Johan

You would be better off using if statements if you have to check range. 99.2% sure switch case is steady-state.

Yes, we do in the first time.
But we have twelve situations (its a winddirectionflag, contacted with reedcontacts and different resistors).
So, i thought, the if-solution became a long code.

J.

You can't mean "case '30':", perhaps you mean "case 30:" ??

Sounds like you need "if (wind_direction >= 25 && wind_direction <= 35)"

Is the output of the reed switches and resistors a voltage that you get with analogread and that is the need for a range to test for?

Yes, I read a voltage of the resistor.

With the if-solution:
Have i write it like this:

if (wind_direction >= 25 && wind_direction <= 35) {
Serial.print("ZW");
}
if (wind_direction >=40 && wind_direction <=50) {
Serial.print("W")
}
...and this twelve times?

jmnijsse:
Yes, we do in the first time.
But we have twelve situations (its a winddirectionflag, contacted with reedcontacts and different resistors).
So, i thought, the if-solution became a long code.

J.

This will look redundant with If and switch, but will be much cleaner- particularly if you're doing the same thing, but with different numbers.

Use 12 if statements to set an int, then switch on that int. IE,

if ((-15 <= wind_direction) && ((wind_direction <= 15)){

evalDir = "N"

} else if ((16 <= wind_direction) && ((wind_direction <= 30)){

evalDir = "NNE"

} else if ((31 <= wind_direction) && ((wind_direction <= 60)){

evalDir = "NE"

} else if ((61 <= wind_direction) && ((wind_direction <= 75)){

evalDir = "ENE"

} else if ((76 <= wind_direction) && ((wind_direction <= 105)){

evalDir = "E"

} else if ((106 <= wind_direction) && ((wind_direction <= 120)){

evalDir = "ESE"

} else if ((121 <= wind_direction) && ((wind_direction <= 150)){

evalDir = "SE"

} else if ((151 <= wind_direction) && ((wind_direction <= 165)){

evalDir = "SSE"

} else if ((166 <= wind_direction) && ((wind_direction <= 195)){

evalDir = "S"

} else if ((196 <= wind_direction) && ((wind_direction <= 210)){

evalDir = "SSW"

} else if ((211 <= wind_direction) && ((wind_direction <= 240)){

evalDir = "SW"

} else if ((241 <= wind_direction) && ((wind_direction <= 255)){

evalDir = "WSW"

} else if ((256 <= wind_direction) && ((wind_direction <= 285)){

evalDir = "W"

} else if ((286 <= wind_direction) && ((wind_direction <= 300)){

evalDir = "WNW"

} else if ((301 <= wind_direction) && ((wind_direction <= 330)){

evalDir = "NW"

} else if ((331 <= wind_direction) && ((wind_direction <= 345)){

evalDir = "NNW"

} else if ((346 <= wind_direction) && ((wind_direction <= 360)){

evalDir = "N"

}

switch (evalDir){

case n:
serial.print(evalDir);
break;

}

You could put the ranges and direction string into an array of structs, then simply loop through the array.

What are the actual ranges? It might be possible to reduce them with a simple formula to give you an int in the 0 to 11 range to use as an index into a string array.

Oops, went to modify my post and removed it by accident.

Wildbill is right, no if's or switch needed.

This is assuming the values you read are relative to degrees.

const char *c_Text[] = { "N", "NNE",  "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW", "N" };

int deg; //Provided from sensor.

#define WHICH_DIRECTION( sensor_degrees )        ( c_Text[ ( int ) ( ( 17.0f / 360.0f )  * ( float ) sensor_degrees ) ] )  
#define WHICH_DIRECTION__SAFE( sensor_degrees )  ( c_Text[ ( int ) ( ( ( 17.0f / 360.0f )  * ( float ) sensor_degrees ) - 0.0001f ) ] )  

void loop(){

  //Get value into deg
  deg = 34;

  //If sensor data is in range 0 to 359
  Serial.print( WHICH_DIRECTION( deg ) );

  //If you receive a value of 360 instead of 0, use this instead. ( prevents overflow ).
  //Shouldn't need this. A sensor should only give one result for a discrete position.
  Serial.print( WHICH_DIRECTION__SAFE( deg ) );
};

wildbill:
What are the actual ranges? It might be possible to reduce them with a simple formula to give you an int in the 0 to 11 range to use as an index into a string array.

Would this be an instance to use map()? Something like:

map( wind_direction, 0, 359, 0, 11 );

You want to use a convoluted function to divide by 30? Whatever floats your boat, I guess.

Division is slower than multiplication.

( 17.0f / 360.0f ) is a compile time constant, only operation being emitted is 0.0472 * deg

Division is slower than multiplication.

So? Have you looked at the map function?

Nope, didn't realise you were referring to it.

Have now tho. map contains an operation not needed for this topic. Division would be faster due to the overhead and the fact that gcc will optimise most / operations to * operations.

PaulS:
You want to use a convoluted function to divide by 30? Whatever floats your boat, I guess.

Yeah, didn't really think that one through, did I?

jmnijsse:
Is it possible to define the '30' as a value of 25 - 35?
The value 30 is in some circumstances a little bit lower or higher, but in all this range he must Serial.print("ZW").

I'm not sure I recommend this, but this compiles and outputs ZW:

void setup ()
{
  int wind_direction = 35;

  Serial.begin (115200);
  
  switch (wind_direction)
  {
  case 25 ... 35:
    Serial.print("ZW");
    break;
  }
}
void loop () { }

Ah, an interesting gcc extension that. Not standard C/C++ though.

I only found out about it on this forum. Usually I would suggest if you want to do something like that you should redesign. But it does answer the original question. And a peek at the generated code is interesting. This code:

volatile int wind_direction = 35;

void setup ()
{

  Serial.begin (115200);
  
  switch (wind_direction)
  {
  case 25 ... 35:
    Serial.print("ZW");
    break;
  }
}
void loop () { }

... generates:

   switch (wind_direction)
  d0:	80 91 03 01 	lds	r24, 0x0103
  d4:	90 91 04 01 	lds	r25, 0x0104
  d8:	49 97       	sbiw	r24, 0x19	; 25
  da:	0b 97       	sbiw	r24, 0x0b	; 11
  dc:	30 f4       	brcc	.+12     	; 0xea <setup+0x2a>
  {
  case 25 ... 35:
    Serial.print("ZW");

It looks like it is doing subtractions rather than generating all 11 possibilities. Although I don't quite see how they get away with a single compare to check both an upper and lower range.

A slightly different test, namely:

void test (int wind_direction)
{
  Serial.println (wind_direction);
  switch (wind_direction)
  {
  case 25 ... 35:
    Serial.println("passed");
    break;
  default:
    Serial.println("failed");
    break;
  }  
}

void setup ()
{

  Serial.begin (115200);
  test (20);
  test (24);
  test (25);
  test (34);
  test (35);
  test (36);

}

void loop () { }

... generates two compares:

  switch (wind_direction)
  d4:	09 51       	subi	r16, 0x19	; 25
  d6:	10 40       	sbci	r17, 0x00	; 0
  d8:	0b 30       	cpi	r16, 0x0B	; 11
  da:	11 05       	cpc	r17, r1
  dc:	28 f4       	brcc	.+10     	; 0xe8 <_Z4testi+0x28>
  {
  case 25 ... 35:
    Serial.println("passed");
  if (v >= lowval && v <= highval)

is equivalent to

  if ((unsigned) (v -  lowval) <= (unsigned) (highval - lowval))

Which is sort of what the compiler is doing. In fact it doesn't need to be unsigned, but its simpler.