20.12.2009

Удвоение пинов Arduino (1)

Часто приходится слышать, что "буду покупать Arduino Mega, потому что в обычном Arduino мало выводов". Действительно: а что делать, если цифровых выводов Arduino хронически не хватает? Тем, кто настроен на покупку, настоятельно рекомендую Freeduino Mega 2560 - по крайней мере, и выводов, и возможностей у нее побольше.

Но есть и более дешевый способ, о котором не подозревают начинающие. Попытаемся исправить ;)

Часть I. Размножение выходов, или ShifOut

Понадобится логическая микросхема, которая принимает данные последовательно, а выдает – параллельно. Наиболее популярным решением является 74HC595:



Полностью ее название звучит как 8-bit serial-in, serial or parallel-out shift register with output latches; 3-state, а по-русски - восьмибитный сдвиговый регистр с последовательным входом и последовательным или параллельным выходом с защелкой и высокоимпендансным выходом.

Для нас это значит, что микросхема умеет последовательно, бит за битом, принимать данные по двум входам и по команде "покажи" выставлять полученный код на своих восьми выходах. Заглянем внутрь (а там сплошные триггеры ;):



"Защелка" (по англ. latch) – это регистр хранения на выходе, который удерживает предыдущий принятый код, пока последовательным способом принимается очередная порция данных. В процессе сдвига данные передаются слева направо между триггерами FFx: со входа DS в FF0, с выхода FF0 в FF1 и так далее; самое последнее значение "выталкивается" из FF7 и теряется навсегда в окружающем пространстве-времени. Но расстраиваться не стоит - это же сдвиговый регистр, ему так и положено работать! ;) В нужный момент FFx переписываются "вниз" - в триггеры LATCH и, если на то будет инверсный разрешающий сигнал OE (Output Enable), код появится на выходах Q0-Q7.

Eagle в курсе про 74HC595, искомый элемент располагается в библиотеке "74xx-eu", секция "74*595". Рисуем простейшую схему:


Немного смущает различное наименование выводов чипа 74HC595 в datasheet и в Eagle - видимо сказывается длительный срок жизни этой микросхемы. Но в любом случае, смысл у них один и тот же. На схеме сделаны следующие соединения:
  • вывод 8 – земля микросхемы 
  • вывод 16 – питание микросхемы 
  • вывод 13 - инверсное разрешение вывода информации – уровень логического нуля на этом входе разрешает выставить хранимый в защелке код на параллельные выходы (Q0-Q7, они же QA-QH). Для простоты подключаем к GND - всегда выводить;
  • вывод 10 – инверсный вход сброса сдвигового регистра. Тоже обходимся без него, поэтому делаем его пожизненно неактивным -  подаем туда логическую единицу (на то он инверсный), притягивая к питанию VСС;
  • вывод 14 - последовательный вход данных от МК. Подключаем его к digital 11;
  • вывод 11 - вход синхронизации данных, подключаем к digital 12;
  • вывод 12 - синхронизация защелки, подключаем к digital 8.
Как видите, в самом простом варианте у Arduino расходуются только три цифровых выхода.

#define DS   11
#define SHCP 12
#define STCP 8

void send595(byte output) {
  for (int i=0;i<8;i++){
    digitalWrite(DS,output & 1);
    digitalWrite(SHCP,LOW);
    delay(1);
    digitalWrite(SHCP,HIGH);
    output >>= 1;
  }
  digitalWrite(STCP,HIGH);
  delay(1);
  digitalWrite(STCP,LOW);  
}

void setup() {
  pinMode(DS,OUTPUT);
  pinMode(SHCP,OUTPUT);
  pinMode(STCP,OUTPUT);
  digitalWrite(SHCP,LOW);  
  digitalWrite(STCP,LOW);  
}

void loop() {
  for (int k=0;k<256;k++) {
    send595(k);
    delay(100);
  }
}


Если к каждому из выходов SV2 подключить по светодиоду, то мы сможем визуально последовательно наблюдать, как выглядят двоичные числа от 0 до 255 (снова и снова, пока работает loop ;).

Данные передаются по линии DS, при этом микросхема 595 воспринимает их по фронту сигнала SH_CP - это такой момент времени, когда сигнал переходит из состояния логического нуля в единицу. По окончании приема очередных восьми бит надо ненадолго установить ST_CP, чтобы поместить данные в защелку.

