Как вызвать библиотеку из библиотеки?

Stratus
Offline
Зарегистрирован: 11.11.2015

Коллеги,

есть две библиотеки: lib1.h и lib2.h

вот думаю как можно вызвать методы lib1.h из lib2.h.

Пытался это сделать но прикомпиляции пишется ошибка, что он не видит lib1.

Как это можно сделать?

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

Если Вам не нужно вызывать из .cpp файла, а достаточно из .h, то это совсем просто. Сделайте так, чтобы в основном скетче include на тот .h файл в котором вызывается стоял ПОСЛЕ include того файла из которого вызывается. Если надо, могу выложить пример.

Кстати, если вызывать надо из .cpp файла, то тело этой функции (в которой есть такой вызов) всегда можно перенести в .h файл.

Stratus
Offline
Зарегистрирован: 11.11.2015

Да примерчик бы не помешал.....

Я попробовал это сделать теперь он говорить что идет редефинишн - переопределение.

ТО есть мы двараза файл указали ф библиотеке вызвали lib1 и в основном коде.

НО у меня основаная сложность в том как в коде смой библиотеки вызвать другую.

Какой синтаксис, надо ли использовать new ведь по сути в бибилотеке мы создвем новый экземпляр класса другой билиотеки?

А где тогда хранить сами файлы библиотек в папке libraries?

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

В каталоге с библиотеками смотрю файл SpacebrewYun.h, вижу строку #include <Bridge.h>

Здесь Bridge.h расположен в другой библиотеке. Никаких проблем нет.
 
На счет "примерчик", уж лучше Вы приведите примерчик.
 
Вы библиотеки корректно установили? По отдельности работают?
 
 
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

С new и всем остальным никаких проблем - если .h файл того, что мы создаём, видим из того места, где создаём, то все нормально.

Как я уже писал - всё гораздо проще, если весь текст библиотеки находится в .h файле (с файлом .cpp сложнее). Поэтому давайте сделаем так. Сейчас я Вам дам пример как всё сделать для случая, когда всё находится в .h файле. Посмотрите, запустите, убедитесь, что нормально компилируется и т.п.

Затем, если Вы сами не знаете, то я объясню как любую функцию из .cpp файла перенести в .h файл ничего при этом не сломав. И, наконец, если схранится потребность, то тогда уж поговорим как быть, если очень хочется всё держать таки в .cpp файле.

Итак,

1. имеется библиотека VoltageRange - это просто пара чисел и определённая для неё операция "==". Операция определена так, что если сравнить экземпляр VoltageRange с целым числом, то "истина" получится, если число попадает в интервал, заданный парой чисел VoltageRange и "ложь" - если не попадает.

2. Имеется библиотека ResistiveKeyboard, которая содержит несколько диапазонов (типа VoltageRange) и имеет единственный метод - keyPressed(int pin). Метод читает аналоговый пин и проверяет попало ли значение считанное с пина в один из интервалов VoltageRange. Если попало - возвращает номер интервала (считая с 1), а если не попало ни в один - возвращает 0.

3. имеется скетч, который создаёт клавиатуру с четырьмя кнопками и в loop проверяет не нажата ли какая-нибудь кнопка и, когда нажата, печатает номер кнопки.

Файлы расположены стандартно:
MySkethes\kaka\kaka.ino - файл скетча
MySkethes\libraries\VoltageRange\VoltageRange.h - файл библиотеки
MySkethes\libraries\ResistiveKeyboard\ResistiveKeyboard.h - файл библиотеки

Обратите внимание на порядок следования include в скетче
#include <VoltageRange.h>
#include <ResistiveKeyboard.h>

Это важно. Библиотека VoltageRange используется в ResistiveKeyboard, поэтому VoltageRange определена выше. Когда она потребуется для ResistiveKeyboard, она уже будет определена. Если написать include наоборот, то VoltageRange не будет доступна для ResistiveKeyboard

Смотрите. Попробуйте добавить в ResistiveKeyboard new VoltageRange  всё должно работать. Убедитесь, что всё поняли и ответьте на вопрос "хватит ли Вам этого".

Ну, теперь, собственно, тексты. 

kaka.ino

#include <VoltageRange.h>
#include <ResistiveKeyboard.h>

#define KEYBOARD_PIN	1

static VoltageRange ranges[] = {
	VoltageRange(0,256),
	VoltageRange(256, 512),
	VoltageRange(512,768),
	VoltageRange(768,1024)
};

static const int8_t TotalRanges = sizeof(ranges)/sizeof(ranges[0]);

static ResistiveKeyboard keyboard(ranges, TotalRanges);

void setup(void) {
}

void loop(void) {
	const int8_t key = keyboard.keyPressed(KEYBOARD_PIN);
	if (key > 0) {
		Serial.print("Key pressed: ");
		Serial.println(key);
	}
}

VoltageRange.h

#ifndef VOLTAGERANGE_H
#define VOLTAGERANGE_H

#include <arduino.h>

