Как поместить класс LiquidCrystal_I2C в класс LCD?

Я хочу сделать свой основной код чище, поэтому я подумал о создании класса Lcd, который я мог бы использовать каждый раз, когда мне нужно печатать на lcd. Итак, мой основной код каждый раз, когда я пытаюсь напечатать текст, который мне нужно вызвать:

lcd.clear();
lcd.setCursor(1,0);
lcd.print("Text 1st line");
lcd.setCursor(1,0);
lcd.print("Text 2nd line");

Проблема в том, что мне нужно создать класс с именем Lcd, который инициализирует ЖК-дисплей с помощью LiquidCrystal_I2C.h и вызывает его функции, чтобы печатать так, как я хочу. Ниже я опубликую некоторый код, который совершенно неверен, но я думаю, он может дать вам представление о том, что я пытаюсь сделать:

LcdControl.hpp

class LcdControl{
    public:
        LcdControl();
        void printOnLcd(int data,int column,int line);
        void printOnLcd(char data,int column,int line);
};

LcdControl.cpp

#include <LiquidCrystal_I2C.h>
#include <Arduino.h>
#include "LcdControl.hpp"

LcdControl::LcdControl(){
    LiquidCrystal_I2C lcd(0x27,20,4);
    lcd.init();
    lcd.init();
    lcd.backlight();
}

void LcdControl::printOnLcd(int data,int column,int line){
    lcd.clear();
    lcd.setCursor(column,line);
    lcd.print(data);
}

void LcdControl::printOnLcd(char data,int column,int line){
    lcd.clear();
    lcd.setCursor(column,line);
    lcd.print(data);
} 

, 👍0


2 ответа


Лучший ответ:

1

Вы также можете использовать модель наследования, в которой базовым классом является исходная библиотека LiquidCrystal_I2C, а вы просто создаете новый производный класс, в данном случае LcdControl. В LcdControl вы просто упаковываете свои дополнительные методы. Единственная небольшая сложность заключается в том, что вы должны вызывать конструктор базового класса LiquidCrystal_I2C при вызове конструктора производного класса LcdControl.

Вот в симуляции: https://wokwi.com/projects/349238619253244498

Код:

#include <LiquidCrystal_I2C.h>

class LcdControl : public LiquidCrystal_I2C {
  public:

    LcdControl( uint8_t lcd_Addr, uint8_t lcd_cols, uint8_t lcd_rows) :
      // конструктор базового класса
      LiquidCrystal_I2C ( lcd_Addr, lcd_cols, lcd_rows ) {
    }

  
    void printOnLcd(const char * data, int column, int line) {
      LcdControl::clear();
      LcdControl::setCursor(column, line);
      LcdControl::print(data);
    }

} ;

LcdControl lcd(0x27, 20, 4);



void setup() {

  Wire.begin() ;
  lcd.init() ;
  lcd.backlight();

  
  lcd.printOnLcd( "hello world2", 0 , 0 ) ;
  delay(1000) ;

  lcd.printOnLcd( "hello world3", 1 , 2 ) ;
  
}

void loop() {

}

,

1

Потенциально локальный элемент lcd конструктора становится членом вместо этого:

class LcdControl{
    public:
        LcdControl();
    // ...
    private:
        LiquidCrystal_I2C lcd;    

Там он доступен из всех ваших функций-членов и (без лишних слов) существует в течение времени существования переменной LcdControl. В настоящее время у вас есть экземпляр lcd: локальный для конструктора, поэтому недоступный в другом месте (например, внутри printOnLcd()) и умирает, когда конструктор возвращается.

Создание члена lcd происходит в LcdControl() список инициализаторов членов:

LcdControl::LcdControl()
    : lcd(0x27,20,4)
{

Новые стандарты C++ позволяют выполнять некоторые формы инициализации там, где он объявлен как член. Я не собираюсь сейчас перепроверять стандарты. Но описанный выше способ должен работать независимо от того, какое у вас ядро и версия Arduino.

Возможно, вызов функции init() ЖК-дисплея должен быть выполнен в аналоге init()/begin() в вашей собственной учебный класс. Когда вы делаете что-то, что может дать сбой в конструкторе, у вас мало возможностей обнаружить/обработать это, когда это делается в конструкторе на встроенном устройстве, таком как Arduino, где ваш класс может быть глобальным и где исключения не поддерживаются; некоторые исключения поддерживаются Arduino, а некоторые нет. Для Arduino ошибочная часть инициализации/конструкции часто отделяется, чтобы вы могли контролировать, как и где/когда произойдет этот сбой, часто в setup() и не полагаясь на исключения.

Есть много способов добиться чего-то подобного. Вышеприведенное кажется наиболее близким к тому, что вы пытаетесь решить в вопросе. Это может не обязательно иметь наибольший смысл в вашем конкретном использовании. Вы можете захотеть, чтобы класс имел указатель члена или ссылку на член вместо экземпляра члена, но вам нужно быть более осторожным с их соответствующими сроками жизни. Часто бывает ошибкой выполнять инициализацию во внутренних слоях вашего кода, не предоставляя пользователю никакого контроля над ним. Например, запретить пользователю вашего класса LcdControl инициализировать свой собственный экземпляр LiquidCrystal_I2C и передать его или разрешить передачу параметров для LcdControl класс для использования.

,