Макросы

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014
Проблема следующая!
Пытаюсь подправить библиотеку (CyberLib) чтобы можно было работать с переменными и в цыкле.
 Если с D_In, D_Out, D_High, D_Low и D_Inv все нормально - подстановка происходит, что видно на прилагаемом коде, - то если запросить D_Read - выдает ошибку, хотя делал также как и с остальными.
Вопрос - Почему верхние макросы подставляют значение а последний не хочет.
(Текст Ошибки под макросом)
//Эти 2(два)  макроса работают
#define D_In(x) if(x==10) DDRB &=B11111011;
#define D_Out(x) if (x==0) DDRD |=B00000001;\
else if (x==1) DDRD |=B00000010;\
else if (x==2) DDRD |=B00000100;\
else if (x==3) DDRD |=B00001000;\
else if (x==4) DDRD |=B00010000;\
else if (x==5) DDRD |=B00100000;

//Здесь макрос тоже работает
#define D_Inv(x)  switch(x){\
   case 0: PORTD ^=B00000001; break;\
   case 1: PORTD ^=B00000010; break;\
   case 2: PORTD ^=B00000100; break;\
   case 3: PORTD ^=B00001000; break;\
   case 4: PORTD ^=B00010000; break;\
   case 5: PORTD ^=B00100000; break;\
 }

 // А ВОТ с этим проблема хотя и сделан по ВЫШЕ подобному и который работает без ошибки.
//Если раскоментировать 42_ю (buton1 = D_Read(10);) строку - идет ошибка (указана под макросом в коментарии)
#define D_Read(x) switch(x){\
  case 10: ((PINB & B00000100)>>2); break;\
  case 11: ((PINB & B00001000)>>3); break;\
  case 12: ((PINB & B00010000)>>4); break;\
  case 13: ((PINB & B00100000)>>5); break;}
 //main.ino:42: error: expected primary-expression before 'switch'
//main.ino:42: error: expected `;' before 'switch'

void setup()
{
  for(int i=2; i<6; i++)
  {
    D_Out(i); //Понимаю что правильнее DDRх - но делал для проверки работы в цыкле с переменной
  }  
}

void loop()
{ 
  static bool poz = 0;
  static bool buton1 = 0;
  //buton1 = D_Read(10);
  if(!buton1)
  {
    for(int i=3; i<6; i++)
    {
      D_Inv(i);
      poz = !poz;
      if(poz)
      {
        i--;
      }
    delay(1000);
    }
  }
   //D_Beep(13, 1000, 10);
}

Код рабочий - ели закоментировано чтение ПИНА

Смотрел библиотеку ув.Arhat, вот что он пишет - 
"При указании номера пина в переменной - этот подход НЕ РАБОТАЕТ! Макрос развернется в код, склеивающий название переменной с текстом макроса и Вы получите сообщение о синтаксических ошибках и только.
  Такой подход имеет место быть, поскольку все пины Ардуино имеют жесткую привязку к своим функциям, особенно специальным и, соответственно, всегда явно известны при разработке скетчей."
Вот сижу и думаю почему приведенный ниже код работает - может это и есть ошибка.
 
Пока думал над вопросм, для D_Read нашол такое решение, правда сменить пин можно только по дефайну - 
Хоть чтото не надо переписывать по всему коду
#define button 12
//Эти 2(два)  макроса работают
#define D_In(x) if(x==10) DDRB &=B11111011;
#define D_Out(x) if (x==0) DDRD |=B00000001;\
else if (x==1) DDRD |=B00000010;\
else if (x==2) DDRD |=B00000100;\
else if (x==3) DDRD |=B00001000;\
else if (x==4) DDRD |=B00010000;\
else if (x==5) DDRD |=B00100000;

//Здесь макрос тоже работает
#define D_Inv(x)  switch(x){\
   case 0: PORTD ^=B00000001; break;\
   case 1: PORTD ^=B00000010; break;\
   case 2: PORTD ^=B00000100; break;\
   case 3: PORTD ^=B00001000; break;\
   case 4: PORTD ^=B00010000; break;\
   case 5: PORTD ^=B00100000; break;\
 }

#define D_Read(x) _D_READ(x)
#define _D_READ(x) dread_D##x

#define dread_D10 ((PINB & B00000100)>>2)
#define dread_D11 ((PINB & B00001000)>>3)
#define dread_D12 ((PINB & B00010000)>>4)
#define dread_D13 ((PINB & B00100000)>>5)

void setup()
{
  for(int i=2; i<6; i++)
  {
    D_Out(i); //Понимаю что правильнее DDRх - но делал для проверки работы в цыкле с переменной
  }  
  D_In(button);
}

void loop()
{ 
  static bool poz = 0;
  if(D_Read(button))
  {
    for(int i=3; i<6; i++)
    {
      D_Inv(i);
      poz = !poz;
      if(poz) i--;
      delay(1000);
    }
  }
   //D_Beep(13, 1000, 10);
}

 

Но вопрос по первому коду остается Открытым - ПОЧЕМУ? 
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Но, Вы же своими кейсами убили саму идею киберлиба! У Вас хоть переменная, хоть константа - одной командой не получится.

Делать надо так, чтобы при константе получалась лдна команда, а при переменной - короткое вычисление. Возмите DigitalPins - там это уже сделано

b707
Offline
Зарегистрирован: 26.05.2017

vosara - а вы попробуйте сами выполнить подстановку вместо компилятора

Вот что получается:

buton1 =  switch(x){
  case 10: ((PINB & B00000100)>>2); break;\
  case 11: ((PINB & B00001000)>>3); break;\
  case 12: ((PINB & B00010000)>>4); break;\
  case 13: ((PINB & B00100000)>>5); break;}
}

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

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

b707 пишет:

vosara - а вы попробуйте сами выполнить подстановку вместо компилятора

Вот что получается:

buton1 =  switch(x){
  case 10: ((PINB & B00000100)>>2); break;\
  case 11: ((PINB & B00001000)>>3); break;\
  case 12: ((PINB & B00010000)>>4); break;\
  case 13: ((PINB & B00100000)>>5); break;}
}

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

Смотрите как я вижу работу макроса. Возможно я ошибаюсь - поправте

#define D_Out(x) if (x==0) DDRD |=B00000001;\
else if (x==1) DDRD |=B00000010;\
else if (x==2) DDRD |=B00000100;\

#define D_Inv(x)  switch(x){\
   case 1: PORTD ^=B00000010; break;\
   case 2: PORTD ^=B00000100; break;\
 }
 
#define D_Read(x) switch(x){\
  case 10: ((PINB & B00000100)>>2); break;\
  case 11: ((PINB & B00001000)>>3); break;\
}

void setup(){

 D_Out(2);//Кампилятор перед кампиляцией должен заменить эту строчку на
 DDRD |=B00000100;//и похоже он это делает

}

void loop(){

  D_Inv(2);//Кампилятор перед кампиляцией должен заменить эту строчку на
  PORTD ^=B00000100;//и похоже он это делает

  buton = D_Read(10)//Кампилятор перед кампиляцией должен заменить эту строчку на
  buton = ((PINB & B00000100)>>2)//А вот здесь облом
  
}

 

b707
Offline
Зарегистрирован: 26.05.2017

[quote=vosara]

Кампилятор перед кампиляцией должен заменить эту строчку на

buton = D_Read(10)

на

buton = ((PINB & B00000100)>>2)

[\quote]

Неправильно. Макрос, это всего лишь текстовая подстановка, никакие блоки кода в момент подставновки не вычисляются.

На место вашего D_Read(10) будет подставлен не конкретный кэйс из свитча, а весь блок свитча целиком, и что в итоге выйдет - я написал в сообщении #2 выше

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

b707 пишет:
никакие блоки кода в момент подставновки не вычисляются.
Я чуток добавлю.

Вычисляются ПОСЛЕ подстановки. Т.е. при подстановке блок должен быть корректным.

А значит Вам тут надо использовать не switch, а тернарный оператор. Посмотрите, наконец DigitalPins, там всё это сделано.

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014
Это я понял, только не понятно почему макрос работает выборочно
При D_Out(2); и D_Inv(2); он не тянет ввесь блок свича а выбирает кэйс.
Вот полностью рабочий код
#define D_Out(x) if (x==0) DDRD |=B00000001;\
else if (x==1) DDRD |=B00000010;\
else if (x==2) DDRD |=B00000100;\

#define D_Inv(x)  switch(x){\
   case 1: PORTD ^=B00000010; break;\
   case 2: PORTD ^=B00000100; break;\
 }
 
#define D_Read(x) switch(x){\
  case 10: ((PINB & B00000100)>>2); break;\
  case 11: ((PINB & B00001000)>>3); break;\
}

void setup(){

 D_Out(2);//Кампилятор перед кампиляцией должен заменить эту строчку на
 //DDRD |=B00000100;//и похоже он это делает

}

void loop(){

  D_Inv(2);//Кампилятор перед кампиляцией должен заменить эту строчку на
  //PORTD ^=B00000100;//и похоже он это делает
  delay(1000);
}

 

 

b707
Offline
Зарегистрирован: 26.05.2017

vosara - да с чего вы взяли. что он свитч не тянет? - тянет точно так же

Замените свою строчку 24 на

byte i = D_Inv(2);

и убедитесь в наличии точно той же ошибки, как в прошлом случае

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Да Ошибка. Спасибо!