Возможно ли библиотеку GyverButton подружить со сдвиговым регистром?

derungebundener

✩✩✩✩✩✩✩
18 Июл 2020
117
3
@Старик Похабыч, Спасибо, сегодня проверю и отпишусь.
У меня, кстати, появилась мысль использовать shift.read вместо update - выше где-то писал проэ то.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,192
1,281
Москва
Надо читать описание функций в библиотеке.
По сути shift.state() выдает состояние указанного бита. 0 или 1,а update кроме чтения просто говорит нам были ли изменения. Поэтому работать должно. Но повторюсь, конструкция с if логически более верная и позволяет избежать лишних действий.
 

derungebundener

✩✩✩✩✩✩✩
18 Июл 2020
117
3
@Старик Похабыч,

Залез сейчас в код самой библиотеки, а там какой-то умный черт (автор) задержку через delay сделал...

C++:
ShiftType read() {
        lastState = currentState;
        ShiftType result = 0;

        digitalWrite(clockEnablePin, HIGH);
        digitalWrite(ploadPin, LOW);
        delayMicroseconds(pulseWidth);
        digitalWrite(ploadPin, HIGH);
        digitalWrite(clockEnablePin, LOW);

        for(uint16_t i = 0; i < dataWidth; i++) {
            ShiftType value = digitalRead(dataPin);
            result |= (value << ((dataWidth-1) - i));
            digitalWrite(clockPin, HIGH);
            delayMicroseconds(pulseWidth);
            digitalWrite(clockPin, LOW);
        }
        currentState = result;
        return result;
    }
А я ещё себя дурнинушкой считал...
 

kDn

★★★★★✩✩
18 Ноя 2019
1,103
437
Залез сейчас в код самой библиотеки, а там какой-то умный черт (автор) задержку через delay сделал...
И что не так там? Это формирование импульса нужной длины, счет идет на микросекунды, вы эту задержку врядли когда-то ощутите.
 

derungebundener

✩✩✩✩✩✩✩
18 Июл 2020
117
3
@kDn,Delay же зло...
Ну не знаю, 5мс возможо и правда не замечу.

Кстати, update оказывается включает в себя read:

C++:
// same as read, but it returns whether something has changed or not
    boolean update() {
        return read() != lastState;
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,192
1,281
Москва
Там задержка delayMicroseconds, что в тысячу раз меньше чем delay. И да, иногда ее приходиться использовать. Это нормально. Значение pulseWidth может быть 1-2-5. Что будет в 1000, 500 , 200 раз меньше чем delay(1) , так что там все хорошо.
 

bort707

★★★★★★✩
21 Сен 2020
2,898
862
Кстати, update оказывается включает в себя read:
удивительно, правда?:)
В программировании ноль я.
да уж...
Возьмите себе за правило - если не понимаете чужого кода - не лезьте исправлять. Много нервов сэкономите
 

bort707

★★★★★★✩
21 Сен 2020
2,898
862
Но посмотреть как делают можно!
Даже нужно. Но важен настрой. Если новичок видит в библиотечном коде "ошибку" - стоит всегда исходить из того, что это не автор слошил, а новичок что-то не понял в силу своей дремучести.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,192
1,281
Москва
Смотреть полезно, но иногда вредно. Вот сейчас был конкретный пример. С самого начала лучше смотреть на библиотеки как на черный ящик - работает, не трогай. Если смотреть на этом этапе , то можно запутаться. Как только начинаешь понимать что к чему, как куда и за что - можно и смотреть, и учиться, но при этом надо как действовала автор. А уж когда все это будет просто , то можно и изменения вносить.
 

kostyamat

★★★★★★✩
29 Окт 2019
1,097
630
@Старик Похабыч, я учился на примерах, да и сейчас учусь. Вот не лезут мне в голову умные многословия из статей и книжек, а на живой код смотришь и начинаешь вникать. Так вот, я только что себя словил на том, что все мои проекты в базе имели либо примеры из библиотек, либо чужие наработки, либо мои же, из тестовых. Вот прямо с нуля только пару десятков коротеньких скетчей, для теста каких либо функций, писал.

Возможно новичкам стоит именно так и делать, имхо. Не, ну параллельно книжки читать тоже нужно, конечно.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,192
1,281
Москва
@kostyamat,Примеры это всегда хорошо. Элементарные примеры идут практически ко всем библиотекам. Но сами библиотеки несколько сложнее, чем примеры.И примеры часто идут исключительно в виде примеров, не приспособленных для использования совместно с чем либо другим.
 

derungebundener

✩✩✩✩✩✩✩
18 Июл 2020
117
3
@Старик Похабыч,Хотел ещё спросить у вас совета. Дабы не плодить лишние темы, пишу тут. Вопрос такой:

Раздобыл библиотеку BlinkControl: https://github.com/mickey9801/BlinkControl
Ею можно легко управлять миганием светодиодов, при помощи паттернов - мигнуть один раз, мигнуть два раза и т.д.

Паттерны назначаются при помощи массива - 8 int по 2 байта каждый итого 16 байт на один паттерн.
Работает по такому принципу - длительность (миллисекунд) включения, длительность мс выключения, снова длительность включения и т.д.

Вот пример кода из библиотечного примера:

C++:
#include <BlinkControl.h>

BlinkControl led(15);

bool btnState = true;
unsigned long lastPressedAt = 0;

void setup() {
  pinMode(12, INPUT);
 
  led.begin();

  int timing[] = {500,1000,60,1000,500,1000,60,1000};
  led.blink(timing, sizeof(timing)/sizeof(int));
}

void loop() {
  led.loop();

  if (btnState) led.resume();
  else led.pause();

  if (digitalRead(12) == HIGH && millis()-lastPressedAt >= 1000) {
    lastPressedAt = millis();
    btnState = !btnState;
  }
}
К примеру, если у нас есть 2 светодиода и каждому надо по пять паттернов, то это уже 2*5*16= 160 байт, что очень много.

Я задался вопросом:

Можно ли, к примеру, объявить пару-тройку констант с длительностями:
const intA = 250
const intB = 500
const intC = 1000

А потом эти константы скормить массиву в виде указателей:

int timing[] = { &intA, &B, &C };

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

Можете что-то подсказать по этому поводу, если не затруднит?
 

kDn

★★★★★✩✩
18 Ноя 2019
1,103
437
Можете что-то подсказать по этому поводу, если не затруднит?
Конечно можно - поглядеть сколько памяти расходует указатель можно через:
C++:
sizeof(int *)
По сути задачи - имеет смысл ограничить длительность в паттернах одним байтом, чтобы было от 0 до 255, затем домножать на 100 и получить от 0 до 25500 с шагом 100мс, что будет достаточно. Правда для этого нужно будет исправить вашу библиотеку.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,192
1,281
Москва
Вот эта строка показывает что не нужно именно 8 значений:
led.blink(timing, sizeof(timing)/sizeof(int));
Нужно четное число. Мигание собой представляет включение и выключение. Соттв. череда разных миганий и получается четной.
Теперь пояснение строки
timing - массив задержек
sizeof(timing)/sizeof(int) -размер этого массива.
Если я хочу что бы светодиод коротко вспыхивал каждые пол секунды мне не надо 8 задержек. Можно сделать так:
C++:
int timing[] = {50,450};
led.blink(timing, 2);
если я хочу сделать длинное мигание и потом короткое, то будет так:
C++:
int timing[] = {500,100,50,250};
led.blink(timing, 4);
led.blink можно вызывать по хожу программы и менять стили мигания. Ну я так думаю. Это было бы логично.
Скармливание констант массиву может не иметь особого смысла. Если не хватает оперативной памяти посмотреть можно ли их разместить в памяти программы (progmem)
 

derungebundener

✩✩✩✩✩✩✩
18 Июл 2020
117
3
@kDn,
А если вот так перемножать на 100, то не будет ли однобайтовая изначальная величина весить больше, т.к. результат более одного байта?

@Старик Похабыч, Да, вы правы - все 8 не надо. Я просто немного неверно выразился:
8 int - это максимальный размер массива.

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


@Старик Похабыч, Вы вчера предлагали проверить иной вариант кода со сдвиговым регистром. Дошли руки только сейчас, извиняюсь за подзний ответ. В общем, сделал вот так и оно вроде как работает на первый взгляд:

C++:
#include <ShiftIn.h>
#include <EncButton.h>

// Init ShiftIn instance with a single chip
ShiftIn<1> shift;

EncButton<EB_TICK, VIRT_BTN> enc;
EncButton<EB_TICK, VIRT_BTN> enc2;
EncButton<EB_TICK, VIRT_BTN> enc3;
int counter = 0;
boolean btn3;

void setup() {
  Serial.begin(9600);
  enc.setHoldTimeout(500);
  // declare pins: pLoadPin, clockEnablePin, dataPin, clockPin
  shift.begin(2, 3, 4, 5);

  pinMode(13, OUTPUT);

  Serial.println("Alles ist bereit");
}



void loop()
{
  shift.read(); 
  enc.tick(shift.state(0));
  enc2.tick(shift.state(1));



  if ((shift.state(0) == 0 && (shift.state(1)) == 0))
  {
    btn3 = true;
  }
  else
  {
    btn3 = false;
  }
  enc3.tick(btn3);

  if (enc3.isHold())
    digitalWrite (13, 1);
  else
    digitalWrite (13, 0);


  if (enc.isClick())
  {
    counter++ ;
    Serial.println(counter);
  }

  if (enc2.isClick())
  {
    counter--;
    Serial.println(counter);
  }
}
Для пробы сделал оба вариант - один read другой update - оба работают!
Но, как меня уже переубедили - я все же оставлю тики кнопок внутри условия if update - так вроде и правда выходит правильнее и разгружает вычисления.

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

Большое спасибо за помощь в этом вопросе :)
 
Изменено:

Старик Похабыч

★★★★★★★
14 Авг 2019
4,192
1,281
Москва
Надо понимать, что указатель это то же переменная и то же тратит память.
Если int (а лучше привыкать писать int16_t или uint16_t - это универсальное определение, т.к. int в разных средах может быть размером от 2 до 8 байт) в ардуино занимает 2 байта, то указатель на любую переменную
 

kDn

★★★★★✩✩
18 Ноя 2019
1,103
437
@kDn,
А если вот так перемножать на 100, то не будет ли однобайтовая изначальная величина весить больше, т.к. результат более одного байта?
Темы для изучения:
  • PROGMEM
  • приведение типов
  • переменные на стеке
Я вам уже сказал как оптимизировать массивы, соглашусь с @Старик Похабыч , что их нужно выносить в память программы и читать оттуда.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,192
1,281
Москва
Да, еще вот такой момент. Для упрощения жизни в библиотеке хранятся данные об интервалах в миллисекундах. Но согласитесь, если сделать свечение светодиодом {10,10} то это уже будет ШИМ и светодиод будет гореть в пол яркости. Если это не нужно, то можно модифицировать библиотеку под себя: поменять тип данных с int на byte, значение хранить в десятых долях секунды. При проверке внутри библиотеки, умножать значение на 100. Это даст сокращение занимаемой памяти в 2 раза и упрощение обращения к PROGMEM, т.к. byte читается одинаково ото всюду (но это надо проверить, вроде бы да).
У меня тоже была подобная задача, правда мне не надо было выполнять мигание параллельно процессу, мне надо было при включении сигнализировать о разного вида сбоях путем мигания. Я сделал для себя так: 1) определил 4 типа мигания а) короткое б) длинно в) плавное зажигание г) плавное затухание. 2 ) Просто вызывал функции с разным миганием в нужном мне порядке. Это была аттини85, где памяти кот наплакал.
 

kDn

★★★★★✩✩
18 Ноя 2019
1,103
437
У меня тоже была подобная задача, правда мне не надо было выполнять мигание параллельно процессу,
Если потребуется асинхронный вариант с PWM под FreeRTOS ESP32, то у меня в проекте ESP32CAM такой есть, доработанная реализация от Морозова:

Мигалка живёт отдельным таском и ничему не мешает, включать/выключать/перенастраивать можно когда угодно.