Я поместил вывод байта в отдельную процедуру send595(output) для наглядности, но теперь пора открыть страшную тайну пояснить, что в языке Wiring предусмотрен специальный оператор shiftOut(dataPin, clockPin, bitOrder, value), выполняющий побитовый вывод байтового значения value в порядке bitOrder (имеется ввиду направление вывода value - от старшего бита к младшему или наоборот - от младшего к старшему) через dataPin и clockPin. Как раз подходит для нашего случая:

#define DS   11
#define SHCP 12
#define STCP 8

void setup() {
  pinMode(DS,OUTPUT);
  pinMode(SHCP,OUTPUT);
  pinMode(STCP,OUTPUT);
  digitalWrite(SHCP,LOW);  
  digitalWrite(STCP,LOW);  
}

void loop() {
  for (int k=0;k<256;k++) {
    shiftOut(DS,SHCP,LSBFIRST,k);
    digitalWrite(STCP,HIGH);
    delay(1);
    digitalWrite(STCP,LOW); 
    delay(100);
  }
}


Подведем промежуточные итоги.

Мы пожертвовали тремя,  получили 8, в итоге добавив 5 дополнительных входов. У обычного Arduino 19 выходов, и, теоретически, можно использовать 6 групп по 3, получив 6 * 8 = 48 выходов.

