Pull to refresh

Comments 27

На что только люди не идут, чтобы не учить макросы вообще и x-macro c _Generic в частности…
Написав первые 26 #define, энтузиазм иссяк.

Тогда хотя бы:
chap = [chr(x) for x in range(97, 123)] + [chr(x).upper() for x in range(97, 123)]
num = [str(x) for x in range(2, 54)]
А лучше нагуглить или вспомнить string.ascii_letters и string.ascii_uppercase. Тогда и первого P.S. не было бы :)

Ъ-индусский код!


А с циклами и массивами пробовали то же самое написать?

Так это было на заказ сделано. Наверно, оплата шла за каждую строчку кода.
Как говориться как кто умеет, была бы лень, а прогресс будет. Я даже не знаю как поступил был, скорее всего вообще использовал бы XL…
image
хотя дальше все сложнее, но мне просто лень.
Решение с экселем выглядит очень лаконично, учитывая что сделать это можно меньше чем за минуту.
Да, буквально две «формулы» и протянуть вниз.
Первый столбик коды символов, второй рыба, третий превращение этих самых символов из первого столбика в буквы. Можно конечно завести алфавитный список в XL и «проятнуть», но это дольше. 4й порты (забыл их добавить к результату), ну и последний сращиваем все через & в одну строку, профит!
Excel мало подходит, для такого кода
if(ledState_a == true){ 
time_a = time_a - 1; 
digitalWrite(PIN_a, HIGH); 
} 

Очень подходит, попробуйте. Правда с телефона будет не просто это сделать, а вот с мышкой буквально секунды занимает.

Вот это индусятина) Хотя бы как-то так:
for ch in string.ascii_letters:
    print('#define PIN_' + ch, string.ascii_letters.index(ch) + 2)

Учите Python, господа!

Ну, хоть самокритично)
По-моему так получше будет:
import string
for i, ch in enumerate(string.ascii_letters):
    print("#define PIN_{} {}".format(ch, i + 2))
Тогда уж
import string
for i, ch in enumerate(string.ascii_letters, start=2):
    print("#define PIN_{} {}".format(ch, i))
Для питона есть удобный темплейтный движок mako — с ним можно получить читаемый код без этих обёрток в виде print(..). В частности, на нём работает кодогенерация в pyopencl.
А зачем anaconda, если python из коробки в windows и так уже работает нормально? Какие то ещё батники писать… При установке нужно просто галочку поставить, чтоб нужные пути в path попали или сделать потом это ручками. А так и pip уже давно в комплекте идёт и работает прекрасно.

Я понимаю, что можно не быть хорошим программистом и при этом писать программы, хотя бы для ардуино. Но выкладывать это на хабр — как-то странно.

На самом деле вопрос про внешнюю кодогенерацию интересный, потому что С:
— старый и не имеет части возможностей более новых языков. Например, объекты в чистом С дают неслабый оверхед.
— многословный
— с системой макросов, сложных и неинтуитивных. Например, иногда очень хочется сделать define внутри define, или сделать дефайн с генерацией имени через конкатенацию строк в макросе, или использовать if в макросе с раскруткой в compile time, или разделить токен в макросе на части — а низзя, если не брать в расчет извращения типа
g++ -E input.cpp | g++ -c -x c++ - -o output.o

примерно те же проблемы имеет asm
Поэтому в принципе разумно написать короткий понятный код на питоне или ещё на чём, который будет генерировать неподдерживаемый, но шустрый код на С/asm. Проблема в том, что нет устоявшегося мнения, как это делать «правильно»

На питоне простой понятный код будет тормозить, бай дизайн. Си конечно не идеален, и с обьектами там не очень. Но он быстрый. Просто нужно понимать разницу между задачей светодиодом моргнуть и скажем одновременного приема с трех SPI сообщений, с парсингом.

Вот про это я и говорю, что нет устоявшегося мнения про «правильно». Если у нас задача в питоне сгенерировать текстовый файл на несколько тысяч строк, то он навряд ли будет тормозить так, что это станет неприемлемо, но зато мы теоретически сможем помочь gcc с оптимизацией и отбить время на компиляции. Задача становится ещё интереснее, если мы генерируем код на asm, потому, например, что там мы можем выходить из прерывания не туда, откуда в него вошли; такой код сложен в поддержке, но если его писать не на асме, может получить оба достоинства.
Правда, это ни у кого не получилось, чтоб аж прям выстрелить. Разработка компиляторов или кодогенераторов на прологе всплывает с 70х и по наши дни, но значимого выхлопа не видно.
Ссылки на компиляторы и кодогенераторы на прологе
1.Applied logic — it's use and implementation as programming tool. Technical note, 1977
2. Parsing and Compiling Using Prolog, 1987
3. An implementation of retargetable code generators in prolog, 1988
4. Prolog based retargetable code generation, 1989
5. Code Generation — Concepts, Tools, Techniques: Proceedings of the International Workshop on Code Generation, Dagstuhl, Germany, 20–24 May 1991 глава 5, Prolog Implementation,
6. The Practice of Prolog, глава 4, Developing a parallelising Pascal compiler in Prolog (про Паскаль — потому что написано в стиле пошагового туториала), 1990

Видел и публикации 2010х, но там не так интересно и более специализировано
UFO landed and left these words here
написал алфавит

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

Можно как-то так:
#define FIRST_PIN  2
#define LAST_PIN  27


#define PIN_COUNT (LAST_PIN - FIRST_PIN + 1)

word timeout[PIN_COUNT]; 
word elapsed[PIN_COUNT];

void setup() {
  for (byte i = 0; i < PIN_COUNT; i++) {
    timeout[i] = 1000;
    elapsed[i] = 0;
  }

  for (byte i = FIRST_PIN; i <= LAST_PIN; i++) {
    pinMode(i, OUTPUT); 
    pinMode(i + PIN_COUNT, OUTPUT);
  }
  
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0) {
    char x = Serial.read();
    
    if ((x >= 'a') && (x < ('a' + PIN_COUNT))) {
      byte index = x - 'a';
      byte pin = index + FIRST_PIN;
      elapsed[index] = timeout[index];
      digitalWrite(pin, HIGH);
    } else if ((x >= 'A') && (x < ('A' + PIN_COUNT))) {
      byte index = x - 'A';
      byte pin = index + LAST_PIN + 1;
      digitalWrite (pin, !digitalRead(pin));
    }
  }

  delay(1);
  for (byte index = 0; index < PIN_COUNT; index++) {
    if (elapsed[index]) {
      if (--elapsed[index]) {
        char pin = index + FIRST_PIN;
        digitalWrite(pin, LOW);
      }
    }
  }
}


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

Надеюсь, что статьи программистов о разводке плат выглядят не так жалко и беспомощно…

Если есть возможность менять клиентский код, то можно просто было воспользоваться firmata для таких целей.
С ней вообще не надо писать firmware, только client code. А вот его можно писать на любом языке почти, там куча реализаций библиотек протокола.

можно еще все из-под условий в отдельные фунции выделить:

// установить а
long set_a() {
  ledState_a = true;
  time_a = TIME_a;
  return 0;
}

//...

void loop() {

  //...

  //a
  if(x == 'a'){
    set_a();
    x = 0;
  }

  // ...

}


для каждой проверки отдельную функцию, само собой.
Sign up to leave a comment.

Articles