tttapa / Control-Surface

Arduino library for creating MIDI controllers and other MIDI devices.
GNU General Public License v3.0
1.24k stars 139 forks source link

Declaring 1602 LCD in custom selector callback #313

Open huggre opened 3 years ago

huggre commented 3 years ago

Hi, I was hoping someone could show me how to declare a 1602 Liquid Crystal LCD within a custom selector callback. The callback is working correctly when printing the selected bank ID to the serial monitor, however I need to print the selected bank ID to the LCD. Whenever I try to print to the LCD I get a "'lcd' was not declared in this scope" error. Here is my code:

#include <Encoder.h>
#include <Control_Surface.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

// Custom callback to handle output for a selector.
class MySelectorCallback {
  public:
    // Constructor
    MySelectorCallback(int bankID)
      : bankID(bankID) {}

    // Begin function is called once by Control Surface.
    // Use it to initialize everything.
    void begin() {
    }

    // Update function is called continuously by Control Surface.
    // Use it to implement things like fading, blinking ...
    void update() {}

    // Update function with arguments is called when the setting
    // changes.
    // Use it to update the LEDs.
    void update(setting_t oldSetting, setting_t newSetting) {
      (void) oldSetting; // unused in this example
      show(newSetting);
    }

  private:
    // Show the color of the given setting.
    void show(setting_t setting) {  
      lcd.setCursor(1,0);
      //lcd.print(String(setting));

      //Serial.println(setting);

    }

  private:
    // Member variables to remember the pin numbers of the LEDs.
    int bankID;
};

// Create two MIDI interfaces
USBMIDI_Interface usbmidi;
//HardwareSerialMIDI_Interface serialmidi = {Serial1, MIDI_BAUD};

// Create a MIDI pipe factory to connect the MIDI interfaces to Control Surface
BidirectionalMIDI_PipeFactory<1> pipes;

LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 16 chars and 2 line display

Bank<3> bank = {16}; // 2 banks, 16 addresses per banks

// A rotary encoder to select one of the 120 bank settings
GenericEncoderSelector<3, MySelectorCallback> selector = {
  bank,        // bank to manage
  bank.getSelection(),
  {11, 12},      // encoder pins, first pin = CLK, second pin = DT
  4,           // encoder pulses per step
  Wrap::Clamp, // clamp or wrap around when going beyond maximum/minimum setting
};

Bankable::ManyAddresses::NoteButtonMatrix<3, 4, 4> buttons {
  bank,
  {0, 1, 2, 3},    // row pins (outputs, driven low-Z low !)
  {10, 9, 7, 4},    // column pins (inputs, hi-Z)

  // Now the list of address matrices, one for each bank
  {{
    // First bank
    {{{60,61,62,63},
      {64,65,66,67},
      {68,69,70,71},
      {72,73,74,75}}},

    // Second bank
    {{{60,63,65,67},
      {70,72,75,77},
      {79,82,84,87},
      {89,91,94,96}}},

    // Second bank
    {{{60,63,65,67},
      {70,72,75,77},
      {79,82,84,87},
      {89,91,94,96}}},
  }},

  // Finally, the list of MIDI channels, one for each bank
  {
    CHANNEL_1, // first bank
    CHANNEL_1, // second bank
    CHANNEL_1, // third bank
  },
};

// Instantiate an array of CCPotentiometer objects
CCPotentiometer potentiometers[] = {
  {A0,        // Analog pin connected to potentiometer 1
   0x10},     // Controller number of the first potentiometer
  {A1,        // Analog pin connected to potentiometer 2
   0x11},     // Controller number of the second potentiometer
  {A2, 0x12}, // Etc.
  {A3, 0x13},
  //{A4, 0x14},
};

/*
// Instantiate a PBPotentiometer object
// UpDown=A6, SideSide=A5
PBPotentiometer potentiometer = {
  A6,        // Analog pin connected to potentiometer
  CHANNEL_1, // MIDI Channel 1
};
*/

void setup() {

  // Setup LCD
  lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("hello everyone");
  lcd.setCursor(1,1);
  lcd.print("konichiwaa");

  Control_Surface | pipes | usbmidi;
  //Control_Surface | pipes | serialmidi;

  Control_Surface.begin();

}

void loop() {
  Control_Surface.loop();

}
tttapa commented 3 years ago

Please always try to post a minimal example, with as little unrelated code as possible, and post links to the external libraries you're using.

The compiler complains because there is no declaration of any variable lcd inside of the MySelectorCallback class. A global variable lcd is declared further down the line, but you cannot use it before its declaration. You could move that declaration before the MySelectorCallback, but writing to global variables like that is often a bad idea. Instead, you could pass a reference to the LCD display to your callback:

#include <Encoder.h>
#include <Control_Surface.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

// Custom callback to handle output for a selector.
class MySelectorCallback {
  public:
    // Constructor
    MySelectorCallback(LiquidCrystal_I2C &lcd, uint8_t col, uint8_t row)
     : lcd(lcd), col(col), row(row) {}

    // Begin function is called once by Control Surface.
    // Use it to initialize everything.
    void begin() {}

    // Update function is called continuously by Control Surface.
    // Use it to implement things like fading, blinking ...
    void update() {}

    // Update function with arguments is called when the setting
    // changes.
    // Use it to update the text on the LCD.
    void update(setting_t oldSetting, setting_t newSetting) {
      (void) oldSetting; // unused in this example
      lcd.setCursor(col, row);
      lcd.print(newSetting);
    }

  private:
    LiquidCrystal_I2C &lcd;
    uint8_t col, row;
};

USBMIDI_Interface usbmidi;
LiquidCrystal_I2C lcd(0x27, 20, 4);
Bank<3> bank = {16}; 
GenericEncoderSelector<3, MySelectorCallback> selector = {
  bank,        // bank to manage
  {lcd, 1, 0}, // selector callback 
  {11, 12},    // encoder pins
  4,           // encoder pulses per step
  Wrap::Clamp, // clamp or wrap around when going beyond maximum/minimum setting
};

void setup() {
  // Setup LCD
  lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("hello everyone");
  lcd.setCursor(1,1);
  lcd.print("konichiwaa");

  Control_Surface.begin();
}

void loop() {
  Control_Surface.loop();
}
huggre commented 3 years ago

Perfect!!, I will make sure to clean up my code next time.

By the way, have not had any latency issues over USB with the Teensy 2.0 so far.

tttapa commented 3 years ago

By the way, have not had any latency issues over USB with the Teensy 2.0 so far.

Thanks for letting me know, I'll add it to the readme for the next release!