Помогите с указателями на функцию

dachnik
Offline
Зарегистрирован: 26.07.2013

Есть функция чтения значения аналогового пина

 int solid_read(int pin)
{
  int val = analogRead(pin);// считываем значение
  val = map(val, 0 , 1023, 100, 0);
  return  val;             // выводим полученное значение
}

Есть функция меню

void up_down_eeprom_var( int var )
{
int x =0;
lcd.clear(); //очищаем экран
delay(del);
while(1)
{ 
x++;
if (x>interval){break;}
 lcd.print(" now=");
 lcd.print(var);
}}

   Как правильно передеть функции void up_down_eeprom_var(int var ) указатель на функцию int solid_read(int pin)   (параметр int var)? чтобы внутри функции up_down.. читалось значение функции solid_read при каждой итерации цикла while?

Что делал: 

создал указатель на функцию :

int (*pi)(int);
void setup() {
pi = &solid_read;

Далее вызываю функцию void up_down_eeprom_var(pi(0))

и в  lcd.print(var); выводит статичное значение, которое не меняется... )  Если подставить вместо  lcd.print(var); -> lcd.print(pi(0)); то всё ок,функция читается, но так мне не нужно т.к. есть много других функций которые мне надо туда передавать.... , ; второй  вечер сижу голову ломаю...как полноценно читать функцию solid_read(int pin) внутри функции void up_down_eeprom_var( int var )? посредством указателей?=) надеюсь объяснил понятно =)

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Как-то так

void up_down_eeprom_var(int func())
{
 value = func(0);
}

up_down_eeprom_var(solid_read);

 

dachnik
Offline
Зарегистрирован: 26.07.2013

не работает...

Logik
Offline
Зарегистрирован: 05.08.2014

Из текущего проекта

typedef void (*FunOneWireDev)(OneWireDevID id);

//Поиск и перебор устройств
boolean ScanOneWire(FunOneWireDev pCallBack)
{
  OneWireDevID OneWire; 
  boolean res=false;
  
  if(Termometr.OneWireBeginFindDevice()) 
  {
    res=true;
    if(Termometr.OneWireFindNextDevice(OneWire))
      pCallBack(OneWire);
  }
  return res;
}

void TestOneWireDev(OneWireDevID id)
{
  static byte No;
  Serial.print("dev");
  Serial.print(No);
  Serial.print(":");
  for(byte i=0;i<sizeof(OneWireDevID);i++)
  {
    Serial.print(id[i],HEX);Serial.print(" ");
  }
  No++;
}

.....
  if(ScanOneWire(TestOneWireDev))
     Serial.println("end");
  else
     Serial.println("no");

 

dachnik
Offline
Зарегистрирован: 26.07.2013

не могли бы вы пояснить что-куда-откуда, а то не понятно..   

Logik
Offline
Зарегистрирован: 05.08.2014

dachnik пишет:

не могли бы вы пояснить что-куда-откуда, а то не понятно..   

Так написано ж - ScanOneWire(TestOneWireDev)!  Соответственно в ScanOneWire передаем указатель на TestOneWireDev  и оно там его того.

Спрашуйте конкретней, что не понятно.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

dachnik, тебе вроде нужно вместе с указателем на функцию еще и её параметр передать... сделай так:

int up_down_eeprom_var(int func(int), int param)
{
 return func(param);
}

value = up_down_eeprom_var(solid_read, 0);

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015
// создаём тип указателя на функцию, возвращающую int, и принимающую параметром int
typedef int (*RetIntReceiveIntFunc)(int param);

// теперь в нашей функции eeprom_что-то_там делаем параметр с типом:

void eeppom_read_var(RetIntReceiveIntFunc func)
{
// теперь вызываем функцию по переданному указателю, передавая ей нужное значение
// и получая результат
Serial.println("Call passed func with param=100");
int res = func(100);
Serial.print("Result are: ");
Serial.println(res);
}

// теперь пишем нашу функцию, которая будет вызываться
int testFunc(int val)
{
Serial.print("Passed: ");
Serial.println(val);
return val*2;
}
// тестируем
void setup()
{
Serial.begin(9600);

eeppom_read_var(testFunc); // пробуем, чего напечаталось.

}

 

releyshic
Offline
Зарегистрирован: 20.11.2015

