Arduino controlled Digital Potentiometer

#1

Hi,
I’m very VERY new to arduino and programming in general.
I am hoping to be able to write code for a digital potentiometer MCP41010 (for prototype) and possibly AD5262 at a later time using SPI.

I was hoping the DIGIPOT could be controlled with buttons as opposed to just running it’s course, and once i can do that i am hoping to control that fucntion remotely via either Infra-red remote or just a bluetooth from a phone or something.

I have applied the below code just to test MCP41010 and it worked (unsurprisingly since i did not write it):

int CS_signal = 2; // Chip Select signal onsul pin 2 of Arduino
int CLK_signal = 4; // Clock signal on pin 4 of Arduino
int MOSI_signal = 5; // MOSI signal on pin 5 of Arduino
byte cmd_byte2 = B00010001 ; // Command byte
int initial_value = 100; // Setting up the initial value

void initialize() { // send the command byte of value 100 (initial value)
spi_out(CS_signal, cmd_byte2, initial_value);
}

void spi_out(int CS, byte cmd_byte, byte data_byte){ // we need this function to send command byte and data byte to the chip

digitalWrite (CS, LOW);                                                 // to start the transmission, the chip select must be low
spi_transfer(cmd_byte); // invio il COMMAND BYTE
delay(2);
spi_transfer(data_byte); // invio il DATA BYTE
delay(2);
digitalWrite(CS, HIGH);                                                 // to stop the transmission, the chip select must be high

}

void spi_transfer(byte working) {
for(int i = 1; i <= 8; i++) { // Set up a loop of 8 iterations (8 bits in a byte)
if (working > 127) {
digitalWrite (MOSI_signal,HIGH) ; // If the MSB is a 1 then set MOSI high
} else {
digitalWrite (MOSI_signal, LOW) ; } // If the MSB is a 0 then set MOSI low

digitalWrite (CLK_signal,HIGH) ;                                        // Pulse the CLK_signal high
working = working << 1 ;                                                // Bit-shift the working byte
digitalWrite(CLK_signal,LOW) ;                                          // Pulse the CLK_signal low
}

}

void setup() {
pinMode (CS_signal, OUTPUT);
pinMode (CLK_signal, OUTPUT);
pinMode (MOSI_signal, OUTPUT);

initialize();

Serial.begin(9600);                                                     // setting the serial speed
Serial.println("ready!");

}

void loop() {
for (int i = 0; i < 255; i++) {
spi_out(CS_signal, cmd_byte2, i);
Serial.println(i); delay(10);
}
for (int i = 255; i > 0; --i) {
spi_out(CS_signal, cmd_byte2, i);
Serial.println(i);
delay(10);
}
}

I have tried to just logically deduce how to write code from this and am afraid i have failed. I hypothesise that the for loop is all i would have to adapt but am struggling to find things immediately relevant.

Could someone possibly point me in the right direction for what i’ll need to make the adaptations? thanks

0 Likes

#2

It’s difficult to read the code unless you format it as preformatted text so I’ve done that here:

int CS_signal = 2; // Chip Select signal onsul pin 2 of Arduino
int CLK_signal = 4; // Clock signal on pin 4 of Arduino
int MOSI_signal = 5; // MOSI signal on pin 5 of Arduino
byte cmd_byte2 = B00010001 ; // Command byte
int initial_value = 100; // Setting up the initial value

void initialize() { // send the command byte of value 100 (initial value)
    spi_out(CS_signal, cmd_byte2, initial_value);
}

void spi_out(int CS, byte cmd_byte, byte data_byte){ // we need this function to send command byte and data byte to the chip
    digitalWrite (CS, LOW);                                                 // to start the transmission, the chip select must be low
    spi_transfer(cmd_byte); // invio il COMMAND BYTE
    delay(2);
    spi_transfer(data_byte); // invio il DATA BYTE
    delay(2);
    digitalWrite(CS, HIGH);                                                 // to stop the transmission, the chip select must be high
}

void spi_transfer(byte working) {
    for(int i = 1; i &lt;= 8; i++) { // Set up a loop of 8 iterations (8 bits in a byte)
        if (working &gt; 127) {
            digitalWrite (MOSI_signal,HIGH) ; // If the MSB is a 1 then set MOSI high
        } else {
            digitalWrite (MOSI_signal, LOW) ; } // If the MSB is a 0 then set MOSI low
            digitalWrite (CLK_signal,HIGH) ;                                        // Pulse the CLK_signal high
            working = working << 1 ;                                                // Bit-shift the working byte
            digitalWrite(CLK_signal,LOW) ;                                          // Pulse the CLK_signal low
        }
    }
}

void setup() {
    pinMode (CS_signal, OUTPUT);
    pinMode (CLK_signal, OUTPUT);
    pinMode (MOSI_signal, OUTPUT);

    initialize();

    Serial.begin(9600);                                                     // setting the serial speed
    Serial.println("ready!");
}

void loop() {
    for (int i = 0; i &lt; 255; i++) {
        spi_out(CS_signal, cmd_byte2, i);
        Serial.println(i);
        delay(10);
    }
    for (int i = 255; i &gt; 0; --i) {
        spi_out(CS_signal, cmd_byte2, i);
        Serial.println(i);
        delay(10);
    }
}

It’s hard to tell what you mean by it failing. What did or didn’t work? Did you see the value changing in the Serial Monitor?

1 Like

#3

thank you so much for your response. as i said, this code works. It is me who has failed to adapt it to the purpose i desire which is for the digipot to be controlled via button presses rather than just time. I saw no changes. The problem is that i am struggling to even find where to start trying to modify this code and how to modify it so that the digipot will respond to +/- commands.
would looking at any “button press” sketch help me to deduce what to put where?

thanks

1 Like

#4

It certainly would. I’m at work right now but I’ll be able to post a detailed reply later (in about 4h time). In the mean time you could look at the code for a circuito project that just had a button to see how it configured that pin as an input pin and reads/responds to the state of the pin.

1 Like

#5

thank you, i really appreciate you taking the time to help me like this. What i have started doing last night is following :

and taking notes to actually try and understand how to get something from your head onto an arduino project. Once i’ve done that i think i will be better equipped to disect a “push button” code and see if i can make anything of it.

1 Like

#6

I started by making a simple circuit with an Arduino Nano and a mini push button switch: https://www.circuito.io/app?components=97,514,11022

Reviewing the generated code shows the following critical features:

Include the header file that has the definitions for the Button class that’ll be used later, and then define which pin the button is connected to.

#include "Button.h"

#define PUSHBUTTON_PIN_2	2 

Then define a push button variable

Button pushButton(PUSHBUTTON_PIN_2);

In the Setup method, initialise the button

void setup() 
{
    pushButton.init();
}

There are some helpful comments in the generated code that explain the values you can expect pushButtonVal to have after calling the read method.

// Mini Pushbutton Switch - Test Code
//Read pushbutton state. 
//if button is pressed function will return HIGH (1). if not function will return LOW (0). 
//for debounce funtionality try also pushButton.onPress(), .onRelease() and .onChange().
//if debounce is not working properly try changing 'debounceDelay' variable in Button.h
bool pushButtonVal = pushButton.read();

My next post will explain how to tie this with the original code. I think keeping the posts separate will make it easier to understand the differences.

1 Like

#7

right ok, so i’m thinking all i have to do now is to add the 2 pushbuttons to my circuit, i’ve just connected them from the 5v supply to digital pins 7 & 8.

so i would declare them at the start? like in the digital button part of the example sketch:

const int R+ = 7 // arduino pin7 connected to button for increasing resistance
const int R- = 8 // arduino pin8 connected to button that will decrease resistance

Then just replace the 2for loops at the bottom with if statements?
Im confused how to integrate them, like once i poush a button, which DigiPot pin would the HIGH output from the button go to? is it just the wiper? in the example code i copied, the for loop basically just says “this integer ‘i’ will increase from 0 - 255 and then come hback down again” so, do i still just refer to the wiper as “i” with a value between 0 - 255?

Let’s say i wanted a push of R+ to result in a 10 step increase in resistance,
do i just write something like:

//read state of buttons R+ & R- :

R+state = digitalRead(R+) ;

R-state = digitalRead(R-) ;

// if pushed, do the thing (R+ = i+10 & R- = i-10)

if (R+state == High) {

digitalWrite(wiperPin, +10) // ? or would i now just iinitiate the same for loop but rather than make it go all the way from 0-255 just make go up by 10 ???

sorry i still dont know how to do the formating thing for the code like you did earlier

i see you have just replied…took me an hour to write this :laughing:

0 Likes

#8

I was replying and then saw you replied as well! :smiley:

It seems like you’ve got it, but you can’t use + and - in variable names, so I’d suggest calling them btnInc and btnDec for “button increment” and “button decrement”. You’ll also want a global variable for the resistance level - let’s call that resistance:

Button btnInc(7);
Button btnDec(8);
int resistance = 128; // Initial value in the middle of the 0-255 range

You’re right that you replace the code in the loop method, and in there you’d read the values from the two buttons and then update the value if either is pressed. Bounds check the resulting value to avoid exceeding the limits (0…255) before setting that value:

void loop() {
    bool inc = pbInc.read();
    bool dec = pbDec.read();

    if (inc) {
        resistance += 10;
    }
    if (dec) {
        resistance -= 10;
    }

    if (resistance > 255) {
        resistance = 255;
    }
    if (resistance < 0) {
        resistance = 0;
    }

    spi_out(CS_signal, cmd_byte2, resistance);
}
1 Like

#9

I think what is confusing me is that the wiper pin isnt even mentioned in the setup or anything of the original code and that it just works being randomly called “i” in the loop. also, there is a random “working” variable? byte? that, if it has a value greater than 127 then stuff happens and I’m just like “AHHHHHH how am i meant to know what it’s set at??? its not been declared before, whats the script???” and then theres another where for some reason a byte is shifted to the left and i cant find a comment saying why

0 Likes

#10

dude you are such a legend i cannot thank you enough for all your help. reading your stuff now and it seems so simple xD

1 Like

#11

One of the problems with this approach is that the loop method runs over and over as quickly as it can. You won’t be able to press a button and release it quickly enough to only register once. The loop will run LOTS of times in the fraction of a second you have either button pressed.

A simple way to work around this is to delay for a while whenever you detect that a button has been pressed. After you update the resistance value with the spi_out method, you could add these lines of code:

if (inc || dec) {
    delay(500);
}

That’ll give you to half a second to release the button before it registers again. Holding it down will increase or decrease the resistance by 10 every half a second. Something like holding down a key on the keyboard… :slight_smile:

1 Like

#12

awesome, thanks again, this is very informative!
let’s say thew wiper is at position 250, adding 10 would bring it to 260. In my mind i see this like an analogue clock, where the actual value would be 260-255=5, could i then make it jump from position 250 to position 5 with one increase push? i think that would be cool as i’m hoping to use this to control the input Power of a primary coil of a slayer exciter circuit (once i figure out how to make a 5v one) and it would be cool to see it jump from low power to high power and from high to low like that lol

0 Likes

#13

That’s a simple change. The code I wrote will “cap” the resistance at the top/bottom of the range of values.

if (resistance > 255) {
    resistance = 255;
}
if (resistance < 0) {
    resistance = 0;
}

To have it “wrap around”, you’d use this instead:

if (resistance > 255) {
    resistance = resistance - 255;
}
if (resistance < 0) {
    resistance = resistance + 255;
}

Simple! :smiley:

1 Like

#14

thanks!

right so now, Im getting an error saying " ‘pbInc’ was not declared in this scope " and i’m assuming it will say the same thing for pbDec

0 Likes

#15

Could you post your entire source code?

Please use the “</>” button to format it as code.

1 Like

#16

sure, I will in a sec as i think i was brain-farting.
i didnt add in the #include “Button” etc… lol

0 Likes

#17

<#include <SPI.h>

#include <Button.h>

#define PUSHBUTTON_PIN_7
#define PUSHBUTTON_PIN_8

Button Rup(PUSHBUTTON_PIN_8)
Button Rdn(PUSHBUTTON_PIN_7)

void setup() {
Rup.init();
}

void setup() {
Rdn.init();
}

int CS_signal = 2; // Chip Select signal onsul pin 2 of Arduino
int CLK_signal = 4; // Clock signal on pin 4 of Arduino
int MOSI_signal = 5; // MOSI signal on pin 5 of Arduino
byte cmd_byte2 = B00010001 ; // Command byte
int Ri = 100; // Setting up the initial value

Button Rup = 8; // pin 8 (red button) will increase resistance
Button Rdn = 7; // pin 7 (blue button) will decrease resistance

void initialize() { // send the command byte of value 100 (initial value)
spi_out(CS_signal, cmd_byte2, Ri);
}

void spi_out(int CS, byte cmd_byte, byte data_byte){ // we need this function to send command byte and data byte to the chip

digitalWrite (CS, LOW);                                                 // to start the transmission, the chip select must be low
spi_transfer(cmd_byte); // invio il COMMAND BYTE
delay(2);
spi_transfer(data_byte); // invio il DATA BYTE
delay(2);
digitalWrite(CS, HIGH);                                                 // to stop the transmission, the chip select must be high

}

void spi_transfer(byte working) {
for(int i = 1; i <= 8; i++) { // Set up a loop of 8 iterations (8 bits in a byte)
if (working > 127) {
digitalWrite (MOSI_signal,HIGH) ; // If the MSB is a 1 then set MOSI high
} else {
digitalWrite (MOSI_signal, LOW) ; } // If the MSB is a 0 then set MOSI low

digitalWrite (CLK_signal,HIGH) ;                                        // Pulse the CLK_signal high
working = working << 1 ;                                                // Bit-shift the working byte
digitalWrite(CLK_signal,LOW) ;                                          // Pulse the CLK_signal low
}

}

void setup() {
pinMode (CS_signal, OUTPUT);
pinMode (CLK_signal, OUTPUT);
pinMode (MOSI_signal, OUTPUT);

initialize();

Serial.begin(9600);                                                     // setting the serial speed
Serial.println("ready!");

}

void loop() {

bool Rup = pushButton.read();
bool Rdn = pushButton.read();

if (Rup) {
  Ri += 10;
}

if (Rdn) {
  Ri -= 10;
}

if (Ri > 255) {
  Ri = Ri - 255;
}

if (Ri < 255) {
  Ri = Ri + 255;
}
}
0 Likes

#18

ok i have probably tried to change too many things now

i tried #define “button” but it said that doesn’t exist

what i’m noticing from the “button” example code, is that i havent told it to read for the button? i’m not sure sorry i got kinda lost lol

0 Likes

#19

No worries, I’ve got the code and I’m going to list the issues and then the complete corrected code (I hope)…

1 Like

#20

OK, formatted correctly, that’s the following:

<#include <SPI.h>

#include <Button.h>

#define PUSHBUTTON_PIN_7
#define PUSHBUTTON_PIN_8

Button Rup(PUSHBUTTON_PIN_8)
Button Rdn(PUSHBUTTON_PIN_7)

void setup() {
Rup.init();
}

void setup() {
Rdn.init();
}

int CS_signal = 2; // Chip Select signal onsul pin 2 of Arduino
int CLK_signal = 4; // Clock signal on pin 4 of Arduino
int MOSI_signal = 5; // MOSI signal on pin 5 of Arduino
byte cmd_byte2 = B00010001 ; // Command byte
int Ri = 100; // Setting up the initial value

Button Rup = 8; // pin 8 (red button) will increase resistance
Button Rdn = 7; // pin 7 (blue button) will decrease resistance

void initialize() { // send the command byte of value 100 (initial value)
spi_out(CS_signal, cmd_byte2, Ri);
}

void spi_out(int CS, byte cmd_byte, byte data_byte){ // we need this function to send command byte and data byte to the chip

digitalWrite (CS, LOW);                                                 // to start the transmission, the chip select must be low
spi_transfer(cmd_byte); // invio il COMMAND BYTE
delay(2);
spi_transfer(data_byte); // invio il DATA BYTE
delay(2);
digitalWrite(CS, HIGH);                                                 // to stop the transmission, the chip select must be high
}

void spi_transfer(byte working) {
for(int i = 1; i <= 8; i++) { // Set up a loop of 8 iterations (8 bits in a byte)
if (working > 127) {
digitalWrite (MOSI_signal,HIGH) ; // If the MSB is a 1 then set MOSI high
} else {
digitalWrite (MOSI_signal, LOW) ; } // If the MSB is a 0 then set MOSI low

digitalWrite (CLK_signal,HIGH) ;                                        // Pulse the CLK_signal high
working = working << 1 ;                                                // Bit-shift the working byte
digitalWrite(CLK_signal,LOW) ;                                          // Pulse the CLK_signal low
}
}

void setup() {
pinMode (CS_signal, OUTPUT);
pinMode (CLK_signal, OUTPUT);
pinMode (MOSI_signal, OUTPUT);

initialize();

Serial.begin(9600);                                                     // setting the serial speed
Serial.println("ready!");
}

void loop() {

bool Rup = pushButton.read();
bool Rdn = pushButton.read();

if (Rup) {
Ri += 10;
}

if (Rdn) {
Ri -= 10;
}

if (Ri > 255) {
Ri = Ri - 255;
}

if (Ri < 255) {
Ri = Ri + 255;
}
}

Now to the problems:

  1. Line 1 should not start with the less than symbol.
  2. #define can’t have no value so #define PUSHBUTTON_PIN_7 should be #define PUSHBUTTON_PIN_7 7
  3. You have three setup methods. You can only have one.
  4. You seem to have gotten confused by defining rup and rdn twice. I’ve rearranged all variable declarations at the top
  5. You names your buttons the same as the result of reading the button.
  6. You didn’t update the potentiometer in the loop.
  7. You didn’t add the delay after updating the pot (to avoid it spinning wildly whilst pressing the button)

The edited version follows (note that I’ve not tested the code or even tried to compile it - there’s more than likely still an issue in there somewhere!)

#include <SPI.h>
#include <Button.h>

#define PUSHBUTTON_PIN_7 7
#define PUSHBUTTON_PIN_8 8

int CS_signal = 2; // Chip Select signal onsul pin 2 of Arduino
int CLK_signal = 4; // Clock signal on pin 4 of Arduino
int MOSI_signal = 5; // MOSI signal on pin 5 of Arduino
byte cmd_byte2 = B00010001 ; // Command byte
int Ri = 100; // Setting up the initial value

Button btnRup(PUSHBUTTON_PIN_8); // pin 8 (red button) will increase resistance
Button btnRdn(PUSHBUTTON_PIN_7); // pin 7 (blue button) will decrease resistance

void setup() {
    pinMode (CS_signal, OUTPUT);
    pinMode (CLK_signal, OUTPUT);
    pinMode (MOSI_signal, OUTPUT);

    btnRup.init();
    btnRdn.init();
    initialize();

    Serial.begin(9600);                                                     // setting the serial speed
    Serial.println("ready!");
}

void initialize() {
     // send the command byte of value 100 (initial value)
    spi_out(CS_signal, cmd_byte2, Ri);
}

void spi_out(int CS, byte cmd_byte, byte data_byte){ // we need this function to send command byte and data byte to the chip
    digitalWrite (CS, LOW);                                                 // to start the transmission, the chip select must be low
    spi_transfer(cmd_byte); // invio il COMMAND BYTE
    delay(2);
    spi_transfer(data_byte); // invio il DATA BYTE
    delay(2);
    digitalWrite(CS, HIGH);                                                 // to stop the transmission, the chip select must be high
}

void spi_transfer(byte working) {
    for(int i = 1; i <= 8; i++) { // Set up a loop of 8 iterations (8 bits in a byte)
        if (working > 127) {
            digitalWrite (MOSI_signal,HIGH) ; // If the MSB is a 1 then set MOSI high
        } else {
            digitalWrite (MOSI_signal, LOW) ;
        } // If the MSB is a 0 then set MOSI low

        digitalWrite (CLK_signal,HIGH) ;                                        // Pulse the CLK_signal high
        working = working << 1 ;                                                // Bit-shift the working byte
        digitalWrite(CLK_signal,LOW) ;                                          // Pulse the CLK_signal low
    }
}


void loop() {
    bool Rup = btnRup.read();
    bool Rdn = btnRdn.read();

    if (Rup) {
        Ri += 10;
    }

    if (Rdn) {
        Ri -= 10;
    }

    if (Ri > 255) {
        Ri = Ri - 255;
    }

    if (Ri < 255) {
        Ri = Ri + 255;
    }

    spi_out(CS_signal, cmd_byte2, Ri);

    if (inc || dec) {
        delay(500);
    }
}
1 Like