Hey that's me

end2end zone

My life dumped to a web site

end2end

30-Minute Read

Introduction

In a personal project, I wanted to add 2 new devices to an existing quadcopter. The quadcopter was equipped with a 6-channel receiver meaning I only had 1 spare channel to control the 2 devices:

CH 1 : Throttle
CH 2 : Rudder
CH 3 : Ailerons
CH 4 : Elevator
CH 5 : Flight mode
CH 6 : ???
The following article explains how I manage to solve the issue:

How can I control more than one device using a single channel.

EDIT: To make all mixing pre-calculations easier, do not hesitate to use my Mixing Calculator for R/C Transmitter (it’s an Excel Sheet!)

I could have used an 8-channel receiver to solve this but I did not had a free receiver that I could spare. This guide will show you how to multiplex RC transmitter switches (inputs) into a

single channel.

Use a microcontroller

For this type of project, 7 channels is usually required. The easiest method would have been to replace the receiver but since I like the DIY way, I decided to multiplex two switches into the 6th channel and use a microcontroller to read the signal and demultiplex each switches states.

Note: This is only valid if there is a microcontroller connected with the receiver that _ you _ can program to demultiplex the signal. Do not expect your proprietary flight controller to be able to understand your signal.

Multiplexing switches (only)

Design

The following section illustrate the design required for multiplexing as much information as possible into a single channel.

Create blocks

The generic idea is to divide the whole range of the signal (from -150% to 150%) into blocks or bands. Each block correspond to a unique configuration of all switches. Then you create the required mixes to move/update the signal value to the block corresponding to the switches unique configuration.

Minimum number of blocks

The following explain what is the minimum number of blocks that are required for multiplexing a given amount of switches. The number of required blocks for a given number of switches is defined by the all the unique combinations that are possible with the switches. To calculate this, you multiply the number of combinations of each switch by each other. For instance: To multiplex three 2-position switches, 8 blocks are required (2*2*2) which makes 8 unique combinations:

**Block Number** **Switches**
**2-pos** **2-pos** **2-pos**
1 1
2 1
3 1 1
4 1
5 1 1
6 1 1
7 1 1 1
To multiplex two 2-position and one 3-position switches, 12 blocks are required (2\*2\*3) which makes 12 unique combinations:
**Block Number** **Switches**
**2-pos** **2-pos** **3-pos**
1 1
2 2
3 1
4 1 1
5 1 2
6 1
7 1 1
8 1 2
9 1 1
10 1 1 1
11 1 1 2

Note that each switch also requires a mix for working. The amount of switches you can multiplex is then also limited by the amount of mixes you can define in your transmitter.

Supporting 3-position switches

In your design, you will have to decide to support or not 3-position switches. If you do, it will reduce the amount of switches you can multiplex into a single channel since each switches requires 3 blocks instead of 2 blocks. An acceptable compromise is to use this switch as a 2-position switch. Position 1 would then be identical as Position 0 (OFF) and Position 2 would be ON.

Dead Zone

Blocks cannot be juxtaposed to each other and dead zones must be inserted between (or within) blocks. This is required since each transmitters and micro-controllers do not offer the same performance and precision. Dead zones are required since a micro-controller might read data from block 5 but the next pulse of the same signal may introduce a 5uS delay, which would correspond to a different block (ie block 6). For instance, if the following blocks are defined:

Block Min Max
-150% -141%
1 -140% -131%
2 -130% -121%
3 -120% -111%

The difference between -131% (block 1) and -130% (block 2) is ~5uS. If blocks would be juxtaposed, then the micro-controller could sometimes read block 1 and sometimes block 2 which does not mean the same thing at all. This delay might be from the receiver who does not provide a perfect pulse length or from the micro-controller who does not detect the end of the pulse with enough precision. Both errors can be avoided with dead zones. By introducing a dead zone of 5 steps within blocks (of 10 steps), the same blocks would then become something like:

Block Min Max Mix Target
DEAD -150% -148%
-147% -143% -145%
DEAD -142% -138%
1 -137% -133% -135%
DEAD -132% -128%
2 -127% -123% -125%
DEAD -122% -113%
3 -117% -113% -115%

The block size must also have a minimum size to account for the same effect. If the block size is too small, the micro-controller might read data from a dead zone and would not know what to do. The more accurate the receiver and the micro-controller, the smaller the block size and dead zone size can be. Mixes should be created to move the actual signal values to target the middle of the effective block area (not the dead zone). See the

Mixes section for more details.

Block size

Based on my observation, the best values for block size and dead zone size are as follow: A block size of 10 steps is big enough to allow multiplexing a high amount of switches while leaving enough space for a reasonable dead zone between blocks. At the same time, a block size of 10 steps allows the blocks to be rounded easily which makes blocks offsets easy to calculate. The acceptable dead zone size (considering the average precision of most micro-controller and receivers), does not need to be bigger than 2 steps. This configuration leaves two blocks spaced by 4 steps which is enough to prevent issues. The following values are then considered “safe and tested” to get good and stable results:

Block size : 10 steps
Dead zone : 2 steps
Effective size : 6 steps

