First off... I must apologize for this shotty looking diagram, but hopefully it helps:
I plan on using a digital potentiometer in a project I'm working on and this is an example circuit. It basically uses a rotary encoder to control the X9C103P digipot, and a voltage divider with a 10kohm resistor to check the voltage and calculate the resistance.
Here's the code:
#include <X9C.h> // X9C pot library
#define UD 7 // pot up/down mode pin
#define INC 6 // pot increment pin
#define CS 5 // pot chip select pin
#define POT_READING 7 // Analog pin for potentiometer
// Seems odd to have 2 pins set to "7", but
// POT_READING will be reading from A7 and
// UD will be writing to D7
// Rotary Encoder Inputs
#define ENCODER_DT 2 // Encoder output A (... or is it B?... idk)
#define ENCODER_CLK 3 // Encoder output B?
#define ENCODER_SW 4 // Encoder switch/button, will set the digipot to encoders val
#define ENCODER_MIN 0 // Minimum encoder value
#define ENCODER_MAX 99 // Max value from encoder (the X9C library allows max 99 )
int encoderPos = 0; // Position of encoder, restricted to the ENCODER_[MAX/MIN] vals
int currentStateCLK; // Input from encoders CLK pin
int lastStateCLK; // Value of the CLK in the last loop (checking for updates)
bool clkClockwise; // True if rotary is turning clockwise (this isn't really used).
int loopCounter = 0; // Keep track of loop iteration count
int printOhmsEvery = 100;// How often to print the output (avoiding delay())
int ohmReading; // Output of the X9C103P
int lastOhmReading; // Value of the X9C103P in the last iteration
int buttonState; // the current reading from the input pin
int lastButtonState = LOW;// the previous reading from the input pin
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
// Vals for the volts to ohms conversion via Ohms law
int raw = 0;
float Vin = 5;
float Vout = 0;
// Known resistor value
float R1 = 10060;
float R2 = 0;
float buffer = 0;
float R2_previous = 0;
X9C pot;
void setup() {
// Set encoder pins as inputs
pinMode(ENCODER_CLK,INPUT);
pinMode(ENCODER_DT,INPUT);
pinMode(ENCODER_SW, INPUT);
// Setup Serial Monitor
Serial.begin(9600);
// Read the initial state of CLK
lastStateCLK = digitalRead(ENCODER_CLK);
//lastStateSW = digitalRead(SW);
// Call updateEncoder() when any high/low changed seen
// on interrupt 0 (pin 2), or interrupt 1 (pin 3)
attachInterrupt(ENCODER_CLK, updateEncoder, CHANGE);
attachInterrupt(ENCODER_DT, updateEncoder, CHANGE);
pot.begin(CS, INC, UD);
}
void setPot( int targetPos ){
pot.setPot(targetPos);
}
void loop() {
loopCounter++;
int reading = digitalRead(ENCODER_SW);
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;
// only toggle the LED if the new button state is HIGH
if (buttonState == LOW) {
//Serial.println("Button has been pressed..");
setPot(encoderPos);
}
}
}
// set the LED:
// save the reading. Next time through the loop, it'll be the lastButtonState:
lastButtonState = reading;
ohmReading = analogRead(POT_READING);
lastOhmReading = ohmReading;
if ( loopCounter > printOhmsEvery && loopCounter % printOhmsEvery == 0 ){
buffer = ohmReading * Vin;
Vout = (buffer)/1023.0;
buffer = (Vin/Vout) - 1;
R2= R1 * buffer;
Serial.print("Vout:");
Serial.print(Vout);
Serial.print(",R2:");
Serial.print(R2);
Serial.print(",encoderPos:");
Serial.println(encoderPos);
R2_previous = R2;
}
}
void updateEncoder(){
// Read the current state of CLK
currentStateCLK = digitalRead(ENCODER_CLK);
// If last and current state of CLK are different, then pulse occurred
// React to only 1 state change to avoid double count
if (currentStateCLK != lastStateCLK && currentStateCLK == 1){
// If the DT state is different than the CLK state then
// the encoder is rotating CCW so decrement
if (digitalRead(ENCODER_DT) != currentStateCLK) {
if ( encoderPos > ENCODER_MIN ) encoderPos --;
clkClockwise = false;// ="CCW";
}
else {
// Encoder is rotating CW so increment
if ( encoderPos < ENCODER_MAX ) encoderPos ++;
clkClockwise = true;
}
}
// Remember last CLK state
lastStateCLK = currentStateCLK;
}
Now the problem I'm having is the value of R2 is way out of range from what I would expect. This is an X9C103, which means it should only be able to provide a resistance up to 10k ohms, but R2 prints out up to 344815.18, which is much higher than I expected.
Vout:0.00,R2:inf,encoderPos:0
Vout:4.69,R2:660.19,encoderPos:4
Vout:4.60,R2:865.03,encoderPos:4
Vout:3.26,R2:5346.26,encoderPos:23
Vout:3.26,R2:5369.36,encoderPos:31
Vout:2.15,R2:13382.78,encoderPos:47
Vout:0.15,R2:332986.03,encoderPos:96
Vout:0.14,R2:344815.18,encoderPos:96
I have a separate circuit where I use the same voltage divider and code to determine the resistance of an "unknown" resistor and it was shockingly accurate. However, when I switch out the unknown resistor with the output from a digital potentiometer, the reading is much higher.
Additionally, the output voltage from the X9C103 (as you can see in the quoted output above), I can actually get it all the way down to almost 0 volts, which is more of a drop in voltage than I expected (and I verified that with my multimeter.
Question time - Why is it that the calculation for R2 reads so much higher through a digipot than if I switch in a regular resistor? I know that these things are only accurate to like 20% or so, but a resistance of over 300% the expected max makes me thing it's just a basic circuit problem or I may need to calculate the resistance here a bit differently.
And just in case anyone needs it, here are some pictures of the actual circuit:
Thank you in advance!
-J








