Доброго времени суток. Подскажите пожалуйста. Хочу управлять блоком реле с помощью сдвигового регистра. Возможно ли в функцию shiftOut() передать значения булиновских переменных? shiftOut(dataPin, clockPin, LSBFIRST, j); Как из 8 переменных boolean сделать эту j? Спасибо.
Тупо в лоб: Код (C++): uint8_t j = uint8_t(boolean1) | (uint8_t(boolean2) << 1) | (uint8_t(boolean3) << 2) | (uint8_t(boolean4) << 3) | (uint8_t(boolean5) << 4) | (uint8_t(boolean6) << 5) | (uint8_t(boolean7) << 6) | (uint8_t(boolean8) << 7); Можно и без явных преобразований типов, по идее - навскидку не помню, что там стандарт по этому поводу говорит.
Большое спасибо. Работает как надо!!! Зря не пошел я на програмиста учиться а гайки стал крутить. Пол дня гуглил, как это сделать!!! А тут всего: назвал переменную и по битам, сдвигаясь, из других переменных её заполнил. Шайтанама! Спасибо.
IMHO. Наверное, вместо 8 логических переменных можно использовать битовое поле. Тогда, вместо преобразования, потребуется только приведение к uint8_t.
Еще не владею знаниями, чтобы понять это. Переменные меняются в основном цикле программы. Хочу управлять 8 реле 3 контактами. Вариант выше работает.
Код (C++): #pragma pack(push,1) struct { bool Flag0 : 1; bool Flag1 : 1; bool Flag2 : 1; bool Flag3 : 1; bool Flag4 : 1; bool Flag5 : 1; bool Flag6 : 1; bool Flag7 : 1; } Flags; #pragma pack(pop) Flags.Flag7 = true; Flags.Flag5 = false; Flags.Flag2 = true; Flags.Flag1 = true; shiftOut(..., ..., ..., static_cast<uint8_t>(Flags)); вся структура занимает 1 байт и хранит 8 флагов. Подробности - в гугале, ключевые слова для поиска "Битовые поля С"
"Вариант выше" - просто ответ на ваш вопрос. Но, как правильно заметили - хранить булево состояние в 8 переменных - излишество, для этого в одном байте есть целых 8 бит. Использование битовых полей - один из вариантов, ещё вариант - просто битовыми масками сбрасывать/устанавливать нужный бит. Вариант с битовыми полями существенно выигрывает в читабельности кода, что в дальнейшем, в случае серьёзного проекта - скажется только положительно. В век, когда компиляторы и оптимизаторы уже умеют делать оптимизацию лучше, чем среднестатистический программист - грех этим не пользоваться, в угоду читаемости кода. Пмсм, конечно.
Деда, небольшие правки: 1. Забыл префикс Flags. при обращении к полям структуры; 2. Структура не обязана иметь размер в один байт, это специфика компилятора и target, под который компилируем. Поэтому лучше указывать выравнивание по границе байта директивой #pragma pack
А интересно, можно ли Flags обнулять одной командой? Типа (uint8_t)(Flags) = 0; Низя? Или надоть union делать?
Дед, так просто она не преобразуется. Через задницу можно, но я бы union делал. А "через задницу" - это примерно вот так Спойлер: Через задницу Код (C++): #include <Printing.h> #pragma pack(1) struct { bool Flag0 : 1; bool Flag1 : 1; bool Flag2 : 1; bool Flag3 : 1; bool Flag4 : 1; bool Flag5 : 1; bool Flag6 : 1; bool Flag7 : 1; } Flags; void setup(void) { Serial.begin(115200); Flags.Flag7 = true; Serial << "Flags=" << * (uint8_t *) & Flags << "\r\n"; * (uint8_t *) & Flags = 0; Serial << "Flags=" << * (uint8_t *) & Flags << "\r\n"; } void loop(void) {} Я тут подумал, и всплыло, что я то исходил, что структура железобетонная. Если её можно немного поменять, то присваивание перестанет быть проблемой. Вот Спойлер: Изменённая структура Код (C++): #include <Printing.h> #pragma pack(1) struct { uint8_t operator = (const uint8_t n) { return * (uint8_t *) this = n; } bool Flag0 : 1; bool Flag1 : 1; bool Flag2 : 1; bool Flag3 : 1; bool Flag4 : 1; bool Flag5 : 1; bool Flag6 : 1; bool Flag7 : 1; } Flags; void setup(void) { Serial.begin(115200); Flags.Flag7 = true; Serial << "Flags=" << * (uint8_t *) & Flags << "\r\n"; Flags = 0; Serial << "Flags=" << * (uint8_t *) & Flags << "\r\n"; } void loop(void) {}