Но не спешите делать вывод, что это предел. Предела вообще нет! Благодаря специальному последовательному выходу Q7`, можно объединить несколько микросхем, получив 16, 24, 32 и т. д. разрядов:


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

Чтобы изменить состояние хотя бы даже одного из выходов 75HC595, нам придется прогнать  последовательно все 8, 16, 24, 32... разряда через вход DS. Чем больше разрядов - тем больше время установки. А чем больше времени тратится на изменение одного разряда, тем меньше скорость изменения выходного сигнала. Впрочем, вполне вероятно, для некоторых приложений это ограничение не будет существенным, попробуем подсчитать.

На вывод одного разряда необходимо как минимум выполнить одну ассемблерную инструкцию сдвига, одну - вывода в порт и две - на переход в цикле. МК построен по RISC-архитектуре и выполняет одну операцию за такт, работая на частоте 16 МГц. Значит, четыре такта он обрабатывает за 250 нс. Таким образом байт будет выведен не менее, чем за 2 мкс, а предельная частота составит 0,5 МГц (это грубая прикидка верхнего значения -  буду признателен, если кто-то подсчитает точнее).

Побороться с этим пределом будет довольно сложно, потому что все известные мне пути довольно ограничены:

  • повысить тактовую частоту МК больше 16 МГц: потеряем базовую совместимость с Arduino, придется исправлять константу в библиотеке, менять кварц на плате. Больше 20 МГц не получится, увы - а это прирост всего-то на 25%;
  • повысить питание 75HC595N: таково уж свойство КМОП-логики - чем больше напряжение, тем быстрее работает. Но МК Arduino (тоже построенный на КМОП) и так работает на предельном напряжении 4,5..5,5В, и вот его-то ускорить уже не удастся;  В то же время, быстродействие зависит и от серии микросхемы - можно по крайней мере не выбирать древние и медленные. Ставьте современные 74HC595 или даже 74HCT595 и будете иметь в запасе предел 100 МГц, который с запасом "накрывает" способности нашего МК в Arduino.

Таким образом, с выходами разобрались.

А что нужно делать, чтобы размножить входы? Читайте во второй части.

(использованы материалы из статьи Serial to Parallel Shifting-Out with a 74HC595)

35 комментариев:

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

    ОтветитьУдалить
  2. Notice the 0.1uf capacitor on the latchPin, if you have some flicker when the latch pin pulses you can use a capacitor to even it out.

    ОтветитьУдалить
  3. а как написать на двух семисегментных к примеру 2.6? все примеры,которые я видел с какими то бегающими огнями,а я темный :\

    ОтветитьУдалить
  4. С семисегментными индикаторами в основном работают в режиме мультиплексирования - эти "бегущие огни" имеются ввиду?

    ОтветитьУдалить
  5. да нет :),во всех примерах какие я видел (теперь уже три! :))
    используются примерно такие кострукции:
    for (int k=0;k<256;k++) {
    shiftOut(DS,SHCP,LSBFIRST,k);
    я не могу предположить почему делается так.мне нужна самая простая вещь-к примеру 01001100 на восьми выходах.я думал это и есть "битордер" и писал нужный набор нулей и единиц.но так он не работает:)

    ОтветитьУдалить
  6. Попробуйте shiftOut(DS,SHCP,LSBFIRST,0x4c);

    ОтветитьУдалить
  7. Еще можно написать про PFC8574, на ней можно делать и цифровой вход и цифровой выход + цепляется он по I2C =)правда чип такой стоит в несколько раз дороже ....

    ОтветитьУдалить
  8. В очередной раз напоминаю, что приглашаю соавторов ;)

    ОтветитьУдалить
  9. Это "01001100" в шестнадцатеричном представлении.

    Вы же хотели вывести конкретное число, я правильно понял?

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

    Wiring различает численные константы, записанные в разных системах: по умолчанию десятичная, с префиксом "0x" - шестнадцатеричная, c префиксом "B" - бинарная, с префиском "0" - восьмиричная. В вашем случае правильно будет одно из: "B01001100", "0x4c", "1036". Более подробно см. здесь.

    ОтветитьУдалить
  10. Для реальных серьезных приложений может имеет смысл смотреть на SPI?

    ОтветитьУдалить
  11. PFC8574 - хорошая штука, опробовал в действии с Arduino. Полезно, если что-либо имеет двунаправленную шину 8 бит. Тогда это устройство можно подключить к Arduino с минимумом затрат по пинам. Одна микросхема и ввод и вывод. (буду использовать для переделки http://arduinoaboveandbeyond.blogspot.com/2009/12/arduino-with-ibm-at-rtc-module.html)
    Ктсати PFC8574 можно бесплатно заказать для экспериментов на сайте-производителе http://www.ti.com .

    ОтветитьУдалить
  12. Я уже второй день бюсь над одной и той же проблемой. Я не могу высести HIGH на какую-то одну ножку(74НС595). При таком коде (я уже кучу кодов переписал):

    #define DS 11
    #define SHCP 12
    #define STCP 8

    void setup() {
    pinMode(DS,OUTPUT);
    pinMode(SHCP,OUTPUT);
    pinMode(STCP,OUTPUT);
    }

    void loop() {
    shiftOut(DS,SHCP,LSBFIRST,1);
    digitalWrite(STCP,HIGH);
    delay(100);
    digitalWrite(STCP,LOW);
    delay(100);
    }
    }
    светодиод на ножке 1 просто загорается и светит и он не мигает. У меня как-то получалось писать что б на одну ножку только подавалось но не сохранил код и забыл как я это делал. Я даже ШИМ (плавное загорание и затухание светодиода) выводил на отдельную ножку а сейчас не помню. Подскажите пожалуйсто!. Мне нужно именно на отдельную ножку (я это делал без всяких циклов) виводить (+ или -). Или какое-то значение ШИМ. Заранее спасобо!!!

    ОтветитьУдалить
  13. Так все правильно: если в loop выводить константу (т.е. неизменную величину) - светодиоды как загорятся, так и не изменят своего состояния.

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

    ОтветитьУдалить
  14. Нужно что б светодиод через некоторую задержку
    delay(100);
    гас. потом опять згорался. короче мигал. И было это на ножке 7 например (Q7). Дальше шим уже будет переписать не сложно (Хочу размножить количество ШИМ, но сначало нужно разобратся в обычном мигании). Я вообще хочу свою схему сделать усправления сервами. Вот этот метод мне понятем и я вижу не сложную програмную реализацию. (Програмирование знаю хорошо). Не исключаю, что есть другие методы, может даже легче, но хочу с этим разобратся. Подскажите как сделать, что б он мигал. И большое спасибо автору за информацию и всем, кто помогает. Без вашей помоци нам не развиватся =)

    ОтветитьУдалить
  15. Представьте себе, что светодиод подключен без всякой 595-ой, напрямую к выходу Arduino. Напишите sketch, который будет мигать с необходимой задержкой. А потом замените digitalWrite на shiftOut. При этом в зависимости от того, HIGH или LOW был в digitalWrite, надо устанавливать в единицу или ноль позиционно соответствующий бит последнего аргумента shiftOut. Для описанного случая:

    было:

    digitalWrite(HIGH,pinX)

    стало:

    shiftOut(DS,SHCP,LSBFIRST,1); digitalWrite(STCP,HIGH);
    delayMicroseconds(100);
    digitalWrite(STCP,LOW);

    и

    было:

    digitalWrite(LOW,pinX)

    стало:

    shiftOut(DS,SHCP,LSBFIRST,0)
    digitalWrite(STCP,HIGH);
    delayMicroseconds(100);
    digitalWrite(STCP,LOW);

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

    ОтветитьУдалить
  16. Написал скетч: #define DS 11
    #define SHCP 12
    #define STCP 8

    void setup()
    {
    pinMode(DS,OUTPUT);
    pinMode(SHCP,OUTPUT);
    pinMode(STCP,OUTPUT);
    }

    void loop()
    {
    shiftOut(DS,SHCP,LSBFIRST,1);
    digitalWrite(STCP,HIGH);
    delayMicroseconds(100);
    digitalWrite(STCP,LOW);
    /////////////////////////////
    shiftOut(DS,SHCP,LSBFIRST,0);
    digitalWrite(STCP,HIGH);
    delayMicroseconds(100);
    digitalWrite(STCP,LOW);
    }
    Залил в ардуину. Все равно не пашет. Светодиод на ножке 7(Q7). Тупо зарогается и горит. Я уже думаю может у меня ардуина не правильно работает((. Но вроде все нормально. Подключал ко всем выходам светодиод (писал скетч мигания для каждого выхода)все работает. Проверял даже ШИМ скетчем, тоже все ок. В чем проблема?. И я еше не могу понять как она именно обрашается к отдельной ножке?
    shiftOut(DS,SHCP,LSBFIRST,1) - я так понимаю 1, это первый байт. А так как он идет "с другой стороны" то от попадает на ножку 7(Q7). Если мы будем двигатся не с старшего а с младшего MBFIRST (точно не помню ф-цию) то попадем на ножку 15(Q0), так?. А если мы хотим обратится к ножке 3 и двигаемся со старшего, то ф-ция будет выглядеть так:?::: shiftOut(DS,SHCP,LSBFIRST,5)???.

    ОтветитьУдалить
  17. Я же сказал - сначала написать программу так, как будто бы нет никакой 595-ой.

    Задержку пропустили.

    Там, где много "красивых палочек наискосок" поставьте delay(1000) и перед самой последней фигурной закрывающей скобкой - еще delay(1000).

    ОтветитьУдалить
  18. А как произвести обращение? "А если мы хотим обратится к ножке 3 и двигаемся со старшего, то ф-ция будет выглядеть так:? shiftOut(DS,SHCP,LSBFIRST,5)???"

    ОтветитьУдалить
  19. А как обрашатся правильно к ножке? "И я еше не могу понять как она именно обрашается к отдельной ножке?
    shiftOut(DS,SHCP,LSBFIRST,1) - я так понимаю 1, это первый байт. А так как он идет "с другой стороны" то от попадает на ножку 7(Q7). Если мы будем двигатся не с старшего а с младшего MBFIRST (точно не помню ф-цию) то попадем на ножку 15(Q0), так?. А если мы хотим обратится к ножке 3 и двигаемся со старшего, то ф-ция будет выглядеть так:?::: shiftOut(DS,SHCP,LSBFIRST,5)???." И обясните пожалуйсто, зачем нужно так же само "зажигать и гасить" 0 байт? "При этом в зависимости от того, HIGH или LOW был в digitalWrite, надо устанавливать в единицу или ноль позиционно соответствующий бит последнего аргумента shiftOut." Спасибо за ответы!

    ОтветитьУдалить
  20. И можно ли как-то бойтись без установки в единицу или ноль позиционно соответствующий бит последнего аргумента shiftOut?

    ОтветитьУдалить
  21. А что значит "обращение к ножке"? Ввод или вывод?

    ОтветитьУдалить
  22. В этом случае "обращение к ножке" заключается в правильном задании последнего аргумента shiftOut. Он имеет тип byte или 8 бит. В двоичном представлении каждый бит этого байта отвечает за соответствующий выход 595-ой схемы - от Q0 до Q7.

    Для того, чтобы "зажечь" или "погасить" светодиод на соответствующем выводе 595-ой, надо в этом самом байте установить нужный бит в 1 или 0.

    Например, зажечь два крайних светодиода - это в двоичном виде 10000001. Можно перевести в десятичный (129) - и тогда можно написать так: shiftOut(DS,SHCP,LSBFIRST,129).

    Но можно и не переводить, а сразу писать в двоичном виде, если так нагляднее: shiftOut(DS,SHCP,LSBFIRST,B10000001).

    Вот так и происходит "обращение". Не знаю уж, как проще объяснить...

    ОтветитьУдалить
  23. Спасибо за ответ! Теперь понял =)
    Еще есть вопросики:
    1. Написал скетч для ШИМ (плавного включения свтодиода):
    #define DS 11
    #define SHCP 12
    #define STCP 9
    int value;


    void setup()
    {
    pinMode(DS,OUTPUT);
    pinMode(SHCP,OUTPUT);
    pinMode(STCP,OUTPUT);
    }

    void loop()
    {
    for(value = 0 ; value <= 255; value+=5)
    {
    shiftOut(DS,SHCP,LSBFIRST,B10000001);
    analogWrite(STCP, value);
    //digitalWrite(STCP,HIGH);
    delay(30);
    }
    digitalWrite(STCP,LOW);



    shiftOut(DS,SHCP,LSBFIRST,0); //-
    digitalWrite(STCP,HIGH); //| for
    digitalWrite(STCP,LOW); //| what?
    delay(1000); //-

    }
    Светодиод не плавно включается. Просто резко включается и выключается. Где моя ошибка? (похоже она в вопросе №2)
    Вопрос №2: Я так и не могу понять зачем этот кусок кода?:
    shiftOut(DS,SHCP,LSBFIRST,0); //-
    digitalWrite(STCP,HIGH); //| for
    digitalWrite(STCP,LOW); //| what?
    delay(1000); //-
    зачем выводить в - 0?????.Как он работает? Как можна без него обойтись? (Это самый главный вопрос) Как-то писал(Блин вот бы вспомнить=( ), что б просто выводить:
    digitalWrite(STCP,HIGH);
    digitalWrite(STCP,LOW);
    и все!, а не описывал включение
    digitalWrite(STCP,HIGH);
    digitalWrite(STCP,LOW);
    delay(1000);
    и выключение:
    digitalWrite(STCP,HIGH);
    digitalWrite(STCP,LOW);
    delay(1000);
    Код был у меня в 2 раза короче((. Подскажите как это описывается так:? Заранее спасибо!

    ОтветитьУдалить
  24. Использовать analogWrite в данной ситуации - неправильно. В статье я вообще нигде не упоминаю, как размножать ШИМ-выходы, это отдельная тема для отдельной статьи.

    Ответ на вопрос N1: размножить ШИМ можно, но никак не через analogWrite, а только через варьирование задержек между включением и выключением светодиода в цикле.

    Ответ на вопрос N2: этот кусок кода нужен для того, чтобы погасить светодиод. Без него можно, конечно, обойтись - тогда светодиод будет гореть все время.

    К сожалению, то, что Вы писали и забыли я не в силах разгадать. Читать мысли для меня пока что не представляется возможным ;)

    Может кто-то другой поможет?

    ОтветитьУдалить
  25. "а только через варьирование задержек между включением и выключением светодиода в цикле"
    А где про это можно пичитать. (Если можно с примерами). Или может вы покажите кусок кода а там дальше можна будет разбиратся. И у меня проблема в том, что мне нужно со всеми выходами общатся (это же управление сервами).
    А как вообще производиться обшение с сервами на плате SSC-32? Ардуина же через сдвиговые рпгистры сиглал подает, и регистры то 74НС595.

    ОтветитьУдалить
  26. Про ШИМ можно почитать у DI-HALT-а, например.

    ОтветитьУдалить
  27. Здравствуйте. И все таки было бы очень здорово узнать, как же увеличить количество ШИМ-выходов на Arduino. Видимо с использованием сдвиговых регистров? Было бы очень здорово увидеть примеры в коде)

    ОтветитьУдалить
  28. И все таки было бы очень здорово узнать, как же увеличить количество ШИМ-выходов. Видимо как то при помощи тех же сдвиговых регистров? Еще бы примеры в коде)

    ОтветитьУдалить
  29. Здравствуйте, помогите пожалуйста разобраться с проблемой. После заливки скетчей из статьи светодиоды просто загораются по цепочке, а потом гаснут, тоже по цепочке, про этом они какое то время все вместе горят. При изменении delay(100) изменяется время между загоранием светодиодов в цепи. Это никак не похоже на выведение всех цифр от 0 до 255 в двоичном представлении. Если же залить скетч с таким содержанием:
    digitalWrite(0, HIGH);
    digitalWrite(1, HIGH);
    delay(1);
    digitalWrite(1, LOW);
    digitalWrite(0, LOW);
    digitalWrite(2, HIGH);
    delay(1);
    digitalWrite(1.low);
    digitalWrite(1, HIGH);
    delay(1);
    digitalWrite(1, low);
    digitalWrite(1, HIGH);
    delay(1);
    digitalWrite(1, low);
    digitalWrite(1, HIGH);
    delay(1);
    digitalWrite(1, low);
    digitalWrite(1, HIGH);
    delay(1);
    digitalWrite(1, low);
    digitalWrite(1, HIGH);
    delay(1);
    digitalWrite(1, low);
    digitalWrite(1, HIGH);
    delay(1);
    digitalWrite(1, low);
    digitalWrite(2, HIGH);
    delay(1);
    digitalWrite(2, low);
    то все просто не горит (DC - 0, SHCP - 1, STCP - 2);
    Помогите пожалуйста

    ОтветитьУдалить
  30. Коллега, а зачем используете пины 0 и 1? Вы вообще в курсе, что к ним FT232 подключена? Советую переделать схему в точности, как в статье. Тогда, скорее всего, и заработает.

    Если не поможет - welcome to форум, будем разбираться подробно.

    ОтветитьУдалить
  31. Во первых хочу сказать автору огромное спасибо, благодаря серии статей я наконецто научился (тсс, чтоб не спугнуть ;) ) работать с микросхемами подобного типа.

    А во вторых у меня возник вопрос (для бывалых пользователей наверное смешной)
    И так, почитав статьи, поучив даташит, написал скетч, который зажигает мои диодики на всех восьми ножках с некой последовательностью,

    byte g = B01111000;
    shiftOut(DS, SHCP, LSBFIRST, g);
    digitalWrite(STCP, HIGH);
    delay(1000);
    digitalWrite(STCP, LOW);


    g = B10000111;

    shiftOut(DS, SHCP, LSBFIRST, g);
    digitalWrite(STCP, HIGH);
    delay(1000);
    digitalWrite(STCP, LOW);


    но

    мне надо чтоб ети самые 8 диодов сообщали мне визуально о состоянии неких переменных в к-ве 8 штук соответсвенно, логика чайника подсказывает мне такой (казалось бы простой) вариант решения - я определяю значения каждой переменной отдельно ( скажем q1 - q8) и я заведомо знаю, что значения могу быть либо 0 либо 1 (данные, полученные с цыфровых датчиков) и записываю их в значения передаваемого бита в ввиде
    g = B10000111;
    где на самом деле g = B(q1)(q2)(q3)(q4)...(q8)

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

    внимание сам вопрос, как мне создать мою переменную g таким образом, чтоб каждый байт в ней отвечал состоянию переменной q1-q8 соответственно?

    (прошу прощения за много буков, я убил немало времени на поиск ответа в инете, но увы не нашел)


    ОтветитьУдалить
    Ответы
    1. g = (q1 ? (1<<7) : 0) + (q2 ? (1<<6) : 0) + (q3 ? (1<<5) : 0) + (q4 ? (1<<4) : 0) + (q5 ? (1<<3) : 0) + (q6 ? (1<<2) : 0) + (q7 ? (1<<2) : 0) + (q8 ? 1 : 0);

      Удалить
    2. Спасибо!
      Как ето часто бывает, мне не хватило совсем чуточку чтоб найти ответ, не прошло и 10 минут, после моего поста, а я нашел решение, записал я его так
      g = 0;
      g = g + d1;
      g = g << 1;
      g = g + d2;
      g = g << 1;
      g = g + d3;
      g = g << 1;
      g = g + d4;
      g = g << 1;
      g = g + d5;
      g = g << 1;
      g = g + d6;
      g = g << 1;
      g = g + d7;
      g = g << 1;
      g = g + d8;

      Удалить