TB2 003: POTS

Part 1

There are five potentiometers (pots) on the TB2, but we’ll just use the leftmost one for now.

The Arduino Due that powers the TB2 has 12 analog input pins. They are capable of returning a 12bit reading (4096 values), but for compatibility with other Arduino boards they are set to a resolution of 10bits (1024 values in a range from 0 – 1023).

We want to display a reading on the LCD display, so we’ll include code for the LCD, too. We start by including the LCD library.

#include <LiquidCrystal.h>

The leftmost pot is attached to analog pin 0, (also A0). We’ll call the pin A0 pot1.

int pot1 = 0; // the analog pin the leftmost pot is connected to

Next, we’ll initialize the LCD.

// *** LCD ***
// initialize the LCD library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

In the setup() function, we’ll reuse some code from the first tutorial to start communication with the LCD and to write Groovesizer on the first line.

void setup() {
  // *** LCD ***
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Groovesizer");
}

In the loop() function, we get a value from the analog pin A0 (now called pot1) with the analogRead() function. We store the value in a variable called reading.

void loop() {
  // put your main code here, to run repeatedly:
  int reading = analogRead(pot1);

The we set the LCD to write  to the leftmost position in the second row with setCursor().

  lcd.setCursor(0, 1);

Finally, we write the value we read from pot1 and stored in the reading variable and close the loop with }.

  lcd.print(reading);
}

Here’s the code in full up to this point.

#include <LiquidCrystal.h>

int pot1 = 0; // the analog pin the leftmost pot is connected to

// *** LCD ***
// initialize the LCD library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  // *** LCD ***
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Groovesizer");
}

void loop() {
  // put your main code here, to run repeatedly:
  int reading = analogRead(pot1);
  lcd.setCursor(0, 1);
  lcd.print(reading);
}

Try out the code by uploading it to the TB2, and moving the leftmost pot. The current pot1 value is written to the  LCD each time through the loop, but there’s a problem that we’ll address next.

Part 2

When we wrote the pot1 value to the LCD with the last section of code, we didn’t clear the LCD between writes, so we got some garbage characters left over from previous reads. It makes for some confusing and unexpected values.

Let’s try a quick (and unsatisfactory!) fix now. Before we write the latest value of reading, we’ll first clear the four LCD characters where reading will be written. We set the cursor position and print 4 spaces before setting the cursor to the same position and writing the current value of the reading variable.

  lcd.setCursor(0, 1);
  lcd.print("    ");
  lcd.setCursor(0, 1);
  lcd.print(reading);

Here’s the code in full.

#include <LiquidCrystal.h>

int pot1 = 0; // the analog pin the leftmost pot is connected to

// *** LCD ***
// initialize the LCD library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  // *** LCD ***
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Groovesizer");
}

void loop() {
  // put your main code here, to run repeatedly:
  int reading = analogRead(pot1);
  lcd.setCursor(0, 1);
  lcd.print("    ");
  lcd.setCursor(0, 1);
  lcd.print(reading);
}

It’s a step forward in that we can now see the real value of reading without the leftover characters. But it’s also a step backward, because now the value of reading appears to be only half as bright and to be flickering. We’ll address this problem next.

Part 3

The cause of the reduction in brightness and the flickering is that we are now writing a blank character before writing the actual character for the value of reading each time through the loop. What we really want to do is to only clear characters where none should be written, and to update characters that should be written without clearing them first.

That last explanation makes the problem sound harder than it is, but we will have to write our own function to offer an elegant solution to it.

Just like we created the compulsory setup() and loop() functions before, we are now going to write our own showValue() function. The idea is that we can then simply call the showValue() function and pass it the value we want to show, and it will take care of clearing unused characters by itself.

In empty form, our function will look like this.

void showValue(int val) {
}

Like setup() and loop(), the function is preceded by void, meaning that the function will only do something and not return a value. You’ll see that we now have int val in the parentheses, because we want to pass our function an integer value, and we’re going to call that value val in the function.

