LCOV - code coverage report
Current view: top level - src/AH/Hardware/ExtendedInputOutput - AnalogMultiplex.hpp (source / functions) Coverage Total Hit
Test: 73449d9b107c772cf65493691543348214e5d5eb Lines: 100.0 % 50 50
Test Date: 2026-06-06 17:44:35 Functions: 78.3 % 23 18
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* ✔ */
       2              : 
       3              : #pragma once
       4              : 
       5              : #include "ExtendedInputOutput.hpp"
       6              : #include "StaticSizeExtendedIOElement.hpp"
       7              : #include <AH/Containers/Array.hpp>
       8              : #include <stdlib.h>
       9              : 
      10              : BEGIN_AH_NAMESPACE
      11              : 
      12              : /**
      13              :  * @brief   A class for reading multiplexed analog inputs.
      14              :  *          Supports 74HC4067, 74HC4051, etc.
      15              :  * 
      16              :  * You can use many multiplexers on the same address lines if each of the 
      17              :  * multiplexers has a different enable line.
      18              :  * 
      19              :  * @tparam  N 
      20              :  *          The number of address lines.
      21              :  * 
      22              :  * @ingroup AH_ExtIO
      23              :  */
      24              : template <uint8_t N>
      25              : class AnalogMultiplex : public StaticSizeExtendedIOElement<1 << N> {
      26              :   public:
      27              :     /**
      28              :      * @brief   Create a new AnalogMultiplex object on the given pins.
      29              :      * 
      30              :      * @param   analogPin
      31              :      *          The analog input pin connected to the output of the multiplexer.
      32              :      * @param   addressPins
      33              :      *          An array of the pins connected to the address lines of the
      34              :      *          multiplexer. (Labeled S0, S1, S2 ... in the datasheet.)
      35              :      * @param   enablePin
      36              :      *          The digital output pin connected to the enable pin of the
      37              :      *          multiplexer. (Labeled Ē in the datasheet.)  
      38              :      *          If you don't need the enable pin, you can use NO_PIN, which is 
      39              :      *          the default.
      40              :      */
      41           10 :     AnalogMultiplex(pin_t analogPin, const Array<pin_t, N> &addressPins,
      42              :                     pin_t enablePin = NO_PIN)
      43           10 :         : analogPin(analogPin), addressPins(addressPins), enablePin(enablePin) {
      44           10 :     }
      45              : 
      46              :     /**
      47              :      * @brief   Set the pin mode of the analog input pin.  
      48              :      *          This allows you to enable the internal pull-up resistor, for
      49              :      *          use with buttons or open-collector outputs.
      50              :      * 
      51              :      * @note    This applies to all pins of this multiplexer.  
      52              :      *          This affects all pins of the multiplexer, because it has only
      53              :      *          a single common pin.  
      54              :      * 
      55              :      * @param   pin
      56              :      *          (Unused)
      57              :      * @param   mode
      58              :      *          The new mode of the input pin: 
      59              :      *          either INPUT or INPUT_PULLUP.
      60              :      */
      61              :     void pinMode(pin_int_t pin, PinMode_t mode) override;
      62              : 
      63              :     /**
      64              :      * @copydoc pinMode
      65              :      */
      66              :     void pinModeBuffered(pin_int_t pin, PinMode_t mode) override;
      67              : 
      68              :     /**
      69              :      * @brief   The digitalWrite function is not implemented because writing an
      70              :      *          output to a multiplexer is not useful.
      71              :      */
      72              :     void digitalWrite(pin_int_t, PinStatus_t) override // LCOV_EXCL_LINE
      73              :         __attribute__((deprecated)) {}                 // LCOV_EXCL_LINE
      74              : 
      75              :     /**
      76              :      * @copydoc digitalWrite
      77              :      */
      78              :     void digitalWriteBuffered(pin_int_t, PinStatus_t) override // LCOV_EXCL_LINE
      79              :         __attribute__((deprecated)) {}                         // LCOV_EXCL_LINE
      80              : 
      81              :     /**
      82              :      * @brief   Read the digital state of the given input.
      83              :      * 
      84              :      * @param   pin
      85              :      *          The multiplexer's pin number to read from.
      86              :      */
      87              :     PinStatus_t digitalRead(pin_int_t pin) override;
      88              : 
      89              :     /**
      90              :      * @copydoc digitalRead
      91              :      */
      92              :     PinStatus_t digitalReadBuffered(pin_int_t pin) override;
      93              : 
      94              :     /**
      95              :      * @brief   Read the analog value of the given input.
      96              :      * 
      97              :      * @param   pin
      98              :      *          The multiplexer's pin number to read from.
      99              :      */
     100              :     analog_t analogRead(pin_int_t pin) override;
     101              : 
     102              :     /**
     103              :      * @copydoc analogRead
     104              :      */
     105              :     analog_t analogReadBuffered(pin_int_t pin) override;
     106              : 
     107              :     /**
     108              :      * @brief   The analogWrite function is not implemented because writing an
     109              :      *          output to a multiplexer is not useful.
     110              :      */
     111              :     void analogWrite(pin_int_t, analog_t) override // LCOV_EXCL_LINE
     112              :         __attribute__((deprecated)) {}             // LCOV_EXCL_LINE
     113              : 
     114              :     /**
     115              :      * @copydoc analogWrite
     116              :      */
     117              :     void analogWriteBuffered(pin_int_t, analog_t) override // LCOV_EXCL_LINE
     118              :         __attribute__((deprecated)) {}                     // LCOV_EXCL_LINE
     119              : 
     120              :     /**
     121              :      * @brief   Initialize the multiplexer: set the pin mode of the address pins
     122              :      *          and the enable pin to output mode.
     123              :      */
     124              :     void begin() override;
     125              : 
     126              :     /**
     127              :      * @brief   No periodic updating of the state is necessary, all actions are 
     128              :      *          carried out when the user calls analogRead or digitalRead.
     129              :      */
     130              :     void updateBufferedOutputs() override {} // LCOV_EXCL_LINE
     131              : 
     132              :     /**
     133              :      * @brief   No periodic updating of the state is necessary, all actions are 
     134              :      *          carried out when the user calls analogRead or digitalRead.
     135              :      */
     136              :     void updateBufferedInputs() override {} // LCOV_EXCL_LINE
     137              : 
     138              :     /**
     139              :      * @brief   Specify whether to discard the first analog reading after 
     140              :      *          changing the address lines (enabled by default).
     141              :      */
     142            1 :     void discardFirstReading(bool discardFirstReading_) {
     143            1 :         this->discardFirstReading_ = discardFirstReading_;
     144            1 :     }
     145              : 
     146              :   protected:
     147              :     const pin_t analogPin;
     148              :     const Array<pin_t, N> addressPins;
     149              :     const pin_t enablePin;
     150              :     bool discardFirstReading_ = true;
     151              : 
     152              :     /**
     153              :      * @brief   Write the pin number/address to the address pins of the 
     154              :      *          multiplexer.
     155              :      * 
     156              :      * @param   address
     157              :      *          The address to select.
     158              :      */
     159              :     void setMuxAddress(uint8_t address);
     160              : 
     161              :     /**
     162              :      * @brief   Select the correct address and enable the multiplexer.
     163              :      * 
     164              :      * @param   address
     165              :      *          The address to select.
     166              :      */
     167              :     void prepareReading(uint8_t address);
     168              : 
     169              :     /**
     170              :      * @brief   Disable the multiplexer.
     171              :      */
     172              :     void afterReading();
     173              : 
     174              :     // The enable pin is active low.
     175              :     constexpr static auto MUX_ENABLED = LOW;
     176              :     constexpr static auto MUX_DISABLED = HIGH;
     177              : };
     178              : 
     179              : /**
     180              :  * @brief   An alias for AnalogMultiplex<4> to use with CD74HC4067 analog 
     181              :  *          multiplexers.
     182              :  * 
     183              :  * @ingroup AH_ExtIO
     184              :  */
     185              : using CD74HC4067 = AnalogMultiplex<4>;
     186              : 
     187              : /**
     188              :  * @brief   An alias for AnalogMultiplex<3> to use with CD74HC4051 analog 
     189              :  *          multiplexers.
     190              :  * 
     191              :  * @ingroup AH_ExtIO
     192              :  */
     193              : using CD74HC4051 = AnalogMultiplex<3>;
     194              : 
     195              : // -------------------------------------------------------------------------- //
     196              : 
     197              : template <uint8_t N>
     198            2 : void AnalogMultiplex<N>::pinMode(pin_int_t, PinMode_t mode) {
     199            2 :     ExtIO::pinMode(analogPin, mode);
     200            2 : }
     201              : 
     202              : template <uint8_t N>
     203            1 : void AnalogMultiplex<N>::pinModeBuffered(pin_int_t p, PinMode_t mode) {
     204            1 :     AnalogMultiplex<N>::pinMode(p, mode);
     205            1 : }
     206              : 
     207              : template <uint8_t N>
     208            3 : PinStatus_t AnalogMultiplex<N>::digitalRead(pin_int_t pin) {
     209            3 :     prepareReading(static_cast<uint8_t>(pin));
     210            3 :     PinStatus_t result = ExtIO::digitalRead(analogPin);
     211            3 :     afterReading();
     212            3 :     return result;
     213              : }
     214              : 
     215              : template <uint8_t N>
     216            1 : PinStatus_t AnalogMultiplex<N>::digitalReadBuffered(pin_int_t pin) {
     217            1 :     return AnalogMultiplex<N>::digitalRead(pin);
     218              : }
     219              : 
     220              : template <uint8_t N>
     221           11 : analog_t AnalogMultiplex<N>::analogRead(pin_int_t pin) {
     222           11 :     prepareReading(static_cast<uint8_t>(pin));
     223           11 :     if (discardFirstReading_)
     224            8 :         (void)ExtIO::analogRead(analogPin); // Discard first reading
     225           11 :     analog_t result = ExtIO::analogRead(analogPin);
     226           11 :     afterReading();
     227           11 :     return result;
     228              : }
     229              : 
     230              : template <uint8_t N>
     231            1 : analog_t AnalogMultiplex<N>::analogReadBuffered(pin_int_t pin) {
     232            1 :     return AnalogMultiplex<N>::analogRead(pin);
     233              : }
     234              : 
     235              : template <uint8_t N>
     236           10 : void AnalogMultiplex<N>::begin() {
     237           49 :     for (const pin_t &addressPin : addressPins)
     238           39 :         ExtIO::pinMode(addressPin, OUTPUT);
     239           10 :     if (enablePin != NO_PIN) {
     240            7 :         ExtIO::pinMode(enablePin, OUTPUT);
     241            7 :         ExtIO::digitalWrite(enablePin, MUX_DISABLED);
     242              :     }
     243           10 : }
     244              : 
     245              : template <uint8_t N>
     246           14 : void AnalogMultiplex<N>::setMuxAddress(uint8_t address) {
     247           14 :     uint8_t mask = 1;
     248           67 :     for (const pin_t &addressPin : addressPins) {
     249           53 :         ExtIO::digitalWrite(addressPin, (address & mask) != 0 ? HIGH : LOW);
     250           53 :         mask <<= 1;
     251              :     }
     252              : #if !defined(__AVR__) && defined(ARDUINO)
     253              :     delayMicroseconds(SELECT_LINE_DELAY);
     254              : #endif
     255           14 : }
     256              : 
     257              : template <uint8_t N>
     258           14 : void AnalogMultiplex<N>::prepareReading(uint8_t address) {
     259           14 :     setMuxAddress(address);
     260           14 :     if (enablePin != NO_PIN)
     261            7 :         ExtIO::digitalWrite(enablePin, MUX_ENABLED);
     262           14 : }
     263              : 
     264              : template <uint8_t N>
     265           14 : void AnalogMultiplex<N>::afterReading() {
     266           14 :     if (enablePin != NO_PIN)
     267            7 :         ExtIO::digitalWrite(enablePin, MUX_DISABLED);
     268           14 : }
     269              : 
     270              : END_AH_NAMESPACE
        

Generated by: LCOV version 2.4-beta