class VoltageRange {
public:
	VoltageRange (const int minV, const int maxV) {
		m_min = minV;
		m_max = maxV;
	}
	friend const bool operator == (const VoltageRange & r, const int voltage) {
		return (voltage >= r.m_min) && (voltage < r.m_max);
	}
	friend const bool operator == (const int voltage, const VoltageRange & r) {
		return r == voltage;
	}

private:
	int m_min, m_max;

};

#endif	//	VOLTAGERANGE_H

ResistiveKeyboard.h

#ifndef RESISTIVEKEYBOARD_H
#define RESISTIVEKEYBOARD_H

#include <arduino.h>

class ResistiveKeyboard {
public:
	ResistiveKeyboard (VoltageRange * ranges, const int8_t TotalRanges) {
		m_ranges = ranges;
		m_total = TotalRanges;
	}

	const int8_t keyPressed(const int8_t pin) const {
		const int volts = analogRead(pin);
		for (short i=0; i < m_total; i++) {
			if (m_ranges[i] == volts) return i+1;
		}
		return 0;
	}

private:
	VoltageRange * m_ranges;
	int8_t m_total;
};

#endif	//	RESISTIVEKEYBOARD_H

Чуть не забыл! Если будете запускать, добавьте там стандартную инициализацию сериала и т.п. - я это убрал, чтобы не загромождать код.

 

Stratus
Offline
Зарегистрирован: 11.11.2015

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

Вот например:

1. Создаем мы VoltageRange в RestrictiveKeyboard. А где new VoltageRange.

2. В каком синтаксисе писать: VoltageRange VR = new VoltageRange или VoltageRange:VR?Опять же если несколько экземпляров типа VoltageRange то всетаки как то надо создать экземпляр.

3.Взять за правило что если это делается в h файле тогда никаких include он типа и так все видит?

4.Вообще на каком языке мы это все пишем: ( С,С++,'Поскаль' на крайняк:) )?

По факту у меня он снова жалуется на редефинишен, мол я перереопределяю уже заранее определенный класс.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015
Так, давайте отделим мух от котлет и всё расставим по местам. Там нет никакой мистики. Не усложняйте, и всё станет понятно.
Stratus пишет:
1. Создаем мы VoltageRange в RestrictiveKeyboard. А где new VoltageRange.
Нам это не было нужно. Но если нужно создать новый экземпляр при помощи new – нет проблем, так и создаём. Я добавил в конструктор создание и затем удаление нового экземпляра (строки13 и 14 соответственно) – смотрите.
#ifndef RESISTIVEKEYBOARD_H
#define RESISTIVEKEYBOARD_H

#include <arduino.h>
#include "VoltageRange.h"


class ResistiveKeyboard {
public:
	ResistiveKeyboard (VoltageRange * ranges, const int8_t TotalRanges) {
		m_ranges = ranges;
		m_total = TotalRanges;
		VoltageRange * vr = new VoltageRange(0,1024);
		delete vr;
	}

	const int8_t keyPressed(const int8_t pin) const {
		const int volts = analogRead(pin);
		for (short i=0; i < m_total; i++) {
			if (m_ranges[i] == volts) return i+1;
		}
		return 0;
	}

private:
	VoltageRange * m_ranges;
	int8_t m_total;
};

#endif	//	RESISTIVEKEYBOARD_H
 
Stratus пишет:
2. В каком синтаксисе писать: VoltageRange VR = new VoltageRange или VoltageRange:VR?Опять же если несколько экземпляров типа VoltageRange то всетаки как то надо создать экземпляр.
В обычном синтаксисе. См. пример в предыдущем ответе.
Stratus пишет:
3.Взять за правило что если это делается в h файле тогда никаких include он типа и так все видит?
Никто и ничего «так» не видит. Есть общее правило – прежде, чем что-то использовать, это надо определить. Определить можно в том же файле, а можно в другом, но тогда тот другой файл необходимо включить в наш директивой #include. В ней нет ничего таинственного. Если в файле встречается директива #include <a.h> это означает, что в данное место будет просто вставлено содержимое файла «a.h» и всё. Просто можно было взять то содержимое ручками и вставить, а можно написать директиву #include – само вставится.
Stratus пишет:
4.Вообще на каком языке мы это все пишем: ( С,С++,'Поскаль' на крайняк:) )?
Хороший вопрос. Я думал, что на С++.
Stratus пишет:
По факту у меня он снова жалуется на редефинишен, мол я перереопределяю уже заранее определенный класс.
Не вижу кода, но скорее всего Вы перетащили определение класса в свой файл руками, но при этом и #include оставили на месте. В итоге получилось, что класс определяется дважды. 
Как я Вам уже говорил #include – это просто «вставить содержимое «того» файла в данный. Вот и посмотрите с этой точки зрения. Наверняка у Вас в файле определяется тот же класс, что и в «инклюдируемом файле».
 
Stratus
Offline
Зарегистрирован: 11.11.2015
Почему то эта конструкция не работает.

Вот пример: Lib2:

#if defined(ARDUINO) && ARDUINO >= 100
  #include <Arduino.h>
#else
  #include <WProgram.h>
#endif