Inside the function, we’re going to use a if/else-if/else structure to check for the value of val, and to write spaces in front of the value of val depending on its size. Note that we don’t have to set the cursor position; we’ll do it once before we call the showValue() function, and the print(reading) function will automatically write to the next cursor position after we’ve printed the spaces .

Here’s the complete function.

void showValue(int val) {
  if (val < 10)
  {
    lcd.print("   "); // three spaces
    lcd.print(val);
  }
  else if (val < 100)
  {
    lcd.print("  "); // two spaces
    lcd.print(val);
  }
  else if (val < 1000)
  {
    lcd.print(" "); // one space
    lcd.print(val);
  }
  else
    lcd.print(val); // no spaces required
}

Now we can simply call the showValue() function from within the loop() function.

showValue(reading);

Here’s the code in full.

#include <LiquidCrystal.h>

int pot1 = 0; // the analog pin the leftmost pot is connected to

// *** LCD ***
// initialize the LCD library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  // *** LCD ***
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Groovesizer");
}

void loop() {
  // put your main code here, to run repeatedly:
  int reading = analogRead(pot1);
  lcd.setCursor(0, 1);
  showValue(reading);
}

void showValue(int val) {
  if (val < 10)
  {
    lcd.print("   ");
    lcd.print(val);
  }
  else if (val < 100)
  {
    lcd.print("  ");
    lcd.print(val);
  }
  else if (val < 1000)
  {
    lcd.print(" ");
    lcd.print(val);
  }
  else
    lcd.print(val);
}

Much better! You can probably still see some flickering on the final character now and again, however. This is because it’s possible that your pot ends up between two values. In the TB2 code, I minimize this flickering by only updating the display if a value has changed, and by locking the pots after a short interval.

Part 4

Finally, let’s read and do something with all 5 the pots. We’ll store our readings for the 5 pots in an array.

int pot[5];

We’ll also have an array to store the last pot value we used so that we only update a value if it has changed.

int lastPot[5];

We’ll create a function called getPots() to update all 5 pots in one go each time through the loop. We can use a for-loop to iterate over the pots, because they’re attached to consecutive analog pins from A0 -A 4.

void getPots() {
  for (int i = 0; i < 5; i++)
    pot[i] = analogRead[i];
}

We’ll print the values of pot 1 to pot 4 (in the code their values correspond to pot[0] to pot[3] because arrays are zero-indexed), but we’ll reduce the range from 1024 values to 256 values by bitshifting two places to the right. We’ll use pot 5 (pot[4]) to adjust the brightness off the LED, again within a range of 0 – 255.

Here’s all the code.

#include <LiquidCrystal.h>

int pot[5]; // an array to store the latest pot values
int lastPot[5]; // an array to store the last changed value for the pot
// *** LCD ***
// initialize the LCD library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  // *** LCD ***
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Groovesizer");
}

void loop() {
  getPots();
  // update the LCD values
  for (int i = 0; i < 4; i++) // pot 1 to pot 4
  {
    if (pot[i] != lastPot[i]) // only if the current reading is different from the last time we updated the LCD value
    {
      lcd.setCursor(i * 4, 1); // we multiply i by 4 because we reserve 4 LCD positions for each pot value
      showValue(pot[i]);
      lastPot[i] = pot[i];
    }
  }
  // adjust the LED brightness
  analogWrite(13, pot[4]); // the LED is on pin 13
}

void showValue(int val) {
  if (val < 10)
  {
    lcd.print("   ");
    lcd.print(val);
  }
  else if (val < 100)
  {
    lcd.print("  ");
    lcd.print(val);
  }
  else if (val < 1000)
  {
    lcd.print(" ");
    lcd.print(val);
  }
  else
    lcd.print(val);
}

void getPots() {
  for (int i = 0; i < 5; i++)
    pot[i] = analogRead(i) >> 2; // we use >> 2 to reduce the range from 0 - 1023 to 0 - 255
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *