Как хранить массив бит анимации

Здравствуйте.
Имею 20 светодиодов WS2812B.
Нужно покадрово их включать.
Пример
image

Можно создать многомерный массив и хранить в нем 1 и 0 (20 светодиодов, 6 кадров, 120 байт, можно занести в PROGMEM, но я так не хочу).

Переменная типа uint32_t весит 4 байта, то есть 32 бита.
120/32 = 3,75 переменных типа uint32_t , то есть 4 переменных uint32_t .

В Excel я соединила все строки в одну и разделила их по 32 бита, соответственно получила 4 переменных.

const uint32_t cadr[5] = {
  0b11000000000000001001100000000001,
  0b00000011000000000000000001100000,
  0b00000000000011000000000000000000,
  0b00000000000000000000000000000001,
  0b00000000000000000000000000000001
};

Теперь на каждый кадр мне нужно получить по 20 значений 0 и 1.
То есть:
1 кадр - это 0 элемент массива, биты с 0 по 19 (20 бит)
2 кадр - это 0 элемент массива, биты с 20 по 32 (12 бит) и 1 элемент массива, биты с 0 по 19 (оставшиеся 20 бит)
и так далее

Вот примерно так получилось объяснить.
Как мне это реализовать?

Возьмите просто на каждый кадр по uint32_t.
Потом просто первые (или последние) 20 бит перебираете в цикле и соответственно в массиве фастледа, к примеру, выставляете черный или карминный цвет.

А с вашим компактным способом только пальцы изобъете об клавиатуру. 6 кадров того не стоят.

А так… Можете функцию написать, можете класс, который делает что-то типа:

uint8_t ledNo = …;
arrayIdx = ledNo / 32;
bitIdx = ledNo - (arrayIdx * 32);

Можно так попробовать
Установка бита в 1 в массиве

uint32_t mass[4] = {0, 0, 0, 0};

void write1_mass(uint32_t *massiv, uint16_t index, byte bitNumber)
 {
  *(massiv + index) |= (1UL << bitNumber);
 }

Запись в бит нуля , и чтение - аналогично

P.S. Пример. Устанавливаем по очереди биты начиная с 0 элемента массива

Спойлер
uint32_t mass[4] = {0, 0, 0, 0};

void write1_mass(uint32_t *massiv, uint16_t index, byte bitNumber)
 {
  *(massiv + index) |= (1UL << bitNumber);
 }


void setup() {
 Serial.begin(9600);
}

void loop() {
  static uint16_t ind = 0;
  static byte bitN = 0;
 
 write1_mass(mass, ind, bitN);

 for(byte ii = 0; ii < 4; ii++)
 {
  Serial.print(mass[ii], BIN);
  Serial.print(' ');
 }
 Serial.println();
 bitN++;
 if(bitN > 19)
 {
  bitN = 0;
  ind++;
 }
 if(ind > 3)
 for(;;);
}

Спойлер

Еще вариант - двумерный массив Anima[kadr][3] на каждый кадр 3 байта. Номер байта в кадре находится по формуле (Nled / 8) номер бита (Nled % 8) далее битовые операции.

@ЕвгенийП как то выкладывал софт для оперирования битами в любом количестве.

Кадров будет много.

*(massiv + index) |= (1UL << bitNumber);

Что значит 1UL ?

Найти бы)

1 Unsigned Long

Это чтобы компилятор приведение типа не сделал.

:slight_smile:
Есть же нормальные, текстовые функции:
bitRead() и bitWrite()
https://www.joyta.ru/10813-arduino-funkcii-bity-i-bajty/
… а не эти богомерзкие >> и << . Кстати они означают на самом деле “много больше” и “много меньше” Т.е. 1000>>1 и 1<<1000.

Это только в математике, а не в программировании.

Кстати, в этом примере, на мой взгляд это лишнее…

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

Там, кстати, за это время протухла ссылка на Printing, сейчас она вот здесь живёт.

1 лайк

Что-то я не совсем понимаю - как красиво заинитить этот булев массив сразу при создании?

С простым всё понятно uintXX_t arr[3] = { 1, 0 , 1 } , а тут как?

Добавить конструктор с тем параметрами, какие нужны и инициализировать в конструкторе.

Если bitNumber больше 15 - не лишнее

1 лайк

Ну да, ну да))

Arduino.h

#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))

в моём примере bitSet()

Хотите верьте - только сейчас глянул.

#include "BoolArray.h"

static const int8_t totalBools = 120;
static CBoolArray<totalBools> booleanArray;

void setup() {
  Serial.begin(9600);
}

void loop() {
}

Я создала переменную 120 бит.
А как мне их сразу забить 1 и 0 ?
А во Flash память можно сохранить будет?

это отсюда?

Если непонятна подобная запись

Спойлер
uint32_t mass[4] = {0, 0, 0, 0};

void write_mass(uint32_t *massiv, uint16_t index, byte bitNumber, bool Bit)
 {
   bitWrite( *(massiv + index), bitNumber, Bit);//упрощаем по заветам Lilik'a
 }


void setup() {
 Serial.begin(9600);
}

void loop() {
  static uint16_t ind = 0;
  static byte bitN = 0;
  bool BIT;
  bitN % 2 ? BIT = true : BIT = false;//определяем чётные и нечётные биты
  
 write_mass(mass, ind, bitN, BIT);

 for(byte ii = 0; ii < 4; ii++)
 {
  Serial.print(mass[ii], BIN);
  Serial.print(' ');
 }
 Serial.println();
 bitN++;
 if(bitN > 19)
 {
  bitN = 0;
  ind++;
 }
 if(ind > 3)
 for(;;);
}
Спойлер

1 лайк

Нулями они уже забиты. Для единиц нужен конструктор, я уже писал @sadman41

В том виде, как сейчас сделано - нет. Если нужно, то всё можно, конечно.