dachnik пишет:

может  надо просто вызвать функцию где надо?


void up_down_eeprom_var( int var, int pin )
{
int x =0;
lcd.clear(); //очищаем экран
delay(del);
while(1)
{ 
int readpin = solid_read(pin); //вызов
x++;
if (x>interval){break;}
 lcd.print(" now=");
 lcd.print(var);
}} 

хотя с твоими кусками кода не понятно какого хрена ты вообще хочешь сделать

ни вызова функций нихрена нет, зачем тебе вообще указатели?

2 функции нельзя никуда передавать!!! функция это алгоритм действия над чемто (данными) как? да и зачем? их кудато передавать!

Задачу нормально сформулируй! и код нормальный дай!!

хотя готов догадаться что должно быть так

void up_down_eeprom_var( int var)
{
int x =0;
lcd.clear(); //очищаем экран
delay(del);
while(1)
{ 
int readpin = solid_read(pin); //вызов
x++;
if (x>interval){break;}
 lcd.print(" now=");
 lcd.print(solid_read(var)); //вывести значение пина var
}} 

 

dachnik
Offline
Зарегистрирован: 26.07.2013

Всем спасибо за советы, но выручила книжка по плюсам

void up_down_eeprom_var(byte eeprom_val, String label, int (*var)()); //объявляем функцию которая имеет указатель
void menu() функция выбора меню
{
int (*p)(); //создаем указатель на функцию
p=temp_in; //присваиваем адрес функции temp_in() указателю *p
up_down_eeprom_var(eeprom_solid_var_1, soil_eeprom_var_1_str, p); //вызываем функцию с указателем *p
}
void up_down_eeprom_var(byte eeprom_val, String label, int (*var)())
{
int x =0;
lcd.clear(); //очищаем экран
delay(del);
while(1)
{ //бесконечный цикл 
x++;
if (x>interval){break;}
button_read();

 lcd.setCursor(0,0);
 lcd.print(label);
 
 lcd.setCursor(0,1);
 lcd.print("set =");
 lcd.print(EEPROM.read(eeprom_val));
 lcd.print(" now=");
 lcd.print(var()); //хали хоп! и функция temp_in() обрабатывается внутри функции void up_down_eeprom_var с использованием указателя на функцию!
}

int temp_in()
 {
   sensors.requestTemperatures(); // Send the command to get temperatures
   int t = dht.readTemperature();
   return t; 
 }

Единственное, пока научился передавать функцию, не имеющую параметров, а как скажем передать функцию, которая была описана в первом посте:

 int solid_read(int pin)
{
  int val = analogRead(pin);// считываем значение
  val = map(val, 0 , 1023, 100, 0);
  return  val;             // выводим полученное значение
}

?

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

Сообщение #6

releyshic
Offline
Зарегистрирован: 20.11.2015

dachnik пишет:

 lcd.print(var()); //хали хоп! и функция temp_in() обрабатывается внутри функции void up_down_eeprom_var с использованием указателя на функцию!

я не пойму что тебе мешает вызвать функцию temp_in()

прямо внутри


lcd.print(temp_in());

? цель твоих действий?

dachnik
Offline
Зарегистрирован: 26.07.2013

Цель такова что эта функция up_down_eeprom_var служит для вызова разных настроек меню и является универсальной функцией для настройки энергонезависимой памяти контролера. Датчиков много функция одна. Экономия места и простота добавления новых устройств.

dachnik
Offline
Зарегистрирован: 26.07.2013

kisoft пишет:

Сообщение #6


Еще один лишний параметр. Можно вместе с указателем передавать...главное правильно синтаксис написать. А с этим проблема компилятор ругается

releyshic
Offline
Зарегистрирован: 20.11.2015

dachnik пишет:
Цель такова что эта функция up_down_eeprom_var служит для вызова разных настроек меню и является универсальной функцией для настройки энергонезависимой памяти контролера. Датчиков много функция одна. Экономия места и простота добавления новых устройств.

типа примитивный вариант обработчика событий ))

только вот я не не пойму о каких аргументах ты толкуешь, откуда этой функции которая всё вызывает должна знать аргументы, даже чисто логически не может знать, она и должна аргументы раздавать или запрашивать их откудато

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

dachnik пишет:
kisoft пишет:

Сообщение #6


