Программирование классами на arduino

alexseyF
Offline
Зарегистрирован: 14.05.2017

Я программировал в основном на C# и немного на QT, поэтому привык пользоваться классовой архитектурой, но в ардуине столкнулся со следующей проблемой. Попытался написать класс с использованием интерфейса 12C для вывода текстовых данных на дисплей размерностью "20*4", при компиляции ошибок не выдает но и дисплей не инициализирует. Прошу не судить строго на низкоуровневых языках опыта практически нет. Вот код

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


//класс дисплея
//###############################################################

class Tdisplay{
  
  public:
  LiquidCrystal_I2C *lcd;  // создаем указатель на дисплей
  Tdisplay();//конструктор класса(а также инициализация дисплея)
  void set_text(char* maintext);//установка текста  (незаконченна)
  void test();  // проверка работы класса
};
//////////////////////////////////////////////////////////////
void Tdisplay::set_text(char* maintext){ //недоделанный метод 
}

void Tdisplay::test(){
  lcd->setCursor(0, 1);
  // Выводим на экран количество секунд с момента запуска ардуины
  lcd->print(millis()/1000);
}

Tdisplay::Tdisplay(){
    lcd =(0x3F,20,4);//инициализируем указатель
    lcd->init();                     
    lcd->backlight();// Включаем подсветку дисплея
    lcd->print("iarduino.ru");//вывод тестового текста
    lcd->setCursor(8, 1);
   lcd->print("LCD 1602");
  }

// Конец класса дисплея
//#############################################################  

Tdisplay display;//инициализирую свой класс дисплея

void setup() {
  // put your setup code here, to run once: 
}

void loop() {
  // put your main code here, to run repeatedly:
  display.test();// вывод тестовой надписи
}

 

T.Rook
Offline
Зарегистрирован: 05.03.2016

У меня Ваш код не компилится (1.6.7)

1. с адресом I2C не промазали?

2. если в инициализации помигать подсветкой, мигает?

Пока покопаюсь

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
	    lcd =(0x3F,20,4);//инициализируем указатель
  // Жесть 

Ну что делать. Мы тут не пишим на высокоуровневых языках типа ДОЛЛАР,АКЦИИ,ФЬЮЧЕРСЫ и прочее.

ПС:https://goo.gl/JsmLc5

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

alexseyF пишет:

...привык пользоваться классовой архитектурой, но в ардуине столкнулся со следующей проблемой.

...но и дисплей не инициализирует.

Вы всерьез считаете, что использование классов автоматичекси гарантирует Ваши программы от ошибок?

T.Rook
Offline
Зарегистрирован: 05.03.2016

qwone пишет:

ПС:https://goo.gl/JsmLc5

моих знаний не хва :(

   lcd = new LiquidCrystal_I2C (0x27,16,2);

не работает. Эх, придется ждать решения :(

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C *lcd;


void setup() {
  lcd = new LiquidCrystal_I2C(0x27, 20, 4);
  lcd->init();
  lcd->backlight();
  lcd->setCursor(0, 0);
  lcd->print("Hello, world!");
}


void loop()
{
}

Компилируется прекрасно.

T.Rook
Offline
Зарегистрирован: 05.03.2016

qwone пишет:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C *lcd;


void setup() {
  lcd = new LiquidCrystal_I2C(0x27, 20, 4);
  lcd->init();
  lcd->backlight();
  lcd->setCursor(0, 0);
  lcd->print("Hello, world!");
}


void loop()
{
}

Компилируется прекрасно.

ага. прям здорово. но не работает.

UPD: сорри. забыл что у меня на стенде backlight на PWM висит :)

Ваш код работает. Все тоже самое в классе ТС  - не хочет работать

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

А адрес lcd какой в сканере?

T.Rook
Offline
Зарегистрирован: 05.03.2016

ua6em пишет:

А адрес lcd какой в сканере?

Не буду оффтопичать. ждем ТС

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

alexseyF пишет:

привык пользоваться классовой архитектурой

Стесняюсь спросить, Вы марксист?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Так тоже компилируется

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
class Cl_display {
  private:
    LiquidCrystal_I2C *lcd;  // создаем указатель на дисплей
  public:
    Cl_display() {};
    void setup();
    void work();
};
void Cl_display::setup() {
  lcd = new LiquidCrystal_I2C(0x27, 20, 4);
  lcd->init();
  lcd->backlight();
}
void Cl_display::work() {
  lcd->setCursor(0, 0);
  lcd->print("Hello, world!");
}
Cl_display Display;
void setup() {
  Display.setup();
  Display.work();
}


void loop()
{
}

 

alexseyF
Offline
Зарегистрирован: 14.05.2017

Дисплей без класса подключаеться и работает прекрасно. Но как только переношу в класс то программа просто компилируеться но не работает.

Адрес LSD в сканере 0x3F (без класса все работает)

lcd = new LiquidCrystal_I2C(0x3F, 20, 4); - инициализация предложенная выше не помогла, все компилируеться но не работает.

Можно конечно передать в конструктор моего класса уже проинициалицированный в setup указатель на дисплей. Но все таки интересно возможно ли полностью вынести инициализацию дисплея в класс?

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Не . В конструктор инициализацию перенести нельзя. Вы же не запускаете программу на обесточенном компьюте, что бы включили а программа оп и работает без загрузки.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Да, alexseyF, при программировании для Ардуино не следует забывать о следующем:

Когда Вы пишете программу для ПК, то эта программа вправе ожидать, что к моменту ее старта (и, соответственно, к моменту инициализации используемых ею объектов) уже и ядро ОС и все драйвера загружены и готовы к работе.

В Ардуино скетч начинает работать сразу, и никакой разницы с точки зрения порядка инициализации между прикладными классами и классами библиотек (которые играют роль драйверов) нет. Поэтому инициализация статических переменных (объектов) происходит тогда, когда система еще не полн6остью готова к работе.

Поэтому, вопреки академическим рекомендациям и практике программирования на ПК, в Ардуино принято оставлять собственный конструктор класса пустым. Точнее, использовать его только в том случае, когда хорошо представляешь, зачем это нужно. А реальную инициализацию переменной класса осуществлять в методе init() или begin(), вызываемым из setup(). Но или так, как продемронстрировал qwone: статическим объявляется не сам класс, а указатель на него, а память под него выделяется (и проводится инициализация) опять-таки из setup(), т.е. только тогда, когда вся "системная" игициализация заведомо отработала.

alexseyF
Offline
Зарегистрирован: 14.05.2017

Спасибо друзья вот такой код сработал

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

//класс дисплея
//###############################################################

class Tdisplay{
  
  public:
  LiquidCrystal_I2C *lcd;  // Устанавливаем дисплей
  Tdisplay();//конструктор класса
  void set_text(char* maintext);//установка текста  
  void test();
  void setup();  
};
//////////////////////////////////////////////////////////////
void Tdisplay::set_text(char* maintext){  
}

void Tdisplay::test(){
  lcd->setCursor(0, 1);
  // Выводим на экран количество секунд с момента запуска ардуины
  lcd->print(millis()/1000);
}

void Tdisplay::setup(){
  lcd = new LiquidCrystal_I2C (0x3F,20,4);// (0x3F,20,4);
    lcd->init();                     
    lcd->backlight();// Включаем подсветку дисплея
    lcd->print("iarduino.ru");
    lcd->setCursor(8, 1);
   lcd->print("LCD 1602");
}

Tdisplay::Tdisplay(){
    
  }

// Конец класса дисплея
//#############################################################  

Tdisplay display;

void setup() {
  // put your setup code here, to run once: 
 display.setup();
}

void loop() {
  // put your main code here, to run repeatedly:
// Устанавливаем курсор на вторую строку и нулевой символ.
  display.test();
}

Можно ли перенести инициализацию дисплея в сам конструктор класса  не используя метод setup()

alexseyF
Offline
Зарегистрирован: 14.05.2017

Всем большое спасибо вопрос снят. 

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017
39 // Конец класса дисплея

не занимайся самообманом - конец класса дисплея у тебя здесь:

15 };

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Либо, если будешь работать с классом динамически

TDisplay *display; 

то можно инициализацию делать и в конструкторе, потому что создание экземпляра класса в сетап будет происходить в заданное время, после того как вся run-time инициализация уже отработала

P.S. я тоже сторонник классов, у мня даже каждая релюха или трехцветный LCD классом описан. Памяти жрёть больше, канеш, но камни меньше 328p я не пользую, а туда все влазит с запасом.  И код получает единообразие. 

 

Например 

class TRelay
{
private:
//	const char *fontext = "Relay On";
//	const char *fofftext = "Relay Off";

	bool finverted;
	bool fstate;
	byte fpin;
public:
	TRelay(byte pin);               // Номер пина на котором реле, по умолчанию уровень включения HIGH
	TRelay(byte pin, bool inverse); // Если реле включается низким уровнем inverse = true

	void On(void);     // включить реле 
	void Off(void);    // выключить реле.  Уровень включения определяется finverted

	const char *ToString(void);   // отдает строку "ON" или "OFF" 
	bool State();		      // отдает правильное состояние реле, независимо от уровня включения HIGH или LOW

};