Mixes

The following section defines mix that are required to implement two basic scenarios.

Note that you can easily calculate the effect of a given mix by using my RC Transmitter Mix Calculator to identify the minimum, middle and maximum values of a mix.

Four 2-position switches

The following table shows the signal range and the middle of the effective area for each block. It is calculated using a block size of 10 steps and a dead zone of 2 steps which makes the effective block size to 6 steps:

Block Number Block Offsets Mix Target
Dead Effective Dead
-150 -149 -148 -143 -142 -141 -146
1 -140 -139 -138 -133 -132 -131 -136
2 -130 -129 -128 -123 -122 -121 -126
3 -120 -119 -118 -113 -112 -111 -116
4 -110 -109 -108 -103 -102 -101 -106
5 -100 -99 -98 -93 -92 -91 -96
6 -90 -89 -88 -83 -82 -81 -86
7 -80 -79 -78 -73 -72 -71 -76
8 -70 -69 -68 -63 -62 -61 -66
9 -60 -59 -58 -53 -52 -51 -56
10 -50 -49 -48 -43 -42 -41 -46
11 -40 -39 -38 -33 -32 -31 -36
12 -30 -29 -28 -23 -22 -21 -26
13 -20 -19 -18 -13 -12 -11 -16
14 -10 -9 -8 -3 -2 -1 -6
15 1 2 7 8 9 5
The following mixes must be created to multiplex all switches unique configurations:
Mix info Mix Output
Number Switch High Low Offset 1
A -100 100 -100 -100
1 A -46 36 -46 -36
2 B -20 20
3 C -40 40
4 D -80 80

Note that first 2 mix are mapped to switch A. This is required since the minimum value of a High rate mix is -125% which gives a final mix value of -125% at Position 0. The only way to get a lower value (ie -146) would be to offset the mix (by -17) but then the Low rate value would have the same issue.

As you can see, the sum of all combined mixes matches the middle section of each effective block:

Block Number Switches Mixes
D C B A 1 2 3 4 Sum
-100 -46 -146
1 1 -100 -36 -136
2 1 -100 -46 20 -126
3 1 1 -100 -36 20 -116
4 1 -100 -46 40 -106
5 1 1 -100 -36 40 -96
6 1 1 -100 -46 20 40 -86
7 1 1 1 -100 -36 20 40 -76
8 1 -100 -46 80 -66
9 1 1 -100 -36 80 -56
10 1 1 -100 -46 20 80 -46
11 1 1 1 -100 -36 20 80 -36
12 1 1 -100 -46 40 80 -26
13 1 1 1 -100 -36 40 80 -16
14 1 1 1 -100 -46 20 40 80 -6
15 1 1 1 1 -100 -36 20 40 80 4
Use the
[ Cheat Sheet for Multiplexing four 2-position switches (301 downloads) ](http://www.end2endzone.com/download/1486/ "Version 1.0") for calculating all block offset when multiplexing four 2-position switches. 

Three 2-position and one 3-position switches

The following table shows the signal range and the middle of the effective area for each block. It is calculated using a block size of 10 steps and a dead zone of 2 steps which makes the effective block size to 6 steps:

Block Number Block Offsets Mix Target
Dead Effective Dead
-150 -149 -148 -143 -142 -141 -146
1 -140 -139 -138 -133 -132 -131 -136
2 -130 -129 -128 -123 -122 -121 -126
3 -120 -119 -118 -113 -112 -111 -116
4 -110 -109 -108 -103 -102 -101 -106
5 -100 -99 -98 -93 -92 -91 -96
6 -90 -89 -88 -83 -82 -81 -86
7 -80 -79 -78 -73 -72 -71 -76
8 -70 -69 -68 -63 -62 -61 -66
9 -60 -59 -58 -53 -52 -51 -56
10 -50 -49 -48 -43 -42 -41 -46
11 -40 -39 -38 -33 -32 -31 -36
12 -30 -29 -28 -23 -22 -21 -26
13 -20 -19 -18 -13 -12 -11 -16
14 -10 -9 -8 -3 -2 -1 -6
15 1 2 7 8 9 5
16 10 11 12 17 18 19 15
17 20 21 22 27 28 29 25
18 30 31 32 37 38 39 35
19 40 41 42 47 48 49 45
20 50 51 52 57 58 59 55
21 60 61 62 67 68 69 65
22 70 71 72 77 78 79 75
23 80 81 82 87 88 89 85
The following mixes must be created to multiplex all switches unique configurations:
Mix info Mix Output
Number Switch High Low Offset 1 2
A 68 100 -68 -136
1 A -68 -100 -136 -68
2 A -10 -10 -10 10
3 B -30 30
4 C -60 60
5 D -120 120

Note that first 3 mix are mapped to switch A which is the 3-position switch. The first 2 mix are use to get a constant -136 on all positions. Then the 3rd mix moves the signal value over the first 3 blocks (to the previous, current or next block). As far as I know, there is no way to achieve the same result with only 2 mixes.

As you can see, the sum of all combined mixes matches the middle section of each effective block:

Block Number Switches Mixes
D C B A 1 2 3 4 5 Sum
-136 -10 -146
1 1 -68 -68 -136
2 2 -136 10 -126
3 1 -136 -10 30 -116
4 1 1 -68 -68 30 -106
5 1 2 -136 10 30 -96
6 1 -136 -10 60 -86
7 1 1 -68 -68 60 -76
8 1 2 -136 10 60 -66
9 1 1 -136 -10 30 60 -56
10 1 1 1 -68 -68 30 60 -46
11 1 1 2 -136 10 30 60 -36
12 1 -136 -10 120 -26
13 1 1 -68 -68 120 -16
14 1 2 -136 10 120 -6
15 1 1 -136 -10 30 120 4
16 1 1 1 -68 -68 30 120 14
17 1 1 2 -136 10 30 120 24
18 1 1 -136 -10 60 120 34
19 1 1 1 -68 -68 60 120 44
20 1 1 2 -136 10 60 120 54
21 1 1 1 -136 -10 30 60 120 64
22 1 1 1 1 -68 -68 30 60 120 74
23 1 1 1 2 -136 10 30 60 120 84
Use the
[ Cheat Sheet for Multiplexing three 2-position and one 3-position switches (331 downloads) ](http://www.end2endzone.com/download/1482/ "Version 1.0") for calculating all block offset when multiplexing three 2-position switches and one 3-position switch. 

Three 3-position switches

The following table shows the signal range and the middle of the effective area for each block. Again, it is calculated using a block size of 10 steps and a dead zone of 2 steps which makes the effective block size to 6 steps:

Block Number Block Offsets Mix Target
Dead Effective Dead
-134 -133 -132 -127 -126 -125 -130
1 -124 -123 -122 -117 -116 -115 -120
2 -114 -113 -112 -107 -106 -105 -110
3 -104 -103 -102 -97 -96 -95 -100
4 -94 -93 -92 -87 -86 -85 -90
5 -84 -83 -82 -77 -76 -75 -80
6 -74 -73 -72 -67 -66 -65 -70
7 -64 -63 -62 -57 -56 -55 -60
8 -54 -53 -52 -47 -46 -45 -50
9 -44 -43 -42 -37 -36 -35 -40
10 -34 -33 -32 -27 -26 -25 -30
11 -24 -23 -22 -17 -16 -15 -20
12 -14 -13 -12 -7 -6 -5 -10
13 -4 -3 -2 3 4 5 1
14 6 7 8 13 14 15 11
15 16 17 18 23 24 25 21
16 26 27 28 33 34 35 31
17 36 37 38 43 44 45 41
18 46 47 48 53 54 55 51
19 56 57 58 63 64 65 61
20 66 67 68 73 74 75 71
21 76 77 78 83 84 85 81
22 86 87 88 93 94 95 91
23 96 97 98 103 104 105 101
24 106 107 108 113 114 115 111
25 116 117 118 123 124 125 121
26 126 127 128 133 134 135 131
The following mixes must be created to multiplex all switches unique configurations:
Mix info Mix Output
Number Switch High Low Offset 1 2
A -10 -10 -10 10
1 B -30 -30 -30 30
2 C -90 -90 -90 90

Note that only 3 mix is required for multiplexing three 3-position switches. Mixes are also centered around 0 (instead of starting at -150).

As you can see, the sum of all combined mixes matches the middle section of each effective block:

Block Number Switches Mixes
C B A 1 2 Sum
-10 -30 -90 -130
1 1 -30 -90 -120
2 2 10 -30 -90 -110
3 1 -10 -90 -100
4 1 1 -90 -90
5 1 2 10 -90 -80
6 2 -10 30 -90 -70
7 2 1 30 -90 -60
8 2 2 10 30 -90 -50
9 1 -10 -30 -40
10 1 1 -30 -30
11 1 2 10 -30 -20
12 1 1 -10 -10
13 1 1 1
14 1 1 2 10 10
15 1 2 -10 30 20
16 1 2 1 30 30
17 1 2 2 10 30 40
18 2 -10 -30 90 50
19 2 1 -30 90 60
20 2 2 10 -30 90 70
21 2 1 -10 90 80
22 2 1 1 90 90
23 2 1 2 10 90 100
24 2 2 -10 30 90 110
25 2 2 1 30 90 120
26 2 2 2 10 30 90 130
Use the
[ Cheat Sheet for Multiplexing three 3-position switches (339 downloads) ](http://www.end2endzone.com/download/1484/ "Version 1.0") for calculating all block offset when multiplexing three 3-position switches. 

Decoding

Decoding the switches configuration is relatively easy: First identify the block number matching the signal’s value using a sequence of "

if" statements. Then, update switches state based on the currently selected block. Refer to tables above for offsets & switches states for each selected block.

Note that if you get a signal value that is within the dead zone, it probably means that you have an issue with your transmitter mixes. Verify your mixes and try again.

Since reading switches states does not imply any analog value, you do not really care if the signal value is within the effective area (or not) so clamping is not necessary beside detecting instability issue in the signal. However, in the low probability that you get a signal within a dead zone, then the first dead zone should be considered as if you read the first value of the effective area and the last dead zone as the last value of the effective area.

Required Libraries

PinChangeInt This library allows the arduino to attach interrupts on multiple pins. eRCaGuy_Timer2_Counter (optional) This library configures the arduino’s timer2 to 0.5µs precision. It is used for a micros() function replacement and allows times calculations that are far more precise (8 times!) than the default’s 4µs resolution.

Code sample

The following arduino code (*.ino) can be used to demultiplex the three scenarios above:

  1//Using RcReceiverSignal v1.1.203
  2//required to read the receiver's value
  3//available at http://www.end2endzone.com/rcreceiversignal-an-arduino-library-for-retreiving-the-rc-transmitter-value-from-an-rc-receiver-pulse/
  4#include <RcReceiverSignal.h>
  5
  6//Using PinChangeInt version 2402
  7//RcReceiverSignal library has a dependency to PinChangeInt library.
  8//available at http://code.google.com/p/arduino-pinchangeint/
  9#include <PinChangeInt.h>
 10
 11//Using eRCaGuy_Timer2_Counter version 20140709 (last updated 9 July 2014)
 12//Required to have a micros() replacement function which has a 
 13//1us resolution instead of 4usec.
 14//For more information on this library, see the following:
 15// http://electricrcaircraftguy.com/2014/02/Timer2Counter-more-precise-Arduino-micros-function.html
 16// http://www.instructables.com/id/How-to-get-an-Arduino-micros-function-with-05us-pr/
 17#include <eRCaGuy_Timer2_Counter.h>
 18
 19//project's constants
 20#define RECEIVER_AUX1_IN_PIN 2 // we could choose any pin
 21
 22//project's switches
 23#define ENABLE_SERIAL_OUTPUT
 24
 25//*****************************************************************************
 26//  TODO: UNCOMMENT ONE OF THE FOLLOWING:
 27//****************************************************************************/
 28//#define _4X2POS
 29//#define _3X2POS1X3POS
 30//#define _3X3POS
 31
 32DECLARE_RECEIVER_SIGNAL(receiver_aux1_handler);
 33
 34inline short clamp(const short & iMin, const short & iValue, const short & iMax) {
 35  if (iValue < iMin)
 36    return iMin;
 37  if (iValue > iMax)
 38    return iMax;
 39  return iValue;
 40}
 41
 42void demultiplex4x2Pos(const short & iSignal, bool & oSwitchA, bool & oSwitchB, bool & oSwitchC, bool & oSwitchD) {
 43  #define setSwitches(d,c,b,a) oSwitchA=(a==1); oSwitchB=(b==1); oSwitchC=(c==1); oSwitchD=(d==1);
 44       if ( -150 <= iSignal && iSignal <=  -141 ) { setSwitches( 0 , 0 , 0 , 0 ) }
 45  else if ( -140 <= iSignal && iSignal <=  -131 ) { setSwitches( 0 , 0 , 0 , 1 ) }
 46  else if ( -130 <= iSignal && iSignal <=  -121 ) { setSwitches( 0 , 0 , 1 , 0 ) }
 47  else if ( -120 <= iSignal && iSignal <=  -111 ) { setSwitches( 0 , 0 , 1 , 1 ) }
 48  else if ( -110 <= iSignal && iSignal <=  -101 ) { setSwitches( 0 , 1 , 0 , 0 ) }
 49  else if ( -100 <= iSignal && iSignal <=   -91 ) { setSwitches( 0 , 1 , 0 , 1 ) }
 50  else if (  -90 <= iSignal && iSignal <=   -81 ) { setSwitches( 0 , 1 , 1 , 0 ) }
 51  else if (  -80 <= iSignal && iSignal <=   -71 ) { setSwitches( 0 , 1 , 1 , 1 ) }
 52  else if (  -70 <= iSignal && iSignal <=   -61 ) { setSwitches( 1 , 0 , 0 , 0 ) }
 53  else if (  -60 <= iSignal && iSignal <=   -51 ) { setSwitches( 1 , 0 , 0 , 1 ) }
 54  else if (  -50 <= iSignal && iSignal <=   -41 ) { setSwitches( 1 , 0 , 1 , 0 ) }
 55  else if (  -40 <= iSignal && iSignal <=   -31 ) { setSwitches( 1 , 0 , 1 , 1 ) }
 56  else if (  -30 <= iSignal && iSignal <=   -21 ) { setSwitches( 1 , 1 , 0 , 0 ) }
 57  else if (  -20 <= iSignal && iSignal <=   -11 ) { setSwitches( 1 , 1 , 0 , 1 ) }
 58  else if (  -10 <= iSignal && iSignal <=    -1 ) { setSwitches( 1 , 1 , 1 , 0 ) }
 59  else if (    0 <= iSignal && iSignal <=     9 ) { setSwitches( 1 , 1 , 1 , 1 ) }
 60  else {
 61    setSwitches(0,0,0,0);
 62  }
 63  #undef setSwitches
 64}
 65
 66void demultiplex3x2Pos1x3Pos(const short & iSignal, unsigned char & oSwitchA, bool & oSwitchB, bool & oSwitchC, bool & oSwitchD) {
 67  #define setSwitches(d,c,b,a) oSwitchA=a; oSwitchB=(b==1); oSwitchC=(c==1); oSwitchD=(d==1);
 68       if ( -150 <= iSignal && iSignal <=  -141 ) { setSwitches( 0 , 0 , 0 , 0 ) }
 69  else if ( -140 <= iSignal && iSignal <=  -131 ) { setSwitches( 0 , 0 , 0 , 1 ) }
 70  else if ( -130 <= iSignal && iSignal <=  -121 ) { setSwitches( 0 , 0 , 0 , 2 ) }
 71  else if ( -120 <= iSignal && iSignal <=  -111 ) { setSwitches( 0 , 0 , 1 , 0 ) }
 72  else if ( -110 <= iSignal && iSignal <=  -101 ) { setSwitches( 0 , 0 , 1 , 1 ) }
 73  else if ( -100 <= iSignal && iSignal <=   -91 ) { setSwitches( 0 , 0 , 1 , 2 ) }
 74  else if (  -90 <= iSignal && iSignal <=   -81 ) { setSwitches( 0 , 1 , 0 , 0 ) }
 75  else if (  -80 <= iSignal && iSignal <=   -71 ) { setSwitches( 0 , 1 , 0 , 1 ) }
 76  else if (  -70 <= iSignal && iSignal <=   -61 ) { setSwitches( 0 , 1 , 0 , 2 ) }
 77  else if (  -60 <= iSignal && iSignal <=   -51 ) { setSwitches( 0 , 1 , 1 , 0 ) }
 78  else if (  -50 <= iSignal && iSignal <=   -41 ) { setSwitches( 0 , 1 , 1 , 1 ) }
 79  else if (  -40 <= iSignal && iSignal <=   -31 ) { setSwitches( 0 , 1 , 1 , 2 ) }
 80  else if (  -30 <= iSignal && iSignal <=   -21 ) { setSwitches( 1 , 0 , 0 , 0 ) }
 81  else if (  -20 <= iSignal && iSignal <=   -11 ) { setSwitches( 1 , 0 , 0 , 1 ) }
 82  else if (  -10 <= iSignal && iSignal <=    -1 ) { setSwitches( 1 , 0 , 0 , 2 ) }
 83  else if (    0 <= iSignal && iSignal <=     9 ) { setSwitches( 1 , 0 , 1 , 0 ) }
 84  else if (   10 <= iSignal && iSignal <=    19 ) { setSwitches( 1 , 0 , 1 , 1 ) }
 85  else if (   20 <= iSignal && iSignal <=    29 ) { setSwitches( 1 , 0 , 1 , 2 ) }
 86  else if (   30 <= iSignal && iSignal <=    39 ) { setSwitches( 1 , 1 , 0 , 0 ) }
 87  else if (   40 <= iSignal && iSignal <=    49 ) { setSwitches( 1 , 1 , 0 , 1 ) }
 88  else if (   50 <= iSignal && iSignal <=    59 ) { setSwitches( 1 , 1 , 0 , 2 ) }
 89  else if (   60 <= iSignal && iSignal <=    69 ) { setSwitches( 1 , 1 , 1 , 0 ) }
 90  else if (   70 <= iSignal && iSignal <=    79 ) { setSwitches( 1 , 1 , 1 , 1 ) }
 91  else if (   80 <= iSignal && iSignal <=    89 ) { setSwitches( 1 , 1 , 1 , 2 ) }
 92  else {
 93    setSwitches(0,0,0,0);
 94  }
 95  #undef setSwitches
 96}
 97
 98void demultiplex3x3Pos(const short & iSignal, unsigned char & oSwitchA, unsigned char & oSwitchB, unsigned char & oSwitchC) {
 99  #define setSwitches(c,b,a) oSwitchA=a; oSwitchB=b; oSwitchC=c;
100       if ( -134 <= iSignal && iSignal <=  -125 ) { setSwitches( 0 , 0 , 0 ) }
101  else if ( -124 <= iSignal && iSignal <=  -115 ) { setSwitches( 0 , 0 , 1 ) }
102  else if ( -114 <= iSignal && iSignal <=  -105 ) { setSwitches( 0 , 0 , 2 ) }
103  else if ( -104 <= iSignal && iSignal <=   -95 ) { setSwitches( 0 , 1 , 0 ) }
104  else if (  -94 <= iSignal && iSignal <=   -85 ) { setSwitches( 0 , 1 , 1 ) }
105  else if (  -84 <= iSignal && iSignal <=   -75 ) { setSwitches( 0 , 1 , 2 ) }
106  else if (  -74 <= iSignal && iSignal <=   -65 ) { setSwitches( 0 , 2 , 0 ) }
107  else if (  -64 <= iSignal && iSignal <=   -55 ) { setSwitches( 0 , 2 , 1 ) }
108  else if (  -54 <= iSignal && iSignal <=   -45 ) { setSwitches( 0 , 2 , 2 ) }
109  else if (  -44 <= iSignal && iSignal <=   -35 ) { setSwitches( 1 , 0 , 0 ) }
110  else if (  -34 <= iSignal && iSignal <=   -25 ) { setSwitches( 1 , 0 , 1 ) }
111  else if (  -24 <= iSignal && iSignal <=   -15 ) { setSwitches( 1 , 0 , 2 ) }
112  else if (  -14 <= iSignal && iSignal <=    -5 ) { setSwitches( 1 , 1 , 0 ) }
113  else if (   -4 <= iSignal && iSignal <=     5 ) { setSwitches( 1 , 1 , 1 ) }
114  else if (    6 <= iSignal && iSignal <=    15 ) { setSwitches( 1 , 1 , 2 ) }
115  else if (   16 <= iSignal && iSignal <=    25 ) { setSwitches( 1 , 2 , 0 ) }
116  else if (   26 <= iSignal && iSignal <=    35 ) { setSwitches( 1 , 2 , 1 ) }
117  else if (   36 <= iSignal && iSignal <=    45 ) { setSwitches( 1 , 2 , 2 ) }
118  else if (   46 <= iSignal && iSignal <=    55 ) { setSwitches( 2 , 0 , 0 ) }
119  else if (   56 <= iSignal && iSignal <=    65 ) { setSwitches( 2 , 0 , 1 ) }
120  else if (   66 <= iSignal && iSignal <=    75 ) { setSwitches( 2 , 0 , 2 ) }
121  else if (   76 <= iSignal && iSignal <=    85 ) { setSwitches( 2 , 1 , 0 ) }
122  else if (   86 <= iSignal && iSignal <=    95 ) { setSwitches( 2 , 1 , 1 ) }
123  else if (   96 <= iSignal && iSignal <=   105 ) { setSwitches( 2 , 1 , 2 ) }
124  else if (  106 <= iSignal && iSignal <=   115 ) { setSwitches( 2 , 2 , 0 ) }
125  else if (  116 <= iSignal && iSignal <=   125 ) { setSwitches( 2 , 2 , 1 ) }
126  else if (  126 <= iSignal && iSignal <=   135 ) { setSwitches( 2 , 2 , 2 ) }
127  else {
128    setSwitches(0,0,0);
129  }
130  #undef setSwitches
131}
132
133uint32_t timer2GetCountWrapperFunction() {
134  return timer2.get_count();
135}
136
137void setup() {
138  //configure Timer2
139  timer2.setup(); //this MUST be done before the other Timer2_Counter functions work; Note: since this messes up PWM outputs on pins 3 & 11, as well as 
140                  //interferes with the tone() library (http://arduino.cc/en/reference/tone), you can always revert Timer2 back to normal by calling 
141                  //timer2.unsetup()
142
143  //configure RcReceiverSignal with an external time counter
144  //eRCaGuy_Timer2_Counter lirary has 0.5us resolution.
145  //The counter value must be divided by 2 to convert from 0.5us steps to 1us steps
146  //which results in microseconds resolution.
147  RcReceiverSignal::setExternalTimeCounter(&timer2GetCountWrapperFunction, 1, 2);
148
149  //link RcReceiverSignal to use PinChangeInt library
150  RcReceiverSignal::setAttachInterruptFunction(&PCintPort::attachInterrupt);
151  RcReceiverSignal::setPinStatePointer(&PCintPort::pinState);
152
153  #ifdef ENABLE_SERIAL_OUTPUT
154    Serial.begin(115200);
155    Serial.println("ready");
156  #endif
157
158  receiver_aux1_handler_setup(RECEIVER_AUX1_IN_PIN);
159}
160
161void loop() {
162  //detect when the receiver AUX1 value has changed
163  if (receiver_aux1_handler.hasChanged())
164  {
165    unsigned long pwmValue = receiver_aux1_handler.getPwmValue();
166    RcReceiverSignal::VALUE signal = receiver_aux1_handler.getSignalValue(pwmValue);
167
168    char buffer[100];
169
170#ifdef _4X2POS
171    bool switchA = false;
172    bool switchB = false;
173    bool switchC = false;
174    bool switchD = false;
175    demultiplex4x2Pos(signal, switchA, switchB, switchC, switchD);
176
177    //print switches state
178    sprintf(buffer, "PWM=%04d s=%04d  A=%d B=%d C=%d D=%d", 
179                      (int)pwmValue,
180                      (int)signal,
181                      switchA,
182                      switchB,
183                      switchC,
184                      switchD);
185#endif 
186#ifdef _3X2POS1X3POS
187    unsigned char switchA = 0;
188    bool switchB = false;
189    bool switchC = false;
190    bool switchD = false;
191    demultiplex3x2Pos1x3Pos(signal, switchA, switchB, switchC, switchD);
192
193    //print switches state
194    sprintf(buffer, "PWM=%04d s=%04d  A=%d B=%d C=%d D=%d", 
195                      (int)pwmValue,
196                      (int)signal,
197                      switchA,
198                      switchB,
199                      switchC,
200                      switchD);
201#endif
202#ifdef _3X3POS
203    unsigned char switchA = 0;
204    unsigned char switchB = 0;
205    unsigned char switchC = 0;
206    demultiplex3x3Pos(signal, switchA, switchB, switchC);
207
208    //print switches state
209    sprintf(buffer, "PWM=%04d s=%04d  A=%d B=%d C=%d", 
210                      (int)pwmValue,
211                      (int)signal,
212                      switchA,
213                      switchB,
214                      switchC);
215#endif
216    Serial.println(buffer);
217  }
218}

Sample data

Demultiplexing four 2-position switches : Sample data559x527
Demultiplexing a 3-Position and three 2-Position switches : Sample data539x520
Demultiplexing three 3-Position switches : Sample data533x514

Multiplexing an analog input and switches

Design

Including an analog value (usually a rotating knob) into the multiplexed signal is also possible. However, only a single analog value can be multiplexed.

Please note that including an analog value reduces the number of switches that can be multiplexed into the signal.

Define resolution

Defining the resolution of the analog value means that you must choose the granularity of the value. By default the analog value has at least 200 different values and ranges from -100% to +100%. Since you also want to multiplex switches into the same signal, the resolution must be reduced from 200 different values to a lot less. To support a desired resolution, multiple blocks will need to be sacrificed. I do recommend a resolution of 40 steps (with values from 0 to 39) which is a nice resolution to allow enough details and can also be subdivided into other zones.

What’s different

The design for including an analog value is different than having only switches.

Block size

Block size must be increased to allow the desired resolution. The higher the resolution, the less switches you can multiplex. The block size must be big enough to fit both dead zones and the desired resolution.

Dead zone

A dead zone of 3 steps is also suggested. For instance, to support a resolution of 40 different steps, the block size must be of 46 steps (3+40+3=46). The following table shows the signal range and the middle of the effective area for each block. It is calculated using a block size of 46 steps and a dead zone of 3 steps which makes the effective block size to 40 steps:

Block Number Block Offsets
Dead Effective Dead
-150 -148 -147 -108 -107 -105
1 -104 -102 -101 -62 -61 -59
2 -58 -56 -55 -16 -15 -13
3 -12 -10 -9 30 31 33
4 34 36 37 76 77 79
5 80 82 83 122 123 125
Note that only 6 blocks can be defined using a block size of 46 steps. These blocks only allows 2 sub configurations for multiplexing switches:
  • 2-position switch + 3-position switch
    • Two 2-position switches

Mixes

When multiplexing an analog value, mixes do not have to target the middle of the block’s effective zone (as with switches) since the signal’s value can move within the whole effective area of the block. Assuming the first configuration (2-pos + 3-pos), the following mixes must be created to multiplex all switches unique configurations:

Mix info Mix Output
Number Switch High Low Offset 1 2
RKnob -74 -99 -147 -73
1 RKnob 54 100 -54 -108
2 A -69 100 138
3 B -46 100 46 92

Note that first 2 mix are mapped to the right knob to reach the effective range of the first block (-147% to -108%). Switch B is a 3-position switch and offsets the analog range between block 0 to 2. Then the 3rd mix, assigned to Switch A (2-position), offsets the 3 effective block of switch B to block 0-2 or 3-5.

As you can see, the sum of all combined mixes matches the middle section of each effective block:

Block Number Switches Mixes
A B RKnob 1 2 3 Sum
-147 -147
40 -108 -108
1 1 -147 46 -101
1 1 40 -108 46 -62
2 2 -147 92 -55
2 2 40 -108 92 -16
3 1 -147 138 -9
3 1 40 -108 138 30
4 1 1 -147 138 46 37
4 1 1 40 -108 138 46 76
5 1 2 -147 138 92 83
5 1 2 40 -108 138 92 122
Use the
[ Cheat Sheet for Multiplexing an Analog Knob with a 2-position and a 3-position switch (309 downloads) ](http://www.end2endzone.com/download/1510/ "Version 1.0") for calculating all block offset when multiplexing an analog value with a 2-position and a 3-position switch. 

Decoding

Decoding an analog value with switches configuration is different: First identify the block number matching the signal’s value using a sequence of “if” statements. Then

clamp the value within the effective block area. This is required since the signal can get close to a dead zone (or even reach a dead zone!). To get the actual analog value, you must also offset the block’s effective range to get a constant 0-39 range. Finally, update switches state based on the currently selected block. Refer to tables above for offsets & switches states for each selected block.

Note that reading a value (with the micro-controller) that is outside the analog effective area should be considered the same as reading an analog value of 0 or 39 depending on the closest dead zone.

Code sample

The following arduino code (*.ino) can be used to demultiplex the scenario above:

  1//Using RcReceiverSignal v1.1.203
  2//required to read the receiver's value
  3//available at http://www.end2endzone.com/rcreceiversignal-an-arduino-library-for-retreiving-the-rc-transmitter-value-from-an-rc-receiver-pulse/
  4#include <RcReceiverSignal.h>
  5
  6//Using PinChangeInt version 2402
  7//RcReceiverSignal library has a dependency to PinChangeInt library.
  8//available at http://code.google.com/p/arduino-pinchangeint/
  9#include <PinChangeInt.h>
 10
 11//Using eRCaGuy_Timer2_Counter version 20140709 (last updated 9 July 2014)
 12//Required to have a micros() replacement function which has a 
 13//1us resolution instead of 4usec.
 14//For more information on this library, see the following:
 15// http://electricrcaircraftguy.com/2014/02/Timer2Counter-more-precise-Arduino-micros-function.html
 16// http://www.instructables.com/id/How-to-get-an-Arduino-micros-function-with-05us-pr/
 17#include <eRCaGuy_Timer2_Counter.h>
 18
 19//project's constants
 20#define RECEIVER_AUX1_IN_PIN 2 // we could choose any pin
 21
 22//project's switches
 23#define ENABLE_SERIAL_OUTPUT
 24
 25DECLARE_RECEIVER_SIGNAL(receiver_aux1_handler);
 26
 27inline short clamp(const short & iMin, const short & iValue, const short & iMax) {
 28  if (iValue < iMin)
 29    return iMin;
 30  if (iValue > iMax)
 31    return iMax;
 32  return iValue;
 33}
 34
 35void demultiplexAnalog40_1x2Pos1x3Pos(const short & iSignal, unsigned char & oAnalogA, bool & oSwitch2, unsigned char & oSwitch3) {
 36  #define setSwitches(effectiveMin,signal,effectiveMax,a,b) oAnalogA=clamp(effectiveMin,signal,effectiveMax) - (effectiveMin); oSwitch2=a; oSwitch3=b;
 37       if ( -150 <= iSignal && iSignal <= -105 ) { setSwitches( -147 ,iSignal, -108, 0, 0 ) }
 38  else if ( -104 <= iSignal && iSignal <=  -59 ) { setSwitches( -101 ,iSignal,  -62, 0, 1 ) }
 39  else if (  -58 <= iSignal && iSignal <=  -13 ) { setSwitches(  -55 ,iSignal,  -16, 0, 2 ) }
 40  else if (  -12 <= iSignal && iSignal <=   33 ) { setSwitches(   -9 ,iSignal,   30, 1, 0 ) }
 41  else if (   34 <= iSignal && iSignal <=   79 ) { setSwitches(   37 ,iSignal,   76, 1, 1 ) }
 42  else if (   80 <= iSignal && iSignal <=  125 ) { setSwitches(   83 ,iSignal,  122, 1, 2 ) }
 43  else
 44  {
 45    setSwitches( 0,0,0,0,0 );
 46  }
 47  #undef setSwitches
 48}
 49
 50uint32_t timer2GetCountWrapperFunction() {
 51  return timer2.get_count();
 52}
 53
 54void setup() {
 55  //configure Timer2
 56  timer2.setup(); //this MUST be done before the other Timer2_Counter functions work; Note: since this messes up PWM outputs on pins 3 & 11, as well as 
 57                  //interferes with the tone() library (http://arduino.cc/en/reference/tone), you can always revert Timer2 back to normal by calling 
 58                  //timer2.unsetup()
 59
 60  //configure RcReceiverSignal with an external time counter
 61  //eRCaGuy_Timer2_Counter lirary has 0.5us resolution.
 62  //The counter value must be divided by 2 to convert from 0.5us steps to 1us steps
 63  //which results in microseconds resolution.
 64  RcReceiverSignal::setExternalTimeCounter(&timer2GetCountWrapperFunction, 1, 2);
 65
 66  //link RcReceiverSignal to use PinChangeInt library
 67  RcReceiverSignal::setAttachInterruptFunction(&PCintPort::attachInterrupt);
 68  RcReceiverSignal::setPinStatePointer(&PCintPort::pinState);
 69
 70  #ifdef ENABLE_SERIAL_OUTPUT
 71    Serial.begin(115200);
 72    Serial.println("ready");
 73  #endif
 74
 75  receiver_aux1_handler_setup(RECEIVER_AUX1_IN_PIN);
 76}
 77
 78void loop() {
 79  //detect when the receiver AUX1 value has changed
 80  if (receiver_aux1_handler.hasChanged())
 81  {
 82    unsigned long pwmValue = receiver_aux1_handler.getPwmValue();
 83    RcReceiverSignal::VALUE signal = receiver_aux1_handler.getSignalValue(pwmValue);
 84
 85    char buffer[100];
 86
 87    unsigned char analogA = 0;
 88    bool switch2 = 0;
 89    unsigned char switch3 = 0;
 90    demultiplexAnalog40_1x2Pos1x3Pos(signal, analogA, switch2, switch3);
 91
 92    //print switches state
 93    sprintf(buffer, "PWM=%04d s=%04d  analogA=%2d A=%d B=%d", 
 94                      (int)pwmValue,
 95                      (int)signal,
 96                      analogA,
 97                      switch2,
 98                      switch3);
 99    Serial.println(buffer);
100  }
101}

Sample data

Demultiplexing an analog knob with a 2-Position and a 3-Position switch : Sample data498x510

Say Something

Comments

Recent Posts

Categories

About

Hey! I'm Antoine author of end2end zone. Take a couple of minutes to get to know me a little better.