Еще один лишний параметр. Можно вместе с указателем передавать...главное правильно синтаксис написать. А с этим проблема компилятор ругается

И? Исходник и копия ошибки. Если нет, то разбирайся сам, не вопрос.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

dachnik пишет:

Единственное, пока научился передавать функцию, не имеющую параметров, а как скажем передать функцию, которая была описана в первом посте:

Чем не устроило сообщение номер 7? Чукча не читатель?

 

 

dachnik
Offline
Зарегистрирован: 26.07.2013

не компилится...

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Вот спецом взял и скомпилировал:

// создаём тип указателя на функцию, возвращающую int, и принимающую параметром int
typedef int (*RetIntReceiveIntFunc)(int param);

// теперь в нашей функции eeprom_что-то_там делаем параметр с типом:

void eeppom_read_var(RetIntReceiveIntFunc func)
{
// теперь вызываем функцию по переданному указателю, передавая ей нужное значение
// и получая результат
Serial.println("Call passed func with param=100");
int res = func(100);
Serial.print("Result are: ");
Serial.println(res);
}

// теперь пишем нашу функцию, которая будет вызываться
int testFunc(int val)
{
Serial.print("Passed: ");
Serial.println(val);
return val*2;
}
// тестируем
void setup()
{
Serial.begin(57600);

eeppom_read_var(testFunc); // пробуем, чего напечаталось.

}


void loop() {
  // put your main code here, to run repeatedly:

}

Запустил, как ожидалось, в мониторе порта появилось:

Call passed func with param=100
Passed: 100
Result are: 200

Не компилируется, мдя... Конечно, если не думать и дописать в строчке

eeppom_read_var(testFunc); // пробуем, чего напечаталось.

Что-то типа

eeppom_read_var(testFunc(1234)); // пробуем, чего напечаталось.

То компилироваться перестанет - с чего бы это, Карл?
 

dachnik
Offline
Зарегистрирован: 26.07.2013
sketch_mar16a.ino:3:22: error: variable or field 'eeppom_read_var' declared void
sketch_mar16a.ino:3:22: error: 'RetIntReceiveIntFunc' was not declared in this scope
sketch_mar16a.ino: In function 'void setup()':
sketch_mar16a.ino:28:30: error: invalid conversion from 'int' to 'RetIntReceiveIntFunc {aka int (*)(int)}' [-fpermissive]
sketch_mar16a.ino:6:6: error:   initializing argument 1 of 'void eeppom_read_var(RetIntReceiveIntFunc)' [-fpermissive]
Ошибка компиляции.

всё равно

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

dachnik пишет:

sketch_mar16a.ino:3:22: error: variable or field 'eeppom_read_var' declared void
sketch_mar16a.ino:3:22: error: 'RetIntReceiveIntFunc' was not declared in this scope
sketch_mar16a.ino: In function 'void setup()':
sketch_mar16a.ino:28:30: error: invalid conversion from 'int' to 'RetIntReceiveIntFunc {aka int (*)(int)}' [-fpermissive]
sketch_mar16a.ino:6:6: error:   initializing argument 1 of 'void eeppom_read_var(RetIntReceiveIntFunc)' [-fpermissive]
Ошибка компиляции.

всё равно

Блин. Это ж пример! Понимаете? ПРИ-МЕ-Р!  Вы бездумно его вставили в свой код и хотите, чтобы заработало? Я не переписывал имена ваших функций, например. Ещё раз говорю: скетч компилируется. Что и куда вы вставили - вопрос: вы же не приводите ни строчки кода, который вы изменили!

Вижу лишь, что вы неправильно применяете пример, судя по

nvalid conversion from 'int' to 'RetIntReceiveIntFunc {aka int (*)(int)}

Если действительно хотите разобраться - либо давайте сюда кусок изменённого кода, который не компилируется, либо - читайте учебники по С++, в частности, про указатели, в частности - про указатели на функции.

Иначе всё это - разговор глухого с немым - понадёргают кусков кода, а потом - не компилируется. Вы хоть пробовали сделать так, как я писал: создать новый скетч, вставить туда мой код и убедиться в мониторе порта, что внутри eeprom_read_var вызывается функция, переданная по указателю на неё в eeprom_read_var? Проще уже некуда написать - посмотрите, что выводится в Serial.