class Lib2
{
 public:
  Lib1 * Lib1obj_1;
  Lib1 * Lib1obj_2;
  
  Lib2()
  {
   Lib1obj_1 = new Lib1();
   Lib1obj_2 = new Lib1();
  }
  
  int MethodLib2()
  {
   return Lib1obj_1.MethodLib1() + Lib1obj_2.MethodLib1();
  }

};

(Почему то код вставляется только один раз и только в начале.)

 

Stratus
Offline
Зарегистрирован: 11.11.2015
#if defined(ARDUINO) && ARDUINO >= 100
  #include <Arduino.h>
#else
  #include <WProgram.h>
#endif

class Lib1
{
 public:
  int * valueLib1;

  Lib1()
  {
   valueLib1 = 0;
  }

  int * MethodLib1()
  {
   return valueLib1++;
  }

};

 

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

Я не понял. Что значит не работает? Чтоговорит? Что значит вставляется один раз и в начале. Это что за кусок текста? Он живёт в библиотеке или в основном скетче? Ничего не понял.

Stratus
Offline
Зарегистрирован: 11.11.2015
#if defined(ARDUINO) && ARDUINO >= 100
  #include <Arduino.h>
#else
  #include <WProgram.h>
#endif

class Lib1
{
 public:
  int valueLib1;

  Lib1()
  {
   valueLib1 = 0;
  }

  int MethodLib1()
  {
   return valueLib1++;
  }
};

 

Stratus
Offline
Зарегистрирован: 11.11.2015
#include <Lib1.h>

Lib1 LB11;
Lib1 LB12;

void setup() {
  Serial.begin(9600);
}

void loop() {
   Serial.println(LB11.MethodLib1()+LB12.MethodLib1());
}

Вот в таком варианте: когда LIB1 вызывается из ino файла все работает.

Stratus
Offline
Зарегистрирован: 11.11.2015
#include <Lib1.h>
#include <Lib2.h>

Lib2 LB;

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

void loop() {
  // put your main code here, to run repeatedly:
   LB.MethodLib2();
//   Serial.println(LB.MethodLib2());
}

 

Stratus
Offline
Зарегистрирован: 11.11.2015
#if defined(ARDUINO) && ARDUINO >= 100
  #include <Arduino.h>
#else
  #include <WProgram.h>
#endif

class Lib1
{
 public:
  int * valueLib1;

  Lib1()
  {
   valueLib1 = 0;
  }

  int * MethodLib1()
  {
   return valueLib1++;
  }
};

 

Stratus
Offline
Зарегистрирован: 11.11.2015
#if defined(ARDUINO) && ARDUINO >= 100
  #include <Arduino.h>
#else
  #include <WProgram.h>
#endif

class Lib2
{
 public:
  Lib1 * Lib1obj_1;
  Lib1 * Lib1obj_2;
  
  Lib2()
  {
   Lib1obj_1 = new Lib1();
   Lib1obj_2 = new Lib1();
  }
  
  int * MethodLib2()
  {
   return (Lib1obj_1 -> MethodLib1());
  }
};

Вот в таком варианте когда первая библиотека вызывается не в ino файле а в другой беблиотеку все тоже работает.

Stratus
Offline
Зарегистрирован: 11.11.2015

НО!

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

Во втором варианте также не получается отобразить результат возвращаемого методом значения так как компилятор не может сделать конвертацию типов из int в int*, не получается так же сложить 2 результата возвращаемых 2-мя методами разных обьектов.

В итоге вопрос концептуальный:

Создается ли в первом варианте 2 разных обьекта?

Не могу понять всетаки синтаксис: в первом варианте не нужно указывать ссылочные типы а во втором нужно без этого не работает?

Что правильнее?

ЗЫ: когда добавляю на форум топики код получается добавить только один раз (2 разных кода не добввляются) и он всегда помещается в начале топика.

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

Stratus пишет:

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

Вы никак не поймёте чего я от Вас прошу.

Вот Вы говорите "не работает", но при этом не приводите ТОГО вариаанта, который собственно не работает и не приводите сообщений компилятора. Вместо неработающего варианта, Вы пишете "надо обязательно ..., а иначе ...". Но я же не вижу, как именно Вы добились, чтобы не работало. Как я могу догадаться в чём проблема?

Вот давайте спокойно и методично: дайте мне три файла (ino и две бибилиотеки), которые не компилируются и приведите сообщение компилятора.

Если не умеете постить три файла, соедините в один, только комментариями отделите.

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

Stratus пишет:

#if defined(ARDUINO) && ARDUINO >= 100
  #include <Arduino.h>
#else
  #include <WProgram.h>
#endif

class Lib1
{
 public:
  int * valueLib1;

  Lib1()
  {
   valueLib1 = 0;
  }

  int * MethodLib1()
  {
   return valueLib1++;
  }
};

Это что? Вы описали УКАЗАТЕЛЬ на int. Присвоили УКАЗАТЕЛЮ 0, а затем проводите арифметику с этим УКАЗАТЕЛЕМ! Вы именно этого хотели?