Emre's Bench

a place for the electronic hobbyist

MCP41010 Digital Potentiometer Arduino Tutorial

Providing Analog Output Control

MCP41010 Digital Potentiometer IC

The MCP41010 is a digital potentiometer that is controlled using the SPI (Serial Peripheral Interface) Interface. It provides a 10kΩ potentiometer that is fully adjustable using 256 steps (0-255), offering approximately 39 ohms per step.

This allows your Arduino to programmatically control resistance, which can be used, for example, to create a variable voltage output when used as a voltage divider.

Getting an MCP41010

You may purchase an MCP41010 at any of the following locations:

Amazon

AliExpress

eBay

MCP41010 Pin Outs

The device pin outs are shown below (for the PDIP package):

MCP41010 Digital Potentiometer Pinout Diagram
  • Pin 1 (CS): Chip Select (Input, Active LOW). When LOW, the chip listens for SPI commands.
  • Pin 2 (SCK): Serial Clock (Input). Clock input from the Arduino SPI master.
  • Pin 3 (SI): Serial Data Input (Input). Receives commands from the Arduino when CS is LOW. Sometimes labeled SDI or MOSI.
  • Pin 4 (Vss): Negative Supply or Ground (Connect to GND).
  • Pin 5 (PA0): Potentiometer Terminal A. One end of the internal resistor.
  • Pin 6 (PW0): Potentiometer Wiper Output. The adjustable tap point.
  • Pin 7 (PB0): Potentiometer Terminal B. The other end of the internal resistor.
  • Pin 8 (Vdd): Positive Supply Voltage (Connect to 5V or 3.3V, depending on your Arduino).

The Potentiometer Output

The position of the internal wiper connecting PW0 (Pin 6) to a point along the resistance between PA0 (Pin 5) and PB0 (Pin 7) is controlled via SPI commands. With a fixed voltage applied across terminals A and B (e.g., 5V on A, GND on B), sending SPI commands to change the wiper position (0-255) will change the voltage output at the wiper pin (PW0).

MCP41010 Digital Potentiometer Wiper Diagram

MCP41010 Arduino Tutorial

This tutorial connects the MCP41010 to the Arduino via the standard SPI pins. Potentiometer terminals A (PA0) and B (PB0) are connected to the Arduino 5V and Ground, respectively, creating a voltage divider. The wiper (PW0) output is connected to Arduino Analog Pin A1 to read the resulting voltage.

The sketch cycles the digital potentiometer through all 256 possible wiper positions, reading the voltage at the wiper for each step and printing the level and corresponding voltage to the Serial Monitor.

Connections to the Arduino

Connect your Arduino to the MCP41010 potentiometer as shown below (pins for Arduino Uno/Nano):

MCP41010 Arduino Connections Diagram
  • MCP41010 Pin 1 (CS) to Arduino Pin 10 (SS/CS)
  • MCP41010 Pin 2 (SCK) to Arduino Pin 13 (SCK)
  • MCP41010 Pin 3 (SI) to Arduino Pin 11 (MOSI)
  • MCP41010 Pin 4 (Vss) to Arduino GND
  • MCP41010 Pin 5 (PA0) to Arduino 5V
  • MCP41010 Pin 6 (PW0) to Arduino Analog Pin A1
  • MCP41010 Pin 7 (PB0) to Arduino GND
  • MCP41010 Pin 8 (Vdd) to Arduino 5V

Arduino Sketch

This code uses the standard Arduino SPI library to communicate with the MCP41010.

/*
  Emre's Bench - MCP41010 Digital Potentiometer Tutorial
  Demonstrates controlling the MCP41010 via SPI and reading the wiper voltage.
*/

#include <SPI.h>

const int chipSelectPin = 10;    // SPI Chip Select pin (SS on Uno/Nano)
const int wiperReadPin = A1;     // Analog pin to read the wiper voltage

void setup() {
  // Set the Chip Select pin as an output
  pinMode (chipSelectPin, OUTPUT);
  // Set the default SS pin as an output (required by SPI library even if not used for CS)
  pinMode (SS, OUTPUT); 
  
  Serial.begin(9600);
  SPI.begin(); // Initialize SPI library
  
  Serial.println("MCP41010 Test");
}

void loop() {
  int rawVoltage = 0;
  float voltage = 0.0;

  Serial.println("Sweeping Wiper UP (0 to 255):");
  // Move the potentiometer wiper from 0 to 255
  for (int level = 0; level <= 255; level++) {
    MCP41010Write(level); // Send the new wiper position
    delay(50); // Small delay for stability and readability

    // Read the voltage at the wiper
    rawVoltage = analogRead(wiperReadPin);
    voltage = (rawVoltage * 5.0) / 1023.0; // Convert ADC reading to voltage (assuming 5V reference)

    Serial.print("Level = ");
    Serial.print(level);
    Serial.print("\t Raw = ");
    Serial.print(rawVoltage);
    Serial.print("\t Voltage = ");
    Serial.println(voltage, 3); // Print voltage with 3 decimal places
  }

  delay(2000); // Wait a couple seconds

  Serial.println("\nSweeping Wiper DOWN (255 to 0):");
  // Now move potentiometer wiper back down
  for (int level = 255; level >= 0; level--) {
    MCP41010Write(level);
    delay(50); 

    rawVoltage = analogRead(wiperReadPin);
    voltage = (rawVoltage * 5.0) / 1023.0; 

    Serial.print("Level = ");
    Serial.print(level);
    Serial.print("\t Raw = ");
    Serial.print(rawVoltage);      
    Serial.print("\t Voltage = ");
    Serial.println(voltage, 3);
  }
   delay(2000); // Wait before repeating
}

// Function to send command and value to MCP41010
void MCP41010Write(byte value) {
  // Take the Chip Select pin LOW to select the chip
  digitalWrite(chipSelectPin, LOW);
  
  // Send the command byte (0x11 for writing to Potentiometer 0)
  SPI.transfer(B00010001); 
  // Send the value byte (0-255) for the wiper position
  SPI.transfer(value);     
  
  // Take the Chip Select pin HIGH to release the chip
  digitalWrite(chipSelectPin, HIGH); 
}

Sketch Results

Open the Serial Monitor (9600 baud). You should see the output voltage smoothly changing as the `level` value cycles from 0 to 255 and back down. The voltage should range from approximately 0V (at level 0) to 5V (at level 255).

Note: Due to internal resistances and tolerances, the minimum and maximum voltages might not be exactly 0V and 5V. The voltage change per step should be roughly consistent (around 5V / 256 steps ≈ 19.5 mV/step).