Adding ir remote and 7seg to a x9c104

I want to replace x9c104 digipot with an analog pot of a speaker. I have a working code with physical buttons and I want to replace ir remote buttons with physical ones. also I know that these digipots have 100 positions so I was wondering if we could read those positions and show them on a 7seg display. here is my remote hex codes and functions that I'm after:
“20DF40BF” this button to act as buttonPotUp1
“20DFC03F” this one act as buttonPotDn1
“20DF906F” this one act as buttonPotMax and if pressed again act as buttonPotMid
this is my 7seg datasheet:
here is the code with physical buttons:
Thanks in advance.


#include <X9C.h>                // X9C pot library
#include <Bounce2.h>            // button debounce library

#define UD              10      // pot up/down mode pin
#define INC             11      // pot increment pin
#define CS              12      // pot chip select pin
#define buttonPotMin    3       // button to set pot to min point
#define buttonPotMid    4       // button to set pot to mid point
#define buttonPotMax    5       // button to set pot to max point
#define buttonPotUp10   6       // button to inc pot by 10
#define buttonPotDn10   7       // button to dec pot by 10
#define buttonPotUp1    8       // button to inc pot by 1
#define buttonPotDn1    9       // button to dec pot by 1

// X9C wiring:  pin 3[High Terminal] -- R1 -- pin 5[Wiper] -- R2 -- pin 6[Low Terminal]

// The "X9C_UP" direction refers to the amount of resistance being created between the wiper and the "High" terminal 
// rather than the position of the wiper itself moving up toward the high terminal 
// (which would reduce resistance from wiper to High).
// i.e. setPot(70, false) will set the resistance between the X9C device pins 5 and 3 to 70% of maximum resistance
// where R1 = 70% of max, R2 = 30% of max

const int debounceInterval = 10;    // debounce time (ms) for button readings

X9C pot;                            // instantiate a pot controller
Bounce buttonPotMinDB  = Bounce();  // instantiate a bounce object for each button
Bounce buttonPotMidDB  = Bounce();
Bounce buttonPotMaxDB  = Bounce();
Bounce buttonPotUp10DB = Bounce();
Bounce buttonPotDn10DB = Bounce();
Bounce buttonPotUp1DB  = Bounce();
Bounce buttonPotDn1DB  = Bounce();

void setup() {
  pot.begin(CS, INC, UD);

  pinMode(buttonPotMin,  INPUT_PULLUP);
  pinMode(buttonPotMid,  INPUT_PULLUP);
  pinMode(buttonPotMax,  INPUT_PULLUP);
  pinMode(buttonPotUp10, INPUT_PULLUP);
  pinMode(buttonPotDn10, INPUT_PULLUP);
  pinMode(buttonPotUp1,  INPUT_PULLUP);
  pinMode(buttonPotDn1,  INPUT_PULLUP);

  // attach buttons to debouncers
  buttonPotMinDB.interval(debounceInterval);      // interval in ms

  buttonPotMidDB.interval(debounceInterval);      // interval in ms

  buttonPotMaxDB.interval(debounceInterval);      // interval in ms

  buttonPotUp10DB.interval(debounceInterval);      // interval in ms

  buttonPotDn10DB.interval(debounceInterval);      // interval in ms

  buttonPotUp1DB.interval(debounceInterval);      // interval in ms

  buttonPotDn1DB.interval(debounceInterval);      // interval in ms


void loop() {

  // update the Bounce instances

  // change potentiometer setting if required based on button presses,
  // storing the setting in the chip if "true" is passed to the pot controller

  if ( buttonPotMinDB.fell()) {
    pot.setPotMin(false);                // set pot wiper to 0 resistance (pot will have wiper resistance per datasheet)

  if ( buttonPotMidDB.fell()) {
    pot.setPot(49, false);               // set pot wiper to about half way (between 0 and 99)

  if ( buttonPotMaxDB.fell()) {
    pot.setPotMax(false);                // set pot wiper to full resistance

  if ( buttonPotUp10DB.fell()) {
    pot.trimPot(10, X9C_UP, true);      // move pot wiper 10 positions up ***AND STORE SETTING IN X9C CHIP***

  if ( buttonPotDn10DB.fell()) {
    pot.trimPot(10, X9C_DOWN, false);    // move pot wiper 10 positions down

  if ( buttonPotUp1DB.fell()) {
    pot.trimPot(1, X9C_UP, false);       // move pot wiper 1 position up

  if ( buttonPotDn1DB.fell()) {
    pot.trimPot(1, X9C_DOWN, true);     // move pot wiper 1 position down

So you intend to develop a system with the following components:

  1. An x9c104 digital potentiometer
  2. An 7 segment 4 digit common anode display CL3641BH
  3. An IR remote control unit
  4. An IR receiver

The purpose is to control a loudspeaker.

A. Have you checked that the x9c104 is suitable for this application (voltage, load etc.)?
B. What IR remote control device have you which generates the codes you've supplied ?
C. What IR receiver have you ?
D. How do you intend to drive that 7 segment display. Using a driver chip ?
E. Have you tested that supplied code actually works or have you just found it ?

1 Like

yes, those are my components plus Arduino nano.
A. I checked the digipot and it works perfectly with my speaker.
B. I use LG TV magic remote and it is with NEC protocols.
C. the IR receiver is VS1338B
D. I was hoping to drive the 7 seg with wiring to resistors and Arduino because I saw a page that did so. this is the webpage:
E. yes I've tested the code and it decreases and increases the volume perfectly with physical buttons.

D. It is indeed possible to drive a 4 digit 7 segment display directly from an Arduino Uno (or similar). However. for that, you need 12 free pins (or 11 if you don't need the decimal point). You may also need 4 transistors, depending on the required brightness. If you use a driver chip you can, in the best case, reduce that to two pins.

I don't need decimal points and I also don't need the 4th digit because this potentiometer only has 100 positions.
I have 8 digital and 7 analog pins free

OK. If you can work with 2 digits and maybe a display of less that optimum brightness, you can get away with just 9 pins for the display, if directly driven.

You need 3 pins for the x9c104 as far as I see.

You need 1 pin for the IR receiver.

So, for a Nano or Uno, that should work. Pins A0 to A5 can also be used as digital pins.

I suggest getting what currently works, that is the x9c104, together with the IR part working first. When that is stable, then add on the display part.
Maybe then start by looking at some simple examples of usage of the Arduino IR library.

1 Like

yes, that will do for now. I checked many examples of IR libraries but I couldn't get them to work because of my limited coding knowledge. Currently, I'm learning and I would appreciate it if you could help me with this project.

The first step is to get the IR working in such a way that you can press a button on your remote control and see a response in the serial monitor.

Install the latest version of the IRremote library using the Arduino library manager. This is version is 3.3.0 (well it was today 15.05.2021 21:00 CEST). Try the example code at: Arduino-IRremote/SimpleReceiver.ino at master · Arduino-IRremote/Arduino-IRremote · GitHub and see if you get responses from your remote. You'll need to connect your VS1338B IR receiver to pin 2 (as far as I can see).

1 Like

I did that and I get the signal. these are 3 keys that I need:
Protocol=NEC Address=0x4 Command=0x2 Raw-Data=0xFD02FB04 32 bits LSB first

Protocol=NEC Address=0x4 Command=0x3 Raw-Data=0xFC03FB04 32 bits LSB first

Protocol=NEC Address=x4 Command=0x9 Raw-Data=0xF609FB04 32 bits LSB firt

OK. Good. Post the code that you did that with and the next step is to attempt to integrate into it the calls to the x9c104

If not using the transistors for the digits, use (at least) 1k resistors for the segments to limit the common digit current.

With one of these displays. :sunglasses: (Clock display; colon but no decimals.)

this is the code

 * SimpleReceiver.cpp
 * Demonstrates receiving NEC IR codes with IRrecv
 *  Copyright (C) 2020-2021  Armin Joachimsmeyer
 *  This file is part of Arduino-IRremote
 *  MIT License

 * Specify which protocol(s) should be used for decoding.
 * If no protocol is defined, all protocols are active.
//#define DECODE_DENON        // Includes Sharp
//#define DECODE_JVC
//#define DECODE_PANASONIC    // the same as DECODE_KASEIKYO
//#define DECODE_LG
#define DECODE_NEC          // Includes Apple and Onkyo
//#define DECODE_SONY
//#define DECODE_RC5
//#define DECODE_RC6

//#define DECODE_LEGO_PF

//#define DECODE_DISTANCE     // universal decoder for pulse width or pulse distance protocols
//#define DECODE_HASH         // special decoder for all protocols

#include <Arduino.h>

 * Define macros for input and output pin etc.
#include "PinDefinitionsAndMore.h"

#include <IRremote.h>

void setup() {
    // Just to know which program is running on my Arduino
    Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE));

     * Start the receiver, enable feedback LED and take LED feedback pin from the internal boards definition

    Serial.print(F("Ready to receive IR signals at pin "));

void loop() {
     * Check if received data is available and if yes, try to decode it.
     * Decoded result is in the IrReceiver.decodedIRData structure.
     * E.g. command is in IrReceiver.decodedIRData.command
     * address is in command is in IrReceiver.decodedIRData.address
     * and up to 32 bit raw data in IrReceiver.decodedIRData.decodedRawData
    if (IrReceiver.decode()) {

        // Print a short summary of received data
        if (IrReceiver.decodedIRData.protocol == UNKNOWN) {
            // We have an unknown protocol here, print more info
            IrReceiver.printIRResultRawFormatted(&Serial, true);

         * !!!Important!!! Enable receiving of the next value,
         * since receiving has stopped after the end of the current received data packet.
        IrReceiver.resume(); // Enable receiving of the next value

         * Finally, check the received data and perform actions according to the received command
        if (IrReceiver.decodedIRData.command == 0x3) {
            // do something
        } else if (IrReceiver.decodedIRData.command == 0x2) {
            // do something el

yep . I was planning to use 1k resistors

could anybody help me with combining the IR buttons with the x9c104 codes?

As I see it, you have to copy the initial part of the X9C code into the IR code sample you have created.
Mainly these bits:

#include <X9C.h>                // X9C pot library

#define UD              10      // pot up/down mode pin
#define INC             11      // pot increment pin
#define CS              12      // pot chip select pin

X9C pot;                            // instantiate a pot controller

 pot.begin(CS, INC, UD);  // in setup()

Then you have to replace part of the loop() in the IR code with something like this:

if (IrReceiver.decodedIRData.command == 0x2 ) {
  pot.trimPot(1, X9C_UP, false);       // move pot wiper 1 position up
else if (IrReceiver.decodedIRData.command == 0x3) {
  pot.trimPot(1, X9C_DOWN, true);     // move pot wiper 1 position down
else if (IrReceiver.decodedIRData.command == 0x9) {
  // the two commands here should be toggled (future)
  pot.setPotMax(false);                // set pot wiper to full resistance
  // pot.setPot(49, false);               // set pot wiper to about half way (between 0 and 99)
else {
  // unknown command

You will then have to handle the toggling of the command 0x9 where the same button has an alternative function.

1 Like

woooow. It worked Thank you so much.
now I have to figure out the toggle button and 7 segment
does anyone know how to make an IR button toggle between 2 functions?

Hint 1: Use a state variable to remember the it's state. First its false, then set true, then set false etc.
Hint 2: There is a current user question on the forum where the SevSeg.h library is in use to control a seven segment display.

I cannot understand this part. could you please explain how? so sorry I'm a rookie

I've searched a lot but couldn't find anything that can help me. any help would be appreciated

Try this for the alternative function.

else if (IrReceiver.decodedIRData.command == 0x9) {
  // alternate full/half
  static bool comm0x9Toggle = false ;                        // set automatically only one at start of program execution
  if ( comm0x9Toggle == false ) pot.setPotMax(false);        // set pot wiper to full resistance
  else pot.setPot(49, false);                                // set pot wiper to about half way (between 0 and 99)
  comm0x9Toggle = ! comm0x9Toggle ;                          // invert comm0x9Toggle

For driving a seven segment display, see here folowing links and examples:

Note: you can't extract the current state from the X9C chip so you have to keep a counter of the pulses/commands sent to it to determine what you display.

1 Like