Control Surface  1.1.0
MIDI Control Surface library for Arduino
AnalogMultiplex.hpp
Go to the documentation of this file.
1 /* ✔ */
2 
3 #pragma once
4 
6 AH_DIAGNOSTIC_WERROR() // Enable errors on warnings
7 
8 #include "ExtendedInputOutput.hpp"
10 #include <AH/Containers/Array.hpp>
11 #include <stdlib.h>
12 
14 
15 /**
16  * @brief A class for reading multiplexed analog inputs.
17  * Supports 74HC4067, 74HC4051, etc.
18  *
19  * You can use many multiplexers on the same address lines if each of the
20  * multiplexers has a different enable line.
21  *
22  * @tparam N
23  * The number of address lines.
24  *
25  * @ingroup AH_ExtIO
26  */
27 template <uint8_t N>
29  public:
30  /**
31  * @brief Create a new AnalogMultiplex object on the given pins.
32  *
33  * @param analogPin
34  * The analog input pin connected to the output of the multiplexer.
35  * @param addressPins
36  * An array of the pins connected to the address lines of the
37  * multiplexer. (Labeled S0, S1, S2 ... in the datasheet.)
38  * @param enablePin
39  * The digital output pin connected to the enable pin of the
40  * multiplexer. (Labeled Ē in the datasheet.)
41  * If you don't need the enable pin, you can use NO_PIN, which is
42  * the default.
43  */
44  AnalogMultiplex(pin_t analogPin, const Array<pin_t, N> &addressPins,
45  pin_t enablePin = NO_PIN)
46  : analogPin(analogPin), addressPins(addressPins), enablePin(enablePin) {
47  }
48 
49  /**
50  * @brief Set the pin mode of the analog input pin.
51  * This allows you to enable the internal pull-up resistor, for
52  * use with buttons or open-collector outputs.
53  *
54  * @note This applies to all pins of this multiplexer.
55  * This affects all pins of the multiplexer, because it has only
56  * a single common pin.
57  *
58  * @param pin
59  * (Unused)
60  * @param mode
61  * The new mode of the input pin:
62  * either INPUT or INPUT_PULLUP.
63  */
64  void pinMode(pin_t pin, uint8_t mode) override;
65 
66  /**
67  * @brief The digitalWrite function is not implemented because writing an
68  * output to a multiplexer is not useful.
69  */
70  void digitalWrite(pin_t, uint8_t) override // LCOV_EXCL_LINE
71  __attribute__((deprecated)) {} // LCOV_EXCL_LINE
72 
73  /**
74  * @brief Read the digital state of the given input.
75  *
76  * @param pin
77  * The multiplexer's pin number to read from.
78  */
79  int digitalRead(pin_t pin) override;
80 
81  /**
82  * @brief Read the analog value of the given input.
83  *
84  * @param pin
85  * The multiplexer's pin number to read from.
86  */
87  analog_t analogRead(pin_t pin) override;
88 
89  /**
90  * @brief The analogWrite function is not implemented because writing an
91  * output to a multiplexer is not useful.
92  */
93  void analogWrite(pin_t, analog_t) override // LCOV_EXCL_LINE
94  __attribute__((deprecated)) {} // LCOV_EXCL_LINE
95 
96  /**
97  * @brief Initialize the multiplexer: set the pin mode of the address pins
98  * and the enable pin to output mode.
99  */
100  void begin() override;
101 
102  /**
103  * @brief No periodic updating of the state is necessary, all actions are
104  * carried out when the user calls analogRead or digitalRead.
105  */
106  void update() override {} // LCOV_EXCL_LINE
107 
108  private:
109  const pin_t analogPin;
110  const Array<pin_t, N> addressPins;
111  const pin_t enablePin;
112 
113  /**
114  * @brief Write the pin number/address to the address pins of the
115  * multiplexer.
116  *
117  * @param address
118  * The address to select.
119  */
120  void setMuxAddress(uint8_t address);
121 
122  /**
123  * @brief Select the correct address and enable the multiplexer.
124  *
125  * @param address
126  * The address to select.
127  */
128  void prepareReading(uint8_t address);
129 
130  /**
131  * @brief Disable the multiplexer.
132  */
133  void afterReading();
134 
135  // The enable pin is active low.
136  constexpr static uint8_t MUX_ENABLED = LOW;
137  constexpr static uint8_t MUX_DISABLED = HIGH;
138 };
139 
140 /**
141  * @brief An alias for AnalogMultiplex<4> to use with CD74HC4067 analog
142  * multiplexers.
143  *
144  * @ingroup AH_ExtIO
145  */
146 using CD74HC4067 = AnalogMultiplex<4>;
147 
148 /**
149  * @brief An alias for AnalogMultiplex<3> to use with CD74HC4051 analog
150  * multiplexers.
151  *
152  * @ingroup AH_ExtIO
153  */
154 using CD74HC4051 = AnalogMultiplex<3>;
155 
156 // -------------------------------------------------------------------------- //
157 
158 template <uint8_t N>
159 void AnalogMultiplex<N>::pinMode(pin_t, uint8_t mode) {
160  ExtIO::pinMode(analogPin, mode);
161 }
162 
163 template <uint8_t N>
164 int AnalogMultiplex<N>::digitalRead(pin_t pin) {
165  prepareReading(pin);
166  int result = ExtIO::digitalRead(analogPin);
167  afterReading();
168  return result;
169 }
170 
171 template <uint8_t N>
172 analog_t AnalogMultiplex<N>::analogRead(pin_t pin) {
173  prepareReading(pin);
174  ExtIO::analogRead(analogPin); // Discard first reading
175  analog_t result = ExtIO::analogRead(analogPin);
176  afterReading();
177  return result;
178 }
179 
180 template <uint8_t N>
181 void AnalogMultiplex<N>::begin() {
182  for (const pin_t &addressPin : addressPins)
183  ExtIO::pinMode(addressPin, OUTPUT);
184  if (enablePin != NO_PIN) {
185  ExtIO::pinMode(enablePin, OUTPUT);
186  ExtIO::digitalWrite(enablePin, MUX_DISABLED);
187  }
188 }
189 
190 template <uint8_t N>
191 void AnalogMultiplex<N>::setMuxAddress(uint8_t address) {
192  uint8_t mask = 1;
193  for (const pin_t &addressPin : addressPins) {
194  ExtIO::digitalWrite(addressPin, (address & mask) != 0);
195  mask <<= 1;
196  }
197 #if !defined(__AVR__) && !defined(__x86_64__)
198  delayMicroseconds(5);
199 #endif
200 }
201 
202 template <uint8_t N>
203 void AnalogMultiplex<N>::prepareReading(uint8_t address) {
204  setMuxAddress(address);
205  if (enablePin != NO_PIN)
206  ExtIO::digitalWrite(enablePin, MUX_ENABLED);
207 }
208 
209 template <uint8_t N>
210 void AnalogMultiplex<N>::afterReading() {
211  if (enablePin != NO_PIN)
212  ExtIO::digitalWrite(enablePin, MUX_DISABLED);
213 }
214 
215 END_AH_NAMESPACE
216 
217 AH_DIAGNOSTIC_POP()
Warnings.hpp
Array.hpp
AH::AnalogMultiplex
A class for reading multiplexed analog inputs.
Definition: AnalogMultiplex.hpp:28
StaticSizeExtendedIOElement.hpp
AH::StaticSizeExtendedIOElement
A class for ExtendedIOElements with a fixed size.
Definition: StaticSizeExtendedIOElement.hpp:19
AH_DIAGNOSTIC_WERROR
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:16
BEGIN_AH_NAMESPACE
#define BEGIN_AH_NAMESPACE
Definition: AH/Settings/NamespaceSettings.hpp:9