├── .gitignore ├── LICENSE ├── README.RU.md ├── README.md ├── examples ├── CascadedDevices │ └── CascadedDevices.ino ├── CascadedInvert │ └── CascadedInvert.ino ├── CombineCascades │ └── CombineCascades.ino ├── HelloHabr │ └── HelloHabr.ino ├── Inverse │ └── Inverse.ino ├── Inverse2 │ └── Inverse2.ino ├── Matrix │ └── Matrix.ino ├── MultiShift │ └── MultiShift.ino ├── MultiShift2 │ └── MultiShift2.ino ├── MultiShiftHwSPI │ └── MultiShiftHwSPI.ino ├── RandomMove │ ├── RandomMove.ino │ └── randomMovement.h ├── RandomMove1 │ ├── RandomMove1.ino │ └── randomMovement.h ├── SingleShift │ └── SingleShift.ino ├── SingleShiftHwSPI │ └── SingleShiftHwSPI.ino └── TestRotation │ └── TestRotation.ino ├── keywords.txt ├── library.properties └── src ├── BitInt.h ├── BitIntMember.h ├── CoreMax72xx.cpp ├── CoreMax72xx.h ├── DirectInteract.h ├── DirectPin.h ├── LedMatrix.cpp ├── LedMatrix.h ├── MatrixCascade.h ├── RowCol.h ├── RowColIterator.h ├── Traits.h ├── initializer_list.h └── move.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.txt 2 | extras/* 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2016 Valeriy V Dmitriev aka Valmat 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.RU.md: -------------------------------------------------------------------------------- 1 | # LedMatrix 2 | 3 | **LedMatrix** -- это гибкая и мощная Arduino-*C++11* библиотека для управления светодиодными матрицами на чипах MAX7219 и MAX7221. 4 | 5 | - [Основные особенности](#Основные-особенности) 6 | - [Работа с одиночной матрицей](#Работа-с-одиночной-матрицей) 7 | - [Основные методы](#Основные-методы) 8 | - [Поворот матриц](#Поворот-матриц) 9 | - [Сеттеры](#Сеттеры) 10 | - [Геттеры](#Геттеры) 11 | - [Инверсия](#Инверсия) 12 | - [Сдвиг](#Сдвиг) 13 | - [Синтаксический сахар](#Синтаксический-сахар) 14 | - [Каскады матриц](#Каскады-матриц) 15 | - [Основные методы MatrixCascade](#Основные-методы-matrixcascade) 16 | - [Суперкаскады](#Суперкаскады) 17 | - [Дополнительно](#Дополнительно) 18 | 19 | 20 | ## Основные особенности 21 | С помощью библиотеки **LedMatrix** вы можете гибко управлять светодиодными матрицами подключенными с помощью чипов **MAX7219** и **MAX7221**. А так же каскадами таких матриц. И целыми группами каскадов. 22 | Она может работать как через программный SPI, используя для подключения любые три свободные пина, так и через аппаратный интерфейс SPI. 23 | Аппаратный SPI, естественно быстрее. 24 | 25 | Теперь по порядку. 26 | 27 | ## Работа с одиночной матрицей 28 | Прежде всего, необходимо подключить заголовочный файл: `#include `. 29 | Далее, как это принято в программах для Ардуино, необходимо создать глобальный объект: 30 | 31 | ```c 32 | #include "LedMatrix.h" 33 | // pin 11 is connected to the DataIn 34 | // pin 13 is connected to the CLK 35 | // pin 10 is connected to LOAD (cs) 36 | // Software-SPI 37 | LedMatrix matrix(11, 13, 10); 38 | ``` 39 | или так: 40 | ```c 41 | #include "LedMatrix.h" 42 | //Hardware-SPI 43 | LedMatrix matrix(10); 44 | ``` 45 | Теперь с матрицей можно работать. 46 | 47 | Предусмотрено два конструктора. 48 | 49 | Один конструктор создает матрицу, работающую через программный интерфейс SPI: 50 | ```c 51 | // Software-SPI Constructor 52 | // @param dataPin pin on the Arduino where data gets shifted out (DIN) 53 | // @param clockPin pin for the clock (CLK) 54 | // @param csPin pin for selecting the device (CS - chip select pin) 55 | LedMatrix(uint8_t data, uint8_t clk, uint8_t cs); 56 | ``` 57 | другой через аппаратный: 58 | ```c 59 | // HardWare-SPI Constructor 60 | // @param csPin pin for selecting the device (CS -- chip select pin) 61 | LedMatrix(uint8_t cs); 62 | ``` 63 | Выбор используемого интерфейса SPI зависит от вызванного конструктора. 64 | 65 | ### Основные методы 66 | 67 | Перечислю доступные методы. 68 | 69 | ```c 70 | // Set the shutdown (power saving) mode for the device 71 | void shutdown() const; 72 | ``` 73 | Метод `shutdown()` отключает питание матрицы, в целях энергосбережения. По умолчанию, при старте, питание матрицы включено. 74 | 75 | ```c 76 | // Set the wakeup mode for the device 77 | void wakeup() const; 78 | ``` 79 | Метод `wakeup()` включает питание матрицы, если оно было ранее выключено. 80 | 81 | 82 | ```c 83 | // Set the brightness of the display. 84 | // @param intensity the brightness of the display. (0..15) 85 | void setIntensity(uint8_t intensity) const; 86 | ``` 87 | Метод `setIntensity()` устанавливает яркость светодиодов. Возможные значения от 0 до 15. 88 | 89 | 90 | ```c 91 | // Switch all LEDs on the display to off. 92 | void clear(); 93 | ``` 94 | Метод `clear()` "очищает" экран, выключая все точки матрицы. 95 | 96 | 97 | ```c 98 | // Switch all LEDs on the display to on. 99 | void fill(); 100 | ``` 101 | Метод `fill()` "заполняет" экран, включая все точки матрицы. 102 | 103 | ### Поворот матриц 104 | 105 | Как я уже говорил, матрицы могут быть объединены в каскад. Я считаю, что при их объединении в каскад нужно исходить в первую очередь из удобства монтажа. В этом случае, некоторые матрицы могут оказаться повернутыми или даже перевернутыми. На этот случай, я добавил возможность программного поворота матриц. 106 | 107 | Следующие методы реализуют эту возможность: 108 | 109 | ```c 110 | // Set how many times to rotate the matrix clockwise 111 | // @param From 0 to 3 112 | void setRotation(uint8_t times = 1); 113 | 114 | // Reset rotation flag to default 115 | void resetRotation(); 116 | 117 | // Get how many times the matrix was rotated clockwise 118 | uint8_t getRotation() const; 119 | ``` 120 | 121 | Узнать, какой индекс имеет матрица в каскаде поможет следующий метод: 122 | ```c 123 | // get device index in cascade 124 | uint16_t index() const; 125 | ``` 126 | 127 | ### Сеттеры 128 | 129 | Теперь о том как "заполнять" матрицы. 130 | 131 | Для заполнения матрицы доступны следующие методы: 132 | 133 | ```c 134 | // Set the status of a single LED. 135 | // @param Row row the row of the Led (0..7) 136 | // @param Col col the column of the Led (0..7) 137 | // @param state If true the led is switched on, if false it is switched off 138 | void set(const Row &row, const Col &col, bool state); 139 | 140 | // Turn on LED at a point 141 | // @param Row row the row of the Led (0..7) 142 | // @param Col col the column of the Led (0..7) 143 | void on(const Row &row, const Col &col); 144 | 145 | // Turn off LED at a point 146 | // @param Row row the row of the Led (0..7) 147 | // @param Col col the column of the Led (0..7) 148 | void off(const Row &row, const Col &col); 149 | 150 | // Set all LEDs in a row to a new state 151 | // @param row which is to be set (0..7) 152 | // @param value each bit set to 1 will light up the corresponding LED. 153 | void set(const Row &row, buint8_t value); 154 | 155 | // Set all LEDs in a column to a new state 156 | // @param col -- column which is to be set (0..7) 157 | // @param value -- each bit set to 1 will light up the corresponding LED. 158 | void set(const Col &col, buint8_t value); 159 | 160 | // Set all LEDs in a row to a new state 161 | // @param row which is to be set (0..7) 162 | // @param value each bit set to 1 will light up the corresponding LED. 163 | void setRow(const Row &row, buint8_t value); 164 | 165 | // Set all LEDs in a column to a new state 166 | // @param col -- column which is to be set (0..7) 167 | // @param value -- each bit set to 1 will light up the corresponding LED. 168 | void setCol(const Col &col, buint8_t value); 169 | 170 | // Allows to initialize the values of all points of the matrix 171 | // @param initializer_list instance 172 | template 173 | void set(const std::initializer_list &disp); 174 | 175 | // Allows to initialize the values of all points of the matrix 176 | // Attention. If you pass an array to this function, strictly follow its length 177 | // @param raw array 178 | void set(const uint8_t arr[]); 179 | ``` 180 | 181 | В списках аргументов вы можете видеть здесь типы `Row`, `Col` и `buint8_t`. 182 | Не пугайтесь. Они были введены для удобства. Чем они могут быть вам полезны я напишу ниже. 183 | А пока вам достаточно знать, что эти типы автоматически преобразуются в числа типа `uint8_t` и обратно. 184 | По сути, эти типы и есть `uint8_t` + немного сахара. 185 | 186 | То есть такая запись: 187 | ```c 188 | matrix.on(3, 5); 189 | ``` 190 | абсолютно корректна. 191 | 192 | Расписывать назначения всех сеттеров не буду, поскольку их называния и прототипы говорят сами за себя. 193 | Подробно остановлюсь на двух. 194 | 195 | ```c 196 | template 197 | void set(const std::initializer_list &disp); 198 | ``` 199 | Этот метод позволяет вам заполнить матрицу на месте. Прямо во время компиляции, не создавая промежуточных массивов или чего то еще. 200 | Вот пример использования: 201 | ```c 202 | matrix.set({0b00000000, 0b01100110, 0b10011001, 0b10000001, 0b01000010, 0b00100100, 0b00011000, 0b00000000}); 203 | ``` 204 | 205 | Метод `void set(const uint8_t arr[])` позволяет заполнить матрицу предварительно созданным массивом: 206 | ```c 207 | uint8_t arr[8] = {0b00000000, 0b00100000, 0b00000000, 0b01100000, 0b00100000, 0b00100000, 0b00100000, 0b01110000}; 208 | matrix.set(arr); 209 | ``` 210 | ### Геттеры 211 | 212 | Для извлечения информации из матрицы предназначена следующая группа методов: 213 | 214 | ```c 215 | // Get state of LED point on matrix 216 | // @param row the row of the Led (0..7) 217 | // @param col the column of the Led (0..7) 218 | bool get(const Row &row, const Col &col) const; 219 | 220 | // Get the values on row of LED-matrix 221 | // @param row the row of the Led (0..7) 222 | buint8_t get(const Row &row) const; 223 | 224 | // Get the values on colomn of LED-matrix 225 | // @param col the column of the Led (0..7) 226 | buint8_t get(const Col &col) const; 227 | 228 | // Get the values on row of LED-matrix 229 | // @param row the row of the Led (0..7) 230 | buint8_t getRow(const Row &row) const; 231 | 232 | // Get the values on colomn of LED-matrix 233 | // @param col the column of the Led (0..7) 234 | buint8_t getCol(const Col &col) const; 235 | ``` 236 | Я думаю, дополнительные комментарии не нужны. 237 | 238 | ### Инверсия 239 | 240 | Точки матрицы, а так же отдельные строки и столбцы можно инвертировать. Для этого предназначены следующие методы: 241 | 242 | ```c 243 | // Invert all points of matrix 244 | void invert(); 245 | 246 | // Invert current point on matrix 247 | // @param row the row of the LED (0..7) 248 | // @param col the column of the LED (0..7) 249 | void invert(const Row &row, const Col &col); 250 | 251 | // Invert row on matrix 252 | // @param row the row of the LED (0..7) 253 | void invert(const Row &row); 254 | 255 | // Invert colomn on matrix 256 | // @param col the column of the LED (0..7) 257 | void invert(const Col &col); 258 | 259 | // Invert row on matrix 260 | // @param row the row of the LED (0..7) 261 | void invertRow(const Row &row); 262 | 263 | // Invert colomn on matrix 264 | // @param col the column of the LED (0..7) 265 | void invertCol(const Col &col); 266 | ``` 267 | ### Сдвиг 268 | 269 | ```c 270 | // Shift matrix 271 | // @param value is shifting value 272 | // @return shifted value 273 | buint8_t shiftUp(buint8_t value = 0); 274 | buint8_t shiftDown(buint8_t value = 0); 275 | buint8_t shiftLeft(buint8_t value = 0); 276 | buint8_t shiftRight(buint8_t value = 0); 277 | ``` 278 | Эти методы сдвигают матрицу в ту или иную сторону. Возвращаемым значением является вымещенная строка или столбец. В качестве аргумента можно передать значение замещаемой строки или столбца. 279 | 280 | ## Синтаксический сахар 281 | 282 | Пару слов о типах `Row`, `Col` и `buint8_t`. 283 | 284 | `Row`, `Col` объявлены в заголовочном файле `RowCol.h`. Оба эти типа могут быть использованы как числовые, но обладают дополнительными возможностями. 285 | 286 | Переменные `Row`, `Col` всегда в диапазоне 0..7. 287 | 288 | Они выполняют роль итератора и позволяют осуществить красивую перегрузку. 289 | То есть вместо неуклюжего кода 290 | ```c 291 | uint8_t foo(/*...*/) {/*...*/} 292 | 293 | for(uint8_t row = 0; row < 8; ++row) { 294 | matrix.setRow(row, foo(row)); 295 | } 296 | ``` 297 | 298 | можно написать лаконичный код: 299 | ```c 300 | uint8_t foo(/*...*/) {/*...*/} 301 | 302 | for(auto &row: matrix.rows()) { 303 | matrix.set(row, foo(row)); 304 | } 305 | ``` 306 | 307 | Для их использования предусмотрено два метода: 308 | ```c 309 | // Make rows and colomns iterable 310 | RowsIterator rows() const; 311 | ColsIterator cols() const; 312 | ``` 313 | которые возвращают итераторы для строк и столбцов, соответственно. 314 | 315 | 316 | Тип `buint8_t` определен в заголовочном файле `BitInt.h`. 317 | Его определение это просто специализация шаблонного класса `BitInt`: 318 | ```c 319 | // Types predefinition 320 | using buint8_t = BitInt; 321 | // ... 322 | ``` 323 | 324 | Он ведет себя как uint8_t, но позволяет легко получить доступ к своему бинарному представлению. 325 | ```c 326 | buint8_t x = 88; // 01011000 327 | x[2] = 1; // 01111000 328 | x[3] = false; // 01101000 329 | bool a = x[4]; // true 330 | bool a = x[7]; // false 331 | 332 | // Iteration: 333 | for(auto v: x) { 334 | Serial.print(v ? "{I}" : "{O}"); 335 | } 336 | ``` 337 | 338 | ## Каскады матриц 339 | 340 | Матрицы могут быть объеденены в каскад. 341 | Схема подключения вот такая: 342 | ``` 343 | -> VVC -> VVC -> 344 | -> GND -> GND -> 345 | -> DIN DOUT -> 346 | DOUT -> DIN 347 | -> CS -> CS -> 348 | -> CLK -> CLK -> 349 | ``` 350 | Как и одиночные матрицы, каскад матриц может управляться как с помощью программного интерфейса SPI, так и с помощью аппаратного. 351 | Точно так же, программный SPI позволяет использовать любые три свободные пина, аппаратный оставляет свободным только один пин (CS): 352 | ``` 353 | // Hardware-SPI wiring scheme: 354 | // CLK => SCLK (Arduino UNO/Nano/Mini pin 13) 355 | // DIN => MOSI (Arduino UNO/Nano/Mini pin 11) 356 | // CS => (Arduino any pin) 357 | ``` 358 | но аппаратный SPI заметно шустрее. 359 | 360 | Software-SPI: 361 | ```c 362 | #include 363 | 364 | // pin 11 is connected to the DataIn 365 | // pin 13 is connected to the CLK 366 | // pin 10 is connected to LOAD (cs) 367 | const uint8_t CascadeSize = 3; 368 | // Software-SPI 369 | MatrixCascade cascade(11, 13, 10); 370 | ``` 371 | Hardware-SPI: 372 | ```c 373 | #include 374 | 375 | // pin 11 is connected to the DataIn 376 | // pin 13 is connected to the CLK 377 | // pin 10 is connected to LOAD (cs) 378 | const uint8_t CascadeSize = 3; 379 | // HardWare-SPI 380 | MatrixCascade cascade(10); 381 | ``` 382 | Обратите внимание, класс `MatrixCascade` шаблонный. И вам нужно явно указать размер каскада (`MatrixCascade<3>`) на этапе компиляции. 383 | 384 | 385 | Что бы использовать каскады матриц и группы каскадов матриц, подключите заголовочный файл [MatrixCascade.h](src/MatrixCascade.h) 386 | 387 | ### Основные методы `MatrixCascade` 388 | 389 | Уже знакомые нам методы, которые в данном случае являются групповыми: 390 | 391 | ```c 392 | // Set the shutdown (power saving) mode for all devices 393 | void shutdown() const; 394 | 395 | // Set the wakeup mode for all devices 396 | void wakeup() const; 397 | 398 | // Set the brightness of all displays. 399 | // @param intensity the brightness of the display. (0..15) 400 | void setIntensity(uint8_t intensity) const; 401 | 402 | // Switch all LEDs on all displays to off. 403 | void clear(); 404 | 405 | // Switch all LEDs on all displays to on. 406 | void fill(); 407 | 408 | // Invert all points of all matrixes 409 | void invert(); 410 | 411 | // How many times to rotate all matrixes clockwise 412 | // @param From 0 to 3 413 | void setRotation(uint8_t times = 1); 414 | 415 | // Reset rotation flag for all matrixes to default 416 | void resetRotation(); 417 | ``` 418 | 419 | Метод позволяющий получить размер каскада: 420 | ```c 421 | // Returns the number of devices on this MatrixCascade 422 | constexpr uint16_t size() const; 423 | ``` 424 | 425 | Получение доступа к матрице по индексу: 426 | ```c 427 | LedMatrix& get(uint16_t index); 428 | ``` 429 | Класс `MatrixCascade` обладает свойствами массива. В частности доступ к содержащимся в нем матрицам можно получить через оператор `[]`: 430 | 431 | ```c 432 | cascade[0].setRotation(3); 433 | cascade[1].setRotation(1); 434 | ``` 435 | 436 | А так же `MatrixCascade` является итерируемым: 437 | ```c 438 | for(auto &matrix: cascade) { 439 | matrix.shiftUp(); 440 | } 441 | ``` 442 | ### Суперкаскады 443 | 444 | Каскады матриц можно, в свою очередь, объединять в суперкаскады. 445 | 446 | Суперкаскад от каскада отличается только способом конструирования объекта. На самом деле это все тот же `MatrixCascade`. 447 | 448 | Что бы создать суперкаскад, нужно использовать функцию `combineCascades()`. Пример: 449 | ```c 450 | auto cascade = combineCascades( 451 | MatrixCascade<5>(10), 452 | MatrixCascade<8>(12), 453 | MatrixCascade<7>(1, 2, 3), 454 | MatrixCascade<8>(4, 5, 6), 455 | MatrixCascade<8>(7, 8, 9), 456 | MatrixCascade<3>(14), 457 | MatrixCascade<6>(15), 458 | ); 459 | ``` 460 | Переменная `cascade` будет объектом типа `MatrixCascade<45>`. Соответственно она будет управлять 45-ю матрицами. Это позволяет снять ограничения *8* матриц на каскад, накладываемые чипами **MAX7219** и **MAX7221**. Фактическим ограничением является количество свободных пинов. 461 | 462 | ## Дополнительно 463 | Более подробную информацию можно получить в [исходном коде](src), который я постарался снабдить комментариями, и в [примерах](examples). 464 | 465 | --- 466 | Библиотека не реализует средств для печати текстовых строк на каскаде матриц. Это сделано специально. Поскольку матрицы могут быть смонтированы произвольным образом. И внесение в библиотеку кода предполагающего какой-то конкретный вид монтажа было бы нарушением целостности. Тем более написать надстроечную библиотеку с нужной функциональностью не составит труда. 467 | 468 | Пара примеров как сделать бегущую строку: [1](examples/MultiShift/MultiShift.ino), [2](examples/HelloHabr/HelloHabr.ino) 469 | 470 | --- 471 | Первоначально, библиотека была форком библиотеки [LedControl](https://github.com/wayoda/LedControl). 472 | Я полностью переработал исходную библиотеку. Целю было получить более гибкий интерфейс, оптимизировать читаемость кода и производительность. 473 | В настоящий момент от исходной библиотеки осталась всего пара строк, так что проект был вынесен в отдельный репозитарий. 474 | 475 | --- 476 | Не стесняйтесь сообщать об найденных ошибках и присылать свои предложения. 477 | 478 | Если вы хорошо знаете английский и в каком-то месте мой перевод показался вам корявым, feel free to report it. 479 | 480 | --- 481 | [Лицензия](LICENSE) 482 | 483 | 484 | [English version](README.md) 485 | 486 | 487 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LedMatrix 2 | **LedMatrix** is a flexible and powerful *Arduino C++11* library to control LED matrixes on chips MAX7219 and MAX7221. 3 | 4 | - [Main features](#main-features) 5 | - [Single matrix](#single-matrix) 6 | - [Basic methods](#basic-methods) 7 | - [Matrix rotation](#matrix-rotation) 8 | - [Setters](#setters) 9 | - [Getters](#getters) 10 | - [Inversion](#inversion) 11 | - [Shifting](#shifting) 12 | - [Syntactic sugar](#syntactic-sugar) 13 | - [Cascades of matrices](#cascades-of-matrices) 14 | - [Basic methods of MatrixCascade](#basic-methods-of-matrixcascade) 15 | - [Supercascades](#supercascades) 16 | - [Additionally](#additionally) 17 | 18 | 19 | ## Main features 20 | 21 | With the **LedMatrix** library, you can flexibly control LED matrixes are connected via chips **MAX7219** and **MAX7221**. As well as cascades of such matrices. And whole groups of cascades. 22 | It can work via software SPI, using any three free pins or through hardware SPI. 23 | Hardware SPI of course is faster. 24 | 25 | ## Single matrix 26 | First of all, you need to connect the header file: `#include `. 27 | Further, as is customary in the Arduino sketches, you need to create a global object: 28 | 29 | ```c 30 | #include "LedMatrix.h" 31 | // pin 11 is connected to the DataIn 32 | // pin 13 is connected to the CLK 33 | // pin 10 is connected to LOAD (cs) 34 | // Software-SPI 35 | LedMatrix matrix(11, 13, 10); 36 | ``` 37 | or so: 38 | ```c 39 | #include "LedMatrix.h" 40 | //Hardware-SPI 41 | LedMatrix matrix(10); 42 | ``` 43 | Now the matrix is ready to use. 44 | 45 | 46 | The library provides two constructors. 47 | 48 | One constructor creates a matrix that operates through software SPI: 49 | ```c 50 | // Software-SPI Constructor 51 | // @param dataPin pin on the Arduino where data gets shifted out (DIN) 52 | // @param clockPin pin for the clock (CLK) 53 | // @param csPin pin for selecting the device (CS - chip select pin) 54 | LedMatrix(uint8_t data, uint8_t clk, uint8_t cs); 55 | ``` 56 | 57 | The other creates by using hardware SPI: 58 | ```c 59 | // HardWare-SPI Constructor 60 | // @param csPin pin for selecting the device (CS -- chip select pin) 61 | LedMatrix(uint8_t cs); 62 | ``` 63 | The choice of the using SPI depends on the invoked constructor. 64 | 65 | ### Basic methods 66 | 67 | Below are the main methods: 68 | 69 | ```c 70 | // Set the shutdown (power saving) mode for the device 71 | void shutdown() const; 72 | ``` 73 | The method `shutdown()` turns off the power of the matrix, in order to save energy. By default, at startup, the matrix power is turned on. 74 | 75 | ```c 76 | // Set the wakeup mode for the device 77 | void wakeup() const; 78 | ``` 79 | The method `wakeup()` turns on the power of the matrix if it was previously turned off. 80 | 81 | ```c 82 | // Set the brightness of the display. 83 | // @param intensity the brightness of the display. (0..15) 84 | void setIntensity(uint8_t intensity) const; 85 | ``` 86 | The method `setIntensity()` sets the brightness of the LEDs. Possible values are from 0 to 15. 87 | 88 | 89 | ```c 90 | // Switch all LEDs on the display to off. 91 | void clear(); 92 | ``` 93 | The method `clear()` "cleans" the screen by turning off all points on the matrix. 94 | 95 | ```c 96 | // Switch all LEDs on the display to on. 97 | void fill(); 98 | ``` 99 | The method `fill()` "fills" the screen by turning on all points on the matrix. 100 | 101 | ### Matrix rotation 102 | 103 | As I said before, the matrix may be combined in a cascade. I believe that when they are combined in a cascade is necessary to proceed first and foremost from the ease of installation. In this case, some matrices may be rotated. For this, I added the ability to programmatically rotation matrices. 104 | 105 | The following methods implement this feature: 106 | 107 | ```c 108 | // Set how many times to rotate the matrix clockwise 109 | // @param From 0 to 3 110 | void setRotation(uint8_t times = 1); 111 | 112 | // Reset rotation flag to default 113 | void resetRotation(); 114 | 115 | // Get how many times the matrix was rotated clockwise 116 | uint8_t getRotation() const; 117 | ``` 118 | 119 | To know which index has the matrix in the cascade will help the following method: 120 | ```c 121 | // get device index in cascade 122 | uint16_t index() const; 123 | ``` 124 | 125 | ### Setters 126 | 127 | Now let's talk about how to "fill" matrixes. 128 | 129 | To fill a matrix, use the following methods: 130 | ```c 131 | // Set the status of a single LED. 132 | // @param Row row the row of the Led (0..7) 133 | // @param Col col the column of the Led (0..7) 134 | // @param state If true the led is switched on, if false it is switched off 135 | void set(const Row &row, const Col &col, bool state); 136 | 137 | // Turn on LED at a point 138 | // @param Row row the row of the Led (0..7) 139 | // @param Col col the column of the Led (0..7) 140 | void on(const Row &row, const Col &col); 141 | 142 | // Turn off LED at a point 143 | // @param Row row the row of the Led (0..7) 144 | // @param Col col the column of the Led (0..7) 145 | void off(const Row &row, const Col &col); 146 | 147 | // Set all LEDs in a row to a new state 148 | // @param row which is to be set (0..7) 149 | // @param value each bit set to 1 will light up the corresponding LED. 150 | void set(const Row &row, buint8_t value); 151 | 152 | // Set all LEDs in a column to a new state 153 | // @param col -- column which is to be set (0..7) 154 | // @param value -- each bit set to 1 will light up the corresponding LED. 155 | void set(const Col &col, buint8_t value); 156 | 157 | // Set all LEDs in a row to a new state 158 | // @param row which is to be set (0..7) 159 | // @param value each bit set to 1 will light up the corresponding LED. 160 | void setRow(const Row &row, buint8_t value); 161 | 162 | // Set all LEDs in a column to a new state 163 | // @param col -- column which is to be set (0..7) 164 | // @param value -- each bit set to 1 will light up the corresponding LED. 165 | void setCol(const Col &col, buint8_t value); 166 | 167 | // Allows to initialize the values of all points of the matrix 168 | // @param initializer_list instance 169 | template 170 | void set(const std::initializer_list &disp); 171 | 172 | // Allows to initialize the values of all points of the matrix 173 | // Attention. If you pass an array to this function, strictly follow its length 174 | // @param raw array 175 | void set(const uint8_t arr[]); 176 | ``` 177 | 178 | In the list of arguments you can see here the types `Row`, `Col` and `buint8_t`. 179 | Do not be alarmed. They were introduced for convenience. What they can do for you I will write [below](#syntactic-sugar). 180 | In the meantime, you need to know that these types are automatically converted to numbers such as `uint8_t` and back. 181 | In fact, these types are the `uint8_t` + a little sugar. 182 | Then the record `matrix.on(3, 5);` is absolutely correct. 183 | 184 | I will not describe use of all these setters, because their naming and prototypes speak for themselves. 185 | 186 | More focus on two. 187 | ```c 188 | template 189 | void set(const std::initializer_list &disp); 190 | ``` 191 | This method allows you to fill the matrix on place. Right at compile time, without creating intermediate arrays or anything else. 192 | 193 | Here is an example: 194 | ```c 195 | matrix.set({0b00000000, 196 | 0b01100110, 197 | 0b10011001, 198 | 0b10000001, 199 | 0b01000010, 200 | 0b00100100, 201 | 0b00011000, 202 | 0b00000000}); 203 | ``` 204 | 205 | The method 206 | ```c 207 | void set(const uint8_t arr[]) 208 | ``` 209 | allows to fill the matrix with a previously created array: 210 | ```c 211 | uint8_t arr[8] = {0b00000000, 212 | 0b00100000, 213 | 0b00000000, 214 | 0b01100000, 215 | 0b00100000, 216 | 0b00100000, 217 | 0b00100000, 218 | 0b01110000}; 219 | matrix.set(arr); 220 | ``` 221 | ### Getters 222 | 223 | The following group of methods is to retrieve information from the matrix: 224 | ```c 225 | // Get state of LED point on matrix 226 | // @param row the row of the Led (0..7) 227 | // @param col the column of the Led (0..7) 228 | bool get(const Row &row, const Col &col) const; 229 | 230 | // Get the values on row of LED-matrix 231 | // @param row the row of the Led (0..7) 232 | buint8_t get(const Row &row) const; 233 | 234 | // Get the values on colomn of LED-matrix 235 | // @param col the column of the Led (0..7) 236 | buint8_t get(const Col &col) const; 237 | 238 | // Get the values on row of LED-matrix 239 | // @param row the row of the Led (0..7) 240 | buint8_t getRow(const Row &row) const; 241 | 242 | // Get the values on colomn of LED-matrix 243 | // @param col the column of the Led (0..7) 244 | buint8_t getCol(const Col &col) const; 245 | ``` 246 | I think any additional comments are not needed. 247 | 248 | ### Inversion 249 | 250 | The points of the matrix, as well as individual rows and columns may be inverted. To do this, use the following methods: 251 | ```c 252 | // Invert all points of matrix 253 | void invert(); 254 | 255 | // Invert current point on matrix 256 | // @param row the row of the LED (0..7) 257 | // @param col the column of the LED (0..7) 258 | void invert(const Row &row, const Col &col); 259 | 260 | // Invert row on matrix 261 | // @param row the row of the LED (0..7) 262 | void invert(const Row &row); 263 | 264 | // Invert colomn on matrix 265 | // @param col the column of the LED (0..7) 266 | void invert(const Col &col); 267 | 268 | // Invert row on matrix 269 | // @param row the row of the LED (0..7) 270 | void invertRow(const Row &row); 271 | 272 | // Invert colomn on matrix 273 | // @param col the column of the LED (0..7) 274 | void invertCol(const Col &col); 275 | ``` 276 | ### Shifting 277 | 278 | ```c 279 | // Shift matrix 280 | // @param value is shifting value 281 | // @return shifted value 282 | buint8_t shiftUp(buint8_t value = 0); 283 | buint8_t shiftDown(buint8_t value = 0); 284 | buint8_t shiftLeft(buint8_t value = 0); 285 | buint8_t shiftRight(buint8_t value = 0); 286 | ``` 287 | These methods shift a matrix in one direction or another. 288 | The return value is an extracted row or column. 289 | As an argument you can pass the value of the replaced row or column. 290 | 291 | 292 | ## Syntactic sugar 293 | 294 | A few words about the types of `Row`, `Col` and `buint8_t`. 295 | 296 | `Row` and `Col` are declared in the header file [RowCol.h](src/RowCol.h). Both these types can be used as a numeric, but they have additional features. 297 | 298 | 299 | - The variables of `Row` and `Col` is always in the range 0..7. 300 | - They serve as an iterator and allow a nice overdrive. 301 | 302 | 303 | That is, instead of the awkward code: 304 | ```c 305 | uint8_t foo(/*...*/) {/*...*/} 306 | 307 | for(uint8_t row = 0; row < 8; ++row) { 308 | matrix.setRow(row, foo(row)); 309 | } 310 | ``` 311 | 312 | you can write concise code: 313 | ```c 314 | uint8_t foo(/*...*/) {/*...*/} 315 | 316 | for(auto &row: matrix.rows()) { 317 | matrix.set(row, foo(row)); 318 | } 319 | ``` 320 | There are two methods to get `Row` and `Col` 321 | ```c 322 | // Make rows and colomns iterable 323 | RowsIterator rows() const; 324 | ColsIterator cols() const; 325 | ``` 326 | These methods return iterators for the rows and columns, respectively. 327 | 328 | The type `buint8_t` is defined in the header file [BitInt.h](src/BitInt.h). 329 | Its definition is just a specialization of template class `BitInt`: 330 | ```c 331 | // Types predefinition 332 | using buint8_t = BitInt; 333 | // ... 334 | ``` 335 | 336 | It behaves as uint8_t, but allows you to easily access their binary representation. 337 | ```c 338 | buint8_t x = 88; // 01011000 339 | x[2] = 1; // 01111000 340 | x[3] = false; // 01101000 341 | bool a = x[4]; // true 342 | bool a = x[7]; // false 343 | 344 | // Iteration: 345 | for(auto v: x) { 346 | Serial.print(v ? "{I}" : "{O}"); 347 | } 348 | ``` 349 | ## Cascades of matrices 350 | Matrixes may be combined in a cascade. 351 | 352 | Wiring scheme like this: 353 | ``` 354 | -> VVC -> VVC -> 355 | -> GND -> GND -> 356 | -> DIN DOUT -> 357 | DOUT -> DIN 358 | -> CS -> CS -> 359 | -> CLK -> CLK -> 360 | ``` 361 | As a single matrix, the cascade matrix can be controlled by using software SPI and by hardware SPI. 362 | 363 | Like single matrix case, software SPI allows you to use any three free pins, the hardware SPI leaves only one free pin (CS): 364 | ``` 365 | // Hardware-SPI wiring scheme: 366 | // CLK => SCLK (Arduino UNO/Nano/Mini pin 13) 367 | // DIN => MOSI (Arduino UNO/Nano/Mini pin 11) 368 | // CS => (Arduino any pin) 369 | ``` 370 | but the hardware SPI is noticeably faster. 371 | 372 | Software-SPI: 373 | ```c 374 | #include 375 | 376 | // pin 11 is connected to the DataIn 377 | // pin 13 is connected to the CLK 378 | // pin 10 is connected to LOAD (cs) 379 | const uint8_t CascadeSize = 3; 380 | // Software-SPI 381 | MatrixCascade cascade(11, 13, 10); 382 | ``` 383 | Hardware-SPI: 384 | ```c 385 | #include 386 | 387 | // pin 11 is connected to the DataIn 388 | // pin 13 is connected to the CLK 389 | // pin 10 is connected to LOAD (cs) 390 | const uint8_t CascadeSize = 3; 391 | // HardWare-SPI 392 | MatrixCascade cascade(10); 393 | ``` 394 | Note, The class `MatrixCascade` is template. And you need to explicitly specify the size of the cascade (`MatrixCascade<3>`) at compile time. 395 | 396 | 397 | To use cascades of matrixes and groups of cascades include the header file [MatrixCascade.h](src/MatrixCascade.h) 398 | 399 | ### Basic methods of `MatrixCascade` 400 | 401 | The familiar methods, which in this case are the group: 402 | ```c 403 | // Set the shutdown (power saving) mode for all devices 404 | void shutdown() const; 405 | 406 | // Set the wakeup mode for all devices 407 | void wakeup() const; 408 | 409 | // Set the brightness of all displays. 410 | // @param intensity the brightness of the display. (0..15) 411 | void setIntensity(uint8_t intensity) const; 412 | 413 | // Switch all LEDs on all displays to off. 414 | void clear(); 415 | 416 | // Switch all LEDs on all displays to on. 417 | void fill(); 418 | 419 | // Invert all points of all matrixes 420 | void invert(); 421 | 422 | // How many times to rotate all matrixes clockwise 423 | // @param From 0 to 3 424 | void setRotation(uint8_t times = 1); 425 | 426 | // Reset rotation flag for all matrixes to default 427 | void resetRotation(); 428 | ``` 429 | 430 | The method allowing to know the size of the cascade: 431 | ```c 432 | // Returns the number of devices on this MatrixCascade 433 | constexpr uint16_t size() const; 434 | ``` 435 | 436 | Access to the matrix by index: 437 | ```c 438 | LedMatrix& get(uint16_t index); 439 | ``` 440 | 441 | Class `MatrixCascade` has a traits of an array. Contained matrixes can be accessed through the operator `[]`: 442 | ```c 443 | cascade[0].setRotation(3); 444 | cascade[1].setRotation(1); 445 | ``` 446 | 447 | Class `MatrixCascade` is iterable: 448 | ```c 449 | for(auto &matrix: cascade) { 450 | matrix.shiftUp(); 451 | } 452 | ``` 453 | ### Supercascades 454 | 455 | 456 | Cascades of matrices may, in turn, combined into a super cascades. 457 | The difference between a cascade and a supercascade is only in the way of constructing any object. In fact it is the same `MatrixCascade`. 458 | 459 | To create a supercascade, you need to use the function `combineCascades()`. 460 | Example: 461 | ```c 462 | auto cascade = combineCascades( 463 | MatrixCascade<5>(10), 464 | MatrixCascade<8>(12), 465 | MatrixCascade<7>(1, 2, 3), 466 | MatrixCascade<8>(4, 5, 6), 467 | MatrixCascade<8>(7, 8, 9), 468 | MatrixCascade<3>(14), 469 | MatrixCascade<6>(15), 470 | ); 471 | ``` 472 | Variable `cascade` is the object of type `MatrixCascade<45>`. 473 | Accordingly, it will control the 45-th matrices. 474 | This makes it possible to lift the restrictions *8* matrices per cascade imposed chips **MAX7219** and **MAX7221** 475 | The actual limitation is the number of free pins. 476 | 477 | ## Additionally 478 | 479 | More detailed information is available in the [source code](src), which I tried to provide comments, and in the [examples](examples). 480 | 481 | --- 482 | The library does not implement the means to print a text string on the cascade of matrices. This is intentional. 483 | Since the matrix can be mounted in an arbitrary manner. 484 | And entering code into the library involving a particular type of installation would be a violation of integrity. 485 | Especially to write any superstructure library with the desired functionality is not difficult. 486 | All the necessary functions are in the library. 487 | 488 | A couple of examples how to make a running line: [1](examples/MultiShift/MultiShift.ino), [2](examples/HelloHabr/HelloHabr.ino) 489 | 490 | --- 491 | Initially, the library was a fork of the library [LedControl](https://github.com/wayoda/LedControl) library. 492 | I completely reworked the original library. From the original library code has remained just a couple of lines. So it was moved to a separate repository. 493 | 494 | --- 495 | Feel free to report bugs and send your suggestions. 496 | 497 | --- 498 | [The MIT License](LICENSE) 499 | 500 | 501 | [Russian version](README.RU.md) 502 | 503 | 504 | -------------------------------------------------------------------------------- /examples/CascadedDevices/CascadedDevices.ino: -------------------------------------------------------------------------------- 1 | #include "MatrixCascade.h" 2 | // This time we have more than one device. 3 | 4 | 5 | // pin 11 is connected to the DataIn 6 | // pin 13 is connected to the CLK 7 | // pin 10 is connected to LOAD (cs) 8 | const uint8_t CascadeSize = 3; 9 | MatrixCascade cascade(11, 13, 10); 10 | 11 | unsigned long delaytime = 30; 12 | 13 | void setup() 14 | { 15 | // Set the brightness. (0..15) 16 | cascade.setIntensity(0); 17 | 18 | // Rotate some matrixes 19 | cascade[1].setRotation(2); 20 | cascade[2].setRotation(2); 21 | } 22 | 23 | void loop() 24 | { 25 | for(auto &matrix: cascade) { 26 | for(auto &row: matrix.rows()) { 27 | for(auto &col: matrix.cols()) { 28 | delay(delaytime); 29 | matrix.on(row, col); 30 | } 31 | } 32 | } 33 | 34 | for(auto &matrix: cascade) { 35 | for(auto &col: matrix.cols()) { 36 | for(auto &row: matrix.rows()) { 37 | delay(delaytime); 38 | matrix.off(row, col); 39 | } 40 | } 41 | 42 | // Rotate matrix 43 | matrix.setRotation(); 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /examples/CascadedInvert/CascadedInvert.ino: -------------------------------------------------------------------------------- 1 | #include "MatrixCascade.h" 2 | 3 | // pin 11 is connected to the DataIn 4 | // pin 13 is connected to the CLK 5 | // pin 10 is connected to LOAD (cs) 6 | const uint8_t CascadeSize = 3; 7 | MatrixCascade cascade(11, 13, 10); 8 | 9 | unsigned long delaytime = 20; 10 | 11 | void setup() 12 | { 13 | // Set the brightness. (0..15) 14 | cascade.setIntensity(0); 15 | 16 | // Rotate some matrixes 17 | cascade[1].setRotation(2); 18 | cascade[2].setRotation(2); 19 | 20 | // Init random sequense 21 | randomSeed(millis()); 22 | } 23 | 24 | 25 | void loop() 26 | { 27 | for(auto &matrix: cascade) { 28 | for(auto &row: matrix.rows()) { 29 | for(auto &col: matrix.cols()) { 30 | delay(delaytime); 31 | matrix.set(row, col, random(2)); 32 | } 33 | } 34 | } 35 | 36 | // Invert all matrixes on cascade 37 | cascade.invert(); 38 | delay(50*delaytime); 39 | 40 | for(auto &matrix: cascade) { 41 | for(auto &col: matrix.cols()) { 42 | for(auto &row: matrix.rows()) { 43 | delay(delaytime); 44 | matrix.set(row, col, random(2)); 45 | } 46 | } 47 | // Rotate matrix 48 | matrix.setRotation(); 49 | } 50 | cascade.invert(); 51 | delay(50*delaytime); 52 | 53 | cascade.clear(); 54 | delay(50*delaytime); 55 | cascade.fill(); 56 | } 57 | 58 | -------------------------------------------------------------------------------- /examples/CombineCascades/CombineCascades.ino: -------------------------------------------------------------------------------- 1 | #include "MatrixCascade.h" 2 | 3 | // 4 | // 5 | // This example clearly shows the difference in the speed between the hardware and software SPI 6 | // 7 | // 8 | 9 | // pin 11 is connected to the DataIn 10 | // pin 13 is connected to the CLK 11 | // pin 10 is connected to LOAD 12 | auto cascade = combineCascades( 13 | MatrixCascade<2>(10), 14 | MatrixCascade<1>(5, 6, 7) 15 | ); 16 | 17 | 18 | 19 | const uint8_t picsCount = 3; 20 | const uint8_t pics[3][8] = { 21 | {B00000000, B00000000, B10001000, B11011001, B10101010, B10001011, B10001010, B00000000}, 22 | {B00000000, B00000000, B00000000, B00010010, B10111011, B10010010, B10011010, B00000000}, 23 | {B00000000, B00100000, B00000000, B10101001, B00100010, B00100100, B00101001, B00000000}, 24 | }; 25 | 26 | 27 | void setup() 28 | { 29 | cascade.setIntensity(0); 30 | 31 | // Rotate some matrixes 32 | cascade[1].setRotation(2); 33 | cascade[2].setRotation(2); 34 | 35 | for (auto &matrix: cascade) 36 | { 37 | matrix.set(pics[matrix.index()]); 38 | } 39 | 40 | } 41 | 42 | const uint8_t matrixSize = 8; 43 | 44 | void loop() 45 | { 46 | // 47 | // Shifting Right 48 | // 49 | 50 | //iterate over colomns 51 | for (uint8_t i = 0; i < matrixSize; ++i) 52 | { 53 | // get last colomn in cascade 54 | auto LastCol = cascade[cascade.size() - 1].getCol(matrixSize - 1); 55 | 56 | for (auto &matrix: cascade) 57 | { 58 | LastCol = matrix.shiftRight(LastCol); 59 | delay(20); 60 | } 61 | //delay(100); 62 | } 63 | //delay(100); 64 | } 65 | -------------------------------------------------------------------------------- /examples/HelloHabr/HelloHabr.ino: -------------------------------------------------------------------------------- 1 | #include "MatrixCascade.h" 2 | 3 | // pin 11 is connected to the DataIn 4 | // pin 13 is connected to the CLK 5 | // pin 10 is connected to LOAD 6 | const uint8_t CascadeSize = 3; 7 | // Software SPI: 8 | //MatrixCascade cascade(11, 13, 10); 9 | // Hardware SPI: 10 | MatrixCascade cascade(10); 11 | 12 | const uint8_t cols[] = { 13 | 0b11111111, 14 | 0b10000000, 15 | 0b10000000, 16 | 0b10000000, 17 | 0b10000000, 18 | 0b11111111, 19 | 0b00000000, 20 | 21 | 0b00111111, 22 | 0b00100100, 23 | 0b00100100, 24 | 0b00011000, 25 | 0b00000000, 26 | 27 | 0b00111111, 28 | 0b00000010, 29 | 0b00000100, 30 | 0b00001000, 31 | 0b00111111, 32 | 0b00000000, 33 | 34 | 0b00111111, 35 | 0b00101001, 36 | 0b00011001, 37 | 0b00000110, 38 | 0b00000000, 39 | 40 | 0b00111111, 41 | 0b00101001, 42 | 0b00101001, 43 | 0b00101001, 44 | 0b00000000, 45 | 46 | 0b00100000, 47 | 0b00100000, 48 | 0b00111111, 49 | 0b00100000, 50 | 0b00100000, 51 | 0b00000000, 52 | 53 | 0b11000011, 54 | 0b01100110, 55 | 0b00111100, 56 | 0b00111100, 57 | 0b01100110, 58 | 0b11000011, 59 | 0b00000000, 60 | 61 | 0b00011111, 62 | 0b00100100, 63 | 0b00100100, 64 | 0b00011111, 65 | 0b00000000, 66 | 67 | 0b00111111, 68 | 0b00101001, 69 | 0b00101001, 70 | 0b00100110, 71 | 0b00000000, 72 | 73 | 0b00111111, 74 | 0b00100100, 75 | 0b00100100, 76 | 0b00011000, 77 | 0b00000000, 78 | 79 | 0b00000000, 80 | 0b00000000, 81 | 0b00000000, 82 | }; 83 | const uint8_t colsCount = sizeof(cols); 84 | 85 | 86 | void setup() 87 | { 88 | cascade.setIntensity(0); 89 | 90 | // Rotate some matrixes 91 | cascade[1].setRotation(2); 92 | cascade[2].setRotation(2); 93 | } 94 | 95 | const uint8_t matrixSize = 8; 96 | 97 | uint8_t offset = 0; 98 | 99 | void loop() 100 | { 101 | uint8_t colInd = 0; 102 | for (auto &matrix: cascade) 103 | { 104 | for (auto &col: matrix.cols()) 105 | { 106 | matrix.set(col, cols[(offset + colInd)%colsCount]); 107 | colInd++; 108 | delay(3); 109 | } 110 | delay(7); 111 | } 112 | ++offset; 113 | offset %= colsCount; 114 | } 115 | -------------------------------------------------------------------------------- /examples/Inverse/Inverse.ino: -------------------------------------------------------------------------------- 1 | #include "LedMatrix.h" 2 | 3 | // pin 11 is connected to the DataIn 4 | // pin 13 is connected to the CLK 5 | // pin 10 is connected to LOAD (cs) 6 | LedMatrix matrix(11, 13, 10); 7 | 8 | const uint16_t delaytime = 700; 9 | 10 | void setup() 11 | { 12 | // Set the brightness to a medium values 13 | matrix.setIntensity(1); 14 | } 15 | 16 | void loop() 17 | { 18 | matrix.set({B01011010, B10100101, B01100110, B10011001, B10011001, B01100110, B10100101, B01011010}); 19 | delay(delaytime); 20 | matrix.invert(); 21 | delay(delaytime); 22 | 23 | 24 | matrix.set({B00011000, B00100100, B01100110, B10011001, B10011001, B01100110, B00100100, B00011000}); 25 | delay(delaytime); 26 | matrix.invert(); 27 | delay(delaytime); 28 | 29 | matrix.set({B11111111, B11111111, B11111111, B01111110, B00111100, B00011000, B00011000, B01111110}); 30 | delay(delaytime); 31 | matrix.invert(); 32 | delay(delaytime); 33 | 34 | matrix.set({B00000000, B00010000, B00101000, B00010000, B00111000, B10010010, B01010100, B00111000}); 35 | delay(delaytime); 36 | matrix.invert(); 37 | delay(delaytime); 38 | 39 | matrix.set({B11111110, B10000010, B10000010, B11111110, B10101010, B11111110, B10101010, B11111110}); 40 | delay(delaytime); 41 | matrix.invert(); 42 | delay(delaytime); 43 | 44 | matrix.set({B00000000, B01100110, B10011001, B10000001, B01000010, B00100100, B00011000, B00000000}); 45 | delay(delaytime); 46 | matrix.invert(); 47 | delay(delaytime); 48 | 49 | matrix.set({B01111111, B00111111, B00011111, B00011111, B00111111, B01110011, B11100001, B01000000}); 50 | delay(delaytime); 51 | matrix.invert(); 52 | delay(delaytime); 53 | 54 | 55 | matrix.setRotation(); 56 | } 57 | -------------------------------------------------------------------------------- /examples/Inverse2/Inverse2.ino: -------------------------------------------------------------------------------- 1 | #include "LedMatrix.h" 2 | 3 | // pin 11 is connected to the DataIn 4 | // pin 13 is connected to the CLK 5 | // pin 10 is connected to LOAD (cs) 6 | LedMatrix matrix(11, 13, 10); 7 | 8 | void setup() 9 | { 10 | // Set the brightness. (0..15) 11 | matrix.setIntensity(0); 12 | } 13 | 14 | void loop() 15 | { 16 | // Switch all LEDs on the display to off. 17 | matrix.clear(); 18 | delay(300); 19 | 20 | // Switch all LEDs on the display to on. 21 | matrix.fill(); 22 | delay(300); 23 | 24 | // Iterate over rows to invert them 25 | for(auto &row: matrix.rows()) { 26 | matrix.invert(row); 27 | delay(70); 28 | } 29 | // Iterate over colomns to invert them 30 | for(auto &col: matrix.cols()) { 31 | matrix.invert(col); 32 | delay(70); 33 | } 34 | 35 | // Iterate for each point to invert it 36 | for(auto &row: matrix.rows()) { 37 | for(auto &col: matrix.cols()) { 38 | matrix.invert(row, col); 39 | delay(30); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /examples/Matrix/Matrix.ino: -------------------------------------------------------------------------------- 1 | #include "LedMatrix.h" 2 | 3 | // pin 11 is connected to the DataIn 4 | // pin 13 is connected to the CLK 5 | // pin 10 is connected to LOAD (cs) 6 | LedMatrix matrix(11, 13, 10); 7 | 8 | const uint16_t delaytime = 300; 9 | 10 | void setup() { 11 | // Set the brightness. (0..15) 12 | matrix.setIntensity(1); 13 | } 14 | 15 | // This method will display the characters for the 16 | // word "Arduino" one after the other on the matrix. 17 | // (you need at least 5x7 leds to see the whole chars) 18 | void writeArduinoOnMatrix() { 19 | 20 | // now display them one by one with a small delay 21 | // A 22 | // using initializer_list example 23 | matrix.set({B01110000, B10001000, B10001000, B10001000, B11111000, B10001000, B10001000, B10001000}); 24 | delay(3*delaytime); 25 | 26 | // r 27 | matrix.set({B00000000, B00000000, B00000000, B10110000, B11001000, B10000000, B10000000, B10000000}); 28 | delay(3*delaytime); 29 | 30 | // d 31 | matrix.set({B00000000, B00001000, B00001000, B01101000, B10011000, B10001000, B10011000, B01101000}); 32 | delay(3*delaytime); 33 | 34 | //u 35 | matrix.set({B00000000, B00000000, B00000000, B10001000, B10001000, B10001000, B10011000, B01101000}); 36 | delay(3*delaytime); 37 | 38 | // i 39 | // Attention. You can do so, but do not use this option. 40 | // If you pass an array to the function set, strictly follow its length 41 | uint8_t arr_i[8] = {B00000000, B00100000, B00000000, B01100000, B00100000, B00100000, B00100000, B01110000}; 42 | matrix.set(arr_i); 43 | delay(3*delaytime); 44 | 45 | //n 46 | auto arr_n = {B00000000, B00000000, B00000000, B10110000, B11001000, B10001000, B10001000, B10001000}; 47 | matrix.set(arr_n); 48 | delay(3*delaytime); 49 | 50 | // o 51 | uint8_t arr_o[] = {B00000000, B00000000, B00000000, B01110000, B10001000, B10001000, B10001000, B01110000}; 52 | // one by one for example 53 | for(auto &row: matrix.rows()) { 54 | matrix.set(row, arr_o[row]); 55 | } 56 | delay(3*delaytime); 57 | 58 | matrix.set({B00000000, B01100110, B10011001, B10000001, B01000010, B00100100, B00011000, B00000000}); 59 | delay(3*delaytime); 60 | 61 | matrix.clear(); 62 | delay(3*delaytime); 63 | } 64 | 65 | // This function lights up a some Leds in a row. 66 | // The pattern will be repeated on every row. 67 | // The pattern will blink along with the row-number. 68 | // row number 4 (index==3) will blink 4 times etc. 69 | void rows() { 70 | for(auto &row: matrix.rows()) { 71 | delay(delaytime); 72 | matrix.set(row, B10101010); 73 | delay(delaytime); 74 | matrix.set(row, 0); 75 | 76 | for(int i=0; i cascade(11, 13, 10); 15 | // Hardware SPI: 16 | MatrixCascade cascade(10); 17 | 18 | const uint8_t picsCount = 3; 19 | const uint8_t pics[3][8] = { 20 | //{0b10000011, 0b10000111, 0b10001001, 0b11010010, 0b11110100, 0b11010010, 0b10001001, 0b10000111}, 21 | //{0b11111111, 0b10000001, 0b10111101, 0b10100101, 0b10100101, 0b10111101, 0b10000001, 0b11111111}, 22 | //{0b10011001, 0b01011010, 0b00111100, 0b11111111, 0b11111111, 0b00111100, 0b01011010, 0b10011001}, 23 | {B00000000, B00000000, B10001000, B11011001, B10101010, B10001011, B10001010, B00000000}, 24 | {B00000000, B00000000, B00000000, B00010010, B10111011, B10010010, B10011010, B00000000}, 25 | {B00000000, B00100000, B00000000, B10101001, B00100010, B00100100, B00101001, B00000000}, 26 | }; 27 | 28 | 29 | void setup() 30 | { 31 | cascade.setIntensity(0); 32 | 33 | // Rotate some matrixes 34 | cascade[1].setRotation(2); 35 | cascade[2].setRotation(2); 36 | 37 | for (auto &matrix: cascade) 38 | { 39 | matrix.set(pics[matrix.index()]); 40 | } 41 | } 42 | 43 | const uint8_t matrixSize = 8; 44 | 45 | void loop() 46 | { 47 | // 48 | // Shifting Right 49 | // 50 | 51 | //iterate over colomns 52 | for (uint8_t i = 0; i < matrixSize; ++i) 53 | { 54 | // get last colomn in cascade 55 | auto LastCol = cascade[CascadeSize - 1].getCol(matrixSize - 1); 56 | 57 | for (auto &matrix: cascade) 58 | { 59 | LastCol = matrix.shiftRight(LastCol); 60 | delay(20); 61 | } 62 | //delay(100); 63 | } 64 | //delay(100); 65 | } 66 | -------------------------------------------------------------------------------- /examples/MultiShift2/MultiShift2.ino: -------------------------------------------------------------------------------- 1 | #include "MatrixCascade.h" 2 | 3 | // pin 11 is connected to the DataIn 4 | // pin 13 is connected to the CLK 5 | // pin 10 is connected to LOAD 6 | const uint8_t CascadeSize = 3; 7 | MatrixCascade cascade(11, 13, 10); 8 | //MatrixCascade cascade(10); 9 | 10 | const uint16_t delaytime = 20; 11 | 12 | //const uint8_t pic[] = {B11001111, B10011110, B00111100, B01111001, B11110011, B11100111, B11001111, B10011110}; 13 | //const uint8_t pic[] = {B01001001, B10010010, B00100100, B01001000, B10010000, B00100000, B01000000, B10000000}; 14 | const uint8_t pic[] = {B10000011, B10000101, B10001001, B11010010, B11110100, B11010010, B10001001, B10000111}; 15 | 16 | 17 | void setup() 18 | { 19 | // Set the brightness. (0..15) 20 | cascade.setIntensity(0); 21 | 22 | for(auto &matrix: cascade) { 23 | matrix.set(pic); 24 | } 25 | } 26 | 27 | void loop() 28 | { 29 | delay(delaytime); 30 | 31 | for(auto &matrix: cascade) { 32 | matrix.set(pic); 33 | for(int i = 0; i < 8; i++){ 34 | matrix.shiftUp(pic[i%8]); 35 | delay(delaytime); 36 | } 37 | delay(1000); 38 | 39 | matrix.set(pic); 40 | for(int i = 0; i < 8; i++){ 41 | matrix.shiftDown(pic[i%8]); 42 | delay(delaytime); 43 | } 44 | delay(1000); 45 | 46 | matrix.set(pic); 47 | for(int i = 0; i < 8; i++){ 48 | matrix.shiftLeft(pic[i%8]); 49 | delay(delaytime); 50 | } 51 | delay(1000); 52 | 53 | matrix.set(pic); 54 | for(int i = 0; i < 8; i++){ 55 | matrix.shiftRight(pic[i%8]); 56 | delay(delaytime); 57 | } 58 | delay(1000); 59 | matrix.setRotation(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /examples/MultiShiftHwSPI/MultiShiftHwSPI.ino: -------------------------------------------------------------------------------- 1 | #include "MatrixCascade.h" 2 | 3 | // hardware SPI wiring scheme: 4 | // CLK => SCLK (Arduino pin 13) 5 | // DOUT => MISO 6 | // DIN => MOSI (Arduino pin 11) 7 | // CS => (Arduino any pin) 8 | 9 | // pin 11 is connected to the DataIn 10 | // pin 13 is connected to the CLK 11 | // pin 10 is connected to LOAD (cs) 12 | const uint8_t CascadeSize = 3; 13 | //MatrixCascade cascade(11, 13, 10); 14 | MatrixCascade cascade(10); 15 | 16 | const uint16_t delaytime = 20; 17 | 18 | //const uint8_t pic[] = {B11001111, B10011110, B00111100, B01111001, B11110011, B11100111, B11001111, B10011110}; 19 | //const uint8_t pic[] = {B01001001, B10010010, B00100100, B01001000, B10010000, B00100000, B01000000, B10000000}; 20 | const uint8_t pic[] = {B10000011, B10000101, B10001001, B11010010, B11110100, B11010010, B10001001, B10000111}; 21 | 22 | 23 | void setup() 24 | { 25 | // Set the brightness. (0..15) 26 | cascade.setIntensity(0); 27 | 28 | for(auto &matrix: cascade) { 29 | matrix.set(pic); 30 | } 31 | } 32 | 33 | void loop() 34 | { 35 | delay(delaytime); 36 | 37 | for(auto &matrix: cascade) { 38 | matrix.set(pic); 39 | for(int i = 0; i < 8; i++){ 40 | matrix.shiftUp(pic[i%8]); 41 | delay(delaytime); 42 | } 43 | delay(1000); 44 | 45 | matrix.set(pic); 46 | for(int i = 0; i < 8; i++){ 47 | matrix.shiftDown(pic[i%8]); 48 | delay(delaytime); 49 | } 50 | delay(1000); 51 | 52 | matrix.set(pic); 53 | for(int i = 0; i < 8; i++){ 54 | matrix.shiftLeft(pic[i%8]); 55 | delay(delaytime); 56 | } 57 | delay(1000); 58 | 59 | matrix.set(pic); 60 | for(int i = 0; i < 8; i++){ 61 | matrix.shiftRight(pic[i%8]); 62 | delay(delaytime); 63 | } 64 | delay(1000); 65 | matrix.setRotation(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examples/RandomMove/RandomMove.ino: -------------------------------------------------------------------------------- 1 | #include "LedMatrix.h" 2 | #include "randomMovement.h" 3 | 4 | // A single display 5 | // pin 11 is connected to the DataIn 6 | // pin 13 is connected to the CLK 7 | // pin 10 is connected to LOAD (cs) 8 | LedMatrix matrix(11, 13, 10); 9 | 10 | randomMovement randMov(matrix, A4); 11 | 12 | void setup() 13 | { 14 | // Set the brightness. (0..15) 15 | matrix.setIntensity(1); 16 | } 17 | 18 | void loop() 19 | { 20 | randMov.off(); 21 | randMov.move(); 22 | randMov.on(); 23 | delay(150); 24 | } 25 | -------------------------------------------------------------------------------- /examples/RandomMove/randomMovement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "LedMatrix.h" 4 | 5 | class randomMovement { 6 | public: 7 | // Constructor 8 | randomMovement(LedMatrix &m, uint8_t randPin) : _m(m) 9 | { 10 | randomSeed(analogRead(randPin) + millis()); 11 | _x = random(max+1); 12 | _y = random(max+1); 13 | _m.clear(); 14 | } 15 | 16 | // Copy & Move constructors 17 | randomMovement( const randomMovement& ) = default; 18 | randomMovement ( randomMovement && ) = default; 19 | 20 | void on() 21 | { 22 | _m.on(_x, _y); 23 | } 24 | void off() 25 | { 26 | _m.off(_x, _y); 27 | } 28 | 29 | void move() 30 | { 31 | _x = move(_x); 32 | _y = move(_y); 33 | } 34 | private: 35 | uint8_t move(uint8_t v) 36 | { 37 | int8_t dv = 1-random(0, 3); 38 | 39 | if(v == 0 && dv != 0) v++; 40 | else if(v == max && dv != 0) v--; 41 | else v += dv; 42 | return v; 43 | } 44 | 45 | private: 46 | LedMatrix &_m; 47 | uint8_t _x = 3; 48 | uint8_t _y = 4; 49 | constexpr static uint8_t max = 7; 50 | }; 51 | 52 | 53 | -------------------------------------------------------------------------------- /examples/RandomMove1/RandomMove1.ino: -------------------------------------------------------------------------------- 1 | #include "MatrixCascade.h" 2 | #include "randomMovement.h" 3 | 4 | 5 | const uint8_t matrixCount = 3; 6 | 7 | // pin 11 is connected to the DataIn 8 | // pin 13 is connected to the CLK 9 | // pin 10 is connected to LOAD (cs) 10 | MatrixCascade cascade(11, 13, 10); 11 | 12 | randomMovement point1(cascade, A4), 13 | point2(cascade, A4), 14 | point3(cascade, A4); 15 | 16 | 17 | void setup() 18 | { 19 | int devices = cascade.size(); 20 | 21 | // Here iterate via access operator 22 | for(int i=0; i < devices; i++) { 23 | // Set the brightness. (0..15) 24 | cascade[i].setIntensity(1); 25 | } 26 | cascade[0].setRotation(3); 27 | cascade[1].setRotation(1); 28 | cascade[2].setRotation(1); 29 | } 30 | 31 | 32 | void loop() 33 | { 34 | point1.off(); 35 | point1.move(); 36 | point1.on(); 37 | 38 | point2.off(); 39 | point2.move(); 40 | point2.on(); 41 | 42 | point3.off(); 43 | point3.move(); 44 | point3.on(); 45 | 46 | delay(150); 47 | } 48 | -------------------------------------------------------------------------------- /examples/RandomMove1/randomMovement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "MatrixCascade.h" 4 | 5 | template 6 | class randomMovement { 7 | public: 8 | // Constructor 9 | randomMovement(MatrixCascade &cascade, uint8_t randPin) : 10 | _cascade(cascade) 11 | { 12 | randomSeed(analogRead(randPin) + millis()); 13 | _x = random(maxX); 14 | _y = random(maxY); 15 | //_cascade.clear(); 16 | } 17 | 18 | // Copy & Move constructors 19 | randomMovement( const randomMovement& ) = default; 20 | randomMovement ( randomMovement && ) = default; 21 | 22 | void on() 23 | { 24 | uint8_t x = _x%maxY; 25 | uint8_t i = (_x - x)/maxY; 26 | _cascade[i].on(x, _y); 27 | } 28 | void off() 29 | { 30 | uint8_t x = _x%maxY; 31 | uint8_t i = (_x - x)/maxY; 32 | _cascade[i].off(x, _y); 33 | } 34 | 35 | void move() 36 | { 37 | _x = move(_x, maxX); 38 | _y = move(_y, maxY); 39 | } 40 | private: 41 | uint8_t move(uint8_t v, uint8_t max) 42 | { 43 | int8_t dv = 1-random(0, 3); 44 | 45 | if(v == 0 && dv != 0) v++; 46 | else if(v == (max-1) && dv != 0) v--; 47 | else v += dv; 48 | return v; 49 | } 50 | 51 | private: 52 | MatrixCascade &_cascade; 53 | uint8_t _x = 0; 54 | uint8_t _y = 0; 55 | constexpr static uint8_t maxX = 8 * cascadeSize; 56 | constexpr static uint8_t maxY = 8; 57 | }; 58 | 59 | 60 | -------------------------------------------------------------------------------- /examples/SingleShift/SingleShift.ino: -------------------------------------------------------------------------------- 1 | #include "LedMatrix.h" 2 | 3 | // pin 11 is connected to the DataIn 4 | // pin 13 is connected to the CLK 5 | // pin 10 is connected to LOAD (cs) 6 | LedMatrix matrix(11, 13, 10); 7 | 8 | const uint16_t delaytime = 1000; 9 | 10 | const uint8_t picsCount = 6; 11 | const uint8_t pics[6][8] = { 12 | {0b10000011, 0b10000111, 0b10001001, 0b11010010, 0b11110100, 0b11010010, 0b10001001, 0b10000111}, 13 | {0b11001111, 0b10011110, 0b00111100, 0b01111001, 0b11110011, 0b11100111, 0b11001111, 0b10011110}, 14 | {0b01001001, 0b10010010, 0b00100100, 0b01001000, 0b10010000, 0b00100000, 0b01000000, 0b10000000}, 15 | {0b11111111, 0b10000001, 0b10111101, 0b10100101, 0b10100101, 0b10111101, 0b10000001, 0b11111111}, 16 | {0b10011001, 0b01011010, 0b00111100, 0b11111111, 0b11111111, 0b00111100, 0b01011010, 0b10011001}, 17 | {0b11111000, 0b00000100, 0b00000010, 0b11111111, 0b11111111, 0b11000010, 0b11000100, 0b11001000}, 18 | }; 19 | 20 | 21 | void setup() 22 | { 23 | matrix.setIntensity(0); 24 | } 25 | 26 | uint8_t ind = 0; 27 | 28 | void loop() 29 | { 30 | 31 | auto pic = pics[ind % picsCount]; 32 | 33 | matrix.set(pics[ind % picsCount]); 34 | for(int i = 0; i < 8; i++){ 35 | matrix.shiftUp(pic[i%8]); 36 | delay(80); 37 | } 38 | delay(1000); 39 | 40 | matrix.set(pic); 41 | for(int i = 0; i < 8; i++){ 42 | matrix.shiftDown(pic[i%8]); 43 | delay(80); 44 | } 45 | delay(1000); 46 | 47 | matrix.set(pic); 48 | for(int i = 0; i < 8; i++){ 49 | matrix.shiftLeft(pic[i%8]); 50 | delay(80); 51 | } 52 | delay(1000); 53 | 54 | matrix.set(pic); 55 | for(int i = 0; i < 8; i++){ 56 | matrix.shiftRight(pic[i%8]); 57 | delay(80); 58 | } 59 | delay(1000); 60 | 61 | ind++; 62 | } 63 | -------------------------------------------------------------------------------- /examples/SingleShiftHwSPI/SingleShiftHwSPI.ino: -------------------------------------------------------------------------------- 1 | #include "LedMatrix.h" 2 | 3 | // SPI wiring scheme: 4 | // CLK => SCLK (Arduino pin 13) 5 | // DOUT => MISO 6 | // DIN => MOSI (Arduino pin 11) 7 | // CS => (Arduino any pin) 8 | 9 | // pin 11 is connected to the DataIn 10 | // pin 13 is connected to the CLK 11 | // pin 10 is connected to LOAD (cs) 12 | //LedMatrix matrix(11, 13, 10); 13 | LedMatrix matrix(10); 14 | 15 | const uint16_t delaytime = 1000; 16 | 17 | const uint8_t picsCount = 6; 18 | const uint8_t pics[6][8] = { 19 | {0b10000011, 0b10000111, 0b10001001, 0b11010010, 0b11110100, 0b11010010, 0b10001001, 0b10000111}, 20 | {0b11001111, 0b10011110, 0b00111100, 0b01111001, 0b11110011, 0b11100111, 0b11001111, 0b10011110}, 21 | {0b01001001, 0b10010010, 0b00100100, 0b01001000, 0b10010000, 0b00100000, 0b01000000, 0b10000000}, 22 | {0b11111111, 0b10000001, 0b10111101, 0b10100101, 0b10100101, 0b10111101, 0b10000001, 0b11111111}, 23 | {0b10011001, 0b01011010, 0b00111100, 0b11111111, 0b11111111, 0b00111100, 0b01011010, 0b10011001}, 24 | {0b11111000, 0b00000100, 0b00000010, 0b11111111, 0b11111111, 0b11000010, 0b11000100, 0b11001000}, 25 | }; 26 | 27 | 28 | void setup() 29 | { 30 | matrix.setIntensity(0); 31 | } 32 | 33 | uint8_t ind = 0; 34 | 35 | void loop() 36 | { 37 | 38 | auto pic = pics[ind % picsCount]; 39 | 40 | matrix.set(pics[ind % picsCount]); 41 | for(int i = 0; i < 8; i++){ 42 | matrix.shiftUp(pic[i%8]); 43 | delay(80); 44 | } 45 | delay(1000); 46 | 47 | matrix.set(pic); 48 | for(int i = 0; i < 8; i++){ 49 | matrix.shiftDown(pic[i%8]); 50 | delay(80); 51 | } 52 | delay(1000); 53 | 54 | matrix.set(pic); 55 | for(int i = 0; i < 8; i++){ 56 | matrix.shiftLeft(pic[i%8]); 57 | delay(80); 58 | } 59 | delay(1000); 60 | 61 | matrix.set(pic); 62 | for(int i = 0; i < 8; i++){ 63 | matrix.shiftRight(pic[i%8]); 64 | delay(80); 65 | } 66 | delay(1000); 67 | 68 | ind++; 69 | } 70 | -------------------------------------------------------------------------------- /examples/TestRotation/TestRotation.ino: -------------------------------------------------------------------------------- 1 | #include "LedMatrix.h" 2 | 3 | // pin 11 is connected to the DataIn 4 | // pin 13 is connected to the CLK 5 | // pin 10 is connected to LOAD (cs) 6 | LedMatrix matrix(11, 13, 10); 7 | 8 | const uint16_t delaytime = 1000; 9 | 10 | void setup() 11 | { 12 | // Set the brightness. (0..15) 13 | matrix.setIntensity(1); 14 | } 15 | 16 | 17 | void loop() 18 | { 19 | matrix.set({B00111111, B00011111, B00001111, B00011111, B00110011, B01100001, B11000111, B10000111}); 20 | delay(delaytime); 21 | 22 | matrix.invert(); 23 | delay(delaytime); 24 | 25 | matrix.setRotation(); 26 | } 27 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For LedMatrix 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | BitInt KEYWORD1 9 | BitIntMember KEYWORD1 10 | buint8_t KEYWORD1 11 | buint16_t KEYWORD1 12 | buint32_t KEYWORD1 13 | buint64_t KEYWORD1 14 | bint8_t KEYWORD1 15 | bint16_t KEYWORD1 16 | bint32_t KEYWORD1 17 | bint64_t KEYWORD1 18 | initializer_list KEYWORD1 19 | LedMatrix KEYWORD1 20 | RowCol KEYWORD1 21 | Col KEYWORD1 22 | Row KEYWORD1 23 | MatrixCascade KEYWORD1 24 | RowColIterator KEYWORD1 25 | ####################################### 26 | # Methods and Functions (KEYWORD2) 27 | ####################################### 28 | 29 | begin KEYWORD2 30 | clear KEYWORD2 31 | cols KEYWORD2 32 | combineCascades KEYWORD2 33 | end KEYWORD2 34 | fill KEYWORD2 35 | get KEYWORD2 36 | getCol KEYWORD2 37 | getRotation KEYWORD2 38 | getRow KEYWORD2 39 | index KEYWORD2 40 | invert KEYWORD2 41 | invertCol KEYWORD2 42 | invertRow KEYWORD2 43 | off KEYWORD2 44 | on KEYWORD2 45 | resetRotation KEYWORD2 46 | rows KEYWORD2 47 | set KEYWORD2 48 | setCol KEYWORD2 49 | setIntensity KEYWORD2 50 | setRotation KEYWORD2 51 | setRow KEYWORD2 52 | shiftDown KEYWORD2 53 | shiftLeft KEYWORD2 54 | shiftRight KEYWORD2 55 | shiftUp KEYWORD2 56 | shutdown KEYWORD2 57 | size KEYWORD2 58 | wakeup KEYWORD2 59 | ####################################### 60 | # Instances (KEYWORD2) 61 | ####################################### 62 | 63 | ####################################### 64 | # Constants (LITERAL1) 65 | ####################################### 66 | 67 | 68 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=LedMatrix 2 | version=1.0.1 3 | author=Valeriy Dmitriev aka Valmat 4 | maintainer=Valeriy Dmitriev aka Valmat 5 | sentence= Flexible and powerful Arduino library to control LED matrixes on chips MAX7219 and MAX7221. 6 | paragraph=The library allows to work with individual matrices and the matrix cascades, and cascades groups. Can use software or hardware SPI. Has other rich features. 7 | category=Display 8 | url=https://github.com/valmat/LedMatrix 9 | architectures=* 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/BitInt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * BitInt is a helper type for use the numeric types as a binary arrays 4 | * 5 | * @author Valeriy V Dmitriev aka valmat , http://valmat.ru/ 6 | * @licenses MIT https://opensource.org/licenses/MIT 7 | * @repo https://github.com/valmat/LedMatrix 8 | * 9 | */ 10 | 11 | #pragma once 12 | #include "BitIntMember.h" 13 | 14 | template 15 | class BitInt { 16 | public: 17 | 18 | // Constructors 19 | constexpr BitInt(T value) : _value(value) {} 20 | constexpr BitInt() : _value(0) {} 21 | 22 | // Get size 23 | constexpr uint8_t size () const 24 | { 25 | return _size; 26 | } 27 | 28 | // Cast to a number 29 | constexpr operator T () const 30 | { 31 | return _value; 32 | } 33 | 34 | constexpr bool get(uint8_t index) const 35 | { 36 | return _value & (1 << (_size - 1 - (index % _size))); 37 | } 38 | 39 | 40 | BitInt& set(uint8_t index, bool state) 41 | { 42 | T val = (1 << (_size - 1 - index % _size)); 43 | _value = state ? (_value | val) : (_value & ~val); 44 | return *this; 45 | } 46 | 47 | // Array access operator 48 | constexpr bool operator[](uint8_t index) const 49 | { 50 | return get(index); 51 | } 52 | 53 | // Array access operator 54 | BitIntMember operator[](uint8_t index) 55 | { 56 | return BitIntMember(index, *this); 57 | } 58 | 59 | // Cast to a number 60 | constexpr T get () const 61 | { 62 | return _value; 63 | } 64 | 65 | // Reverse operator 66 | // Binary order inverting transposition 67 | BitInt operator!() const 68 | { 69 | T rez = 0; 70 | uint8_t pos = 1; 71 | T x; 72 | uint8_t s = _size, s2 = _size / 2; 73 | 74 | for(uint8_t i = 0; i < s2; i++) { 75 | x = _value & (pos << i); 76 | rez = rez | ( x << (s-2*i-1) ); 77 | } 78 | for(uint8_t i = 0; i < s2; i++) { 79 | x = _value & ( pos << (s - i - 1) ); 80 | rez = rez | ( x >> (s-2*i-1) ); 81 | } 82 | return rez; 83 | } 84 | 85 | 86 | // Increment position (pre-increment) 87 | BitInt &operator++() 88 | { 89 | ++_value; 90 | return *this; 91 | } 92 | 93 | // Increment position (post-increment) 94 | BitInt operator++(int) 95 | { 96 | BitInt copy(*this); 97 | ++(*this); 98 | return copy; 99 | } 100 | 101 | // Decrement position (pre-decrement) 102 | BitInt &operator--() 103 | { 104 | --_value; 105 | return *this; 106 | } 107 | 108 | // Increment position (post-decrement) 109 | BitInt operator--(int) 110 | { 111 | BitInt copy(*this); 112 | --(*this); 113 | return copy; 114 | } 115 | 116 | // Make iterable 117 | constexpr const BitIntMember begin() const 118 | { 119 | return BitIntMember(0, *this); 120 | } 121 | constexpr const BitIntMember end() const 122 | { 123 | return BitIntMember(_size, *this); 124 | } 125 | 126 | 127 | BitIntMember begin() 128 | { 129 | return BitIntMember(0, *this); 130 | } 131 | BitIntMember end() 132 | { 133 | return BitIntMember(_size, *this); 134 | } 135 | 136 | private: 137 | 138 | T _value; 139 | }; 140 | 141 | // Types predefinition 142 | using buint8_t = BitInt; 143 | using buint16_t = BitInt; 144 | using buint32_t = BitInt; 145 | using buint64_t = BitInt; 146 | 147 | using bint8_t = BitInt; 148 | using bint16_t = BitInt; 149 | using bint32_t = BitInt; 150 | using bint64_t = BitInt; 151 | 152 | 153 | -------------------------------------------------------------------------------- /src/BitIntMember.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * BitIntMember is an auxiliary type that allows to make BigInt array-accessible and iterable 4 | * 5 | * @author Valeriy V Dmitriev aka valmat , http://valmat.ru/ 6 | * @licenses MIT https://opensource.org/licenses/MIT 7 | * @repo https://github.com/valmat/LedMatrix 8 | * 9 | */ 10 | 11 | #pragma once 12 | 13 | // Forward declaration 14 | template 15 | class BitInt; 16 | 17 | 18 | template 19 | class BitIntMember 20 | { 21 | public: 22 | BitIntMember(uint8_t index, BitInt &val) : 23 | _val(val), 24 | _index(index) 25 | {} 26 | 27 | BitIntMember& operator=(bool state) 28 | { 29 | _val.set(_index, state); 30 | return *this; 31 | } 32 | 33 | operator bool () const 34 | { 35 | return _val.get(_index); 36 | } 37 | 38 | // 39 | // Iterator operators 40 | // 41 | 42 | // Increment position (pre-increment) 43 | BitIntMember &operator++() 44 | { 45 | ++_index; 46 | return *this; 47 | } 48 | 49 | // Increment position (post-increment) 50 | BitIntMember operator++(int) 51 | { 52 | BitIntMember copy(*this); 53 | ++(*this); 54 | return copy; 55 | } 56 | 57 | // Decrement position (pre-decrement) 58 | BitIntMember &operator--() 59 | { 60 | --_index; 61 | return *this; 62 | } 63 | 64 | // Increment position (post-decrement) 65 | BitIntMember operator--(int) 66 | { 67 | BitIntMember copy(*this); 68 | --(*this); 69 | return copy; 70 | } 71 | 72 | // Compare with other iterator 73 | bool operator==(const BitIntMember &rhs) const 74 | { 75 | return (_val == rhs._val && _index == rhs._index); 76 | } 77 | 78 | // Compare with other iterator 79 | bool operator!=(const BitIntMember &rhs) const 80 | { 81 | return !(*this == rhs); 82 | } 83 | 84 | // Dereference as a current object 85 | bool operator*() const 86 | { 87 | return _val.get(_index); 88 | } 89 | 90 | private: 91 | BitInt &_val; 92 | uint8_t _index; 93 | }; 94 | 95 | -------------------------------------------------------------------------------- /src/CoreMax72xx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * CoreMax72xx this is the class for direct interaction with a controller MAX72xx 4 | * 5 | * @author Valeriy V Dmitriev aka valmat , http://valmat.ru/ 6 | * @licenses MIT https://opensource.org/licenses/MIT 7 | * @repo https://github.com/valmat/LedMatrix 8 | * 9 | * 10 | * Software SPI and main core functionality implemented 11 | * by Eberhard Fahle aka wayoda 12 | * https://github.com/wayoda/LedControl 13 | * http://wayoda.github.io/LedControl/ 14 | * 15 | */ 16 | 17 | 18 | #include "CoreMax72xx.h" 19 | #include 20 | 21 | //the opcodes for the MAX7221 and MAX7219 22 | namespace 23 | { 24 | constexpr uint8_t OP_NOOP = 0; 25 | constexpr uint8_t OP_DIGIT0 = 1; 26 | constexpr uint8_t OP_DIGIT1 = 2; 27 | constexpr uint8_t OP_DIGIT2 = 3; 28 | constexpr uint8_t OP_DIGIT3 = 4; 29 | constexpr uint8_t OP_DIGIT4 = 5; 30 | constexpr uint8_t OP_DIGIT5 = 6; 31 | constexpr uint8_t OP_DIGIT6 = 7; 32 | constexpr uint8_t OP_DIGIT7 = 8; 33 | constexpr uint8_t OP_DECODEMODE = 9; 34 | constexpr uint8_t OP_INTENSITY = 10; 35 | constexpr uint8_t OP_SCANLIMIT = 11; 36 | constexpr uint8_t OP_SHUTDOWN = 12; 37 | constexpr uint8_t OP_DISPLAYTEST = 15; 38 | } 39 | 40 | // Software-SPI constructor 41 | CoreMax72xx::CoreMax72xx(uint8_t data, uint8_t clk, uint8_t cs, uint8_t ind, uint16_t cascadeSize) : 42 | _pins(data, clk, cs), 43 | _index(ind), 44 | _cascadeSize(cascadeSize) 45 | { 46 | _initialize(); 47 | } 48 | 49 | // HardWare-SPI constructor 50 | CoreMax72xx::CoreMax72xx(uint8_t cs, uint8_t ind, uint16_t cascadeSize, bool) : 51 | _pins(cs), 52 | _index(ind), 53 | _cascadeSize(cascadeSize), 54 | _isHardwareSPI(true) 55 | { 56 | // initialize SPI: 57 | SPI.setBitOrder(MSBFIRST); 58 | SPI.setDataMode(SPI_MODE0); 59 | SPI.begin(); 60 | 61 | _initialize(); 62 | } 63 | 64 | // Initialize the chip 65 | void CoreMax72xx::_initialize() 66 | { 67 | _pins.latch(); 68 | 69 | _spiTransfer(OP_DISPLAYTEST, 0); 70 | //scanlimit is set to max on startup 71 | _setScanLimit(_limit - uint8_t(1)); 72 | //decode is done in source 73 | _spiTransfer(OP_DECODEMODE, 0); 74 | 75 | // Clear display on startup 76 | // and fill the _status array by zeros 77 | clear(); 78 | //we go into wakeup-mode on startup 79 | wakeup(); 80 | } 81 | 82 | 83 | // Set the shutdown (power saving) mode for the device 84 | void CoreMax72xx::shutdown() const 85 | { 86 | _spiTransfer(OP_SHUTDOWN, 0); 87 | } 88 | 89 | // Set the wakeup mode for the device 90 | void CoreMax72xx::wakeup() const 91 | { 92 | _spiTransfer(OP_SHUTDOWN, 1); 93 | } 94 | 95 | // Set the brightness of the display. 96 | void CoreMax72xx::setIntensity(uint8_t intensity) const 97 | { 98 | _spiTransfer(OP_INTENSITY, intensity % _maxIntensity); 99 | } 100 | 101 | // Switch all LEDs on the display to off. 102 | void CoreMax72xx::clear() 103 | { 104 | for(auto &row: _rows) { 105 | _status[row] = 0; 106 | _spiTransfer(row + 1, _status[row]); 107 | } 108 | } 109 | 110 | // Switch all LEDs on the display to on. 111 | void CoreMax72xx::fill() 112 | { 113 | for(auto &row: _rows) { 114 | _status[row] = 0b11111111; 115 | _spiTransfer(row + 1, _status[row]); 116 | } 117 | } 118 | 119 | // 120 | // Setters: 121 | // 122 | 123 | // Set the status of a single LED. 124 | void CoreMax72xx::set(const Row &row, const Col &col, bool state) 125 | { 126 | _status[row][col] = state; 127 | _spiTransfer(row + 1, _status[row]); 128 | } 129 | 130 | // Set all LEDs in a row to a new state 131 | void CoreMax72xx::setRow(const Row &row, buint8_t value) 132 | { 133 | _status[row] = value; 134 | _spiTransfer(row + 1, _status[row]); 135 | } 136 | 137 | // Set all LEDs in a column to a new state 138 | void CoreMax72xx::setCol(const Col &col, buint8_t value) 139 | { 140 | for(auto &row: _rows) { 141 | set(row, col, value[row]); 142 | } 143 | } 144 | 145 | // 146 | // Getters: 147 | // 148 | 149 | // Get state of LED point on matrix 150 | bool CoreMax72xx::get(const Row &row, const Col &col) const 151 | { 152 | // Return binary value at the intersection of row and column 153 | return _status[row][col]; 154 | } 155 | 156 | // Get the values on row of LED-matrix 157 | buint8_t CoreMax72xx::getRow(const Row &row) const 158 | { 159 | return _status[row]; 160 | } 161 | 162 | // Get the values on colomn of LED-matrix 163 | buint8_t CoreMax72xx::getCol(const Col &col) const 164 | { 165 | buint8_t rez = 0; 166 | for(auto &row: _rows) { 167 | rez[row] = get(row, col); 168 | } 169 | return rez; 170 | } 171 | 172 | // 173 | // Private methods: 174 | // 175 | 176 | // SPI transaction 177 | void CoreMax72xx::_spiTransfer(uint8_t opcode, uint8_t data) const 178 | { 179 | //Create an array with the data to shift out 180 | const uint8_t offset = _index * 2; 181 | const uint16_t maxbytes = _cascadeSize * 2; 182 | 183 | // The array for shifting the data to the devices 184 | uint8_t _spidata[maxbytes]; 185 | 186 | for(uint8_t i = 0; i < maxbytes; i++) { 187 | _spidata[i] = 0; 188 | } 189 | 190 | //put our device data into the array 191 | _spidata[offset+1] = opcode; 192 | _spidata[offset] = data; 193 | 194 | //enable the line 195 | _pins.enable(); 196 | 197 | //Shift out the data 198 | if(_isHardwareSPI) { 199 | SPI.beginTransaction(SPISettings(100000000, MSBFIRST, SPI_MODE0)); 200 | for(uint8_t i = maxbytes; i > 0; i--) { 201 | SPI.transfer(_spidata[i-1]); 202 | } 203 | SPI.endTransaction(); 204 | } else { 205 | for(uint8_t i = maxbytes; i > 0; i--) { 206 | // Software SPI transfer 207 | _pins.transfer(_spidata[i-1]); 208 | } 209 | } 210 | 211 | //latch the data onto the display 212 | _pins.latch(); 213 | } 214 | 215 | 216 | void CoreMax72xx::_setScanLimit(uint8_t limit) const 217 | { 218 | _spiTransfer(OP_SCANLIMIT, max(limit, uint8_t(_limit - 1) )); 219 | } 220 | -------------------------------------------------------------------------------- /src/CoreMax72xx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * CoreMax72xx this is a class to direct interaction with a controller MAX72xx 4 | * 5 | * @author Valeriy V Dmitriev aka valmat , http://valmat.ru/ 6 | * @licenses MIT https://opensource.org/licenses/MIT 7 | * @repo https://github.com/valmat/LedMatrix 8 | * 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "Arduino.h" 14 | #include "RowCol.h" 15 | #include "RowColIterator.h" 16 | #include "BitInt.h" 17 | #include "DirectInteract.h" 18 | 19 | 20 | class CoreMax72xx 21 | { 22 | public: 23 | 24 | // Software-SPI constructor 25 | // @param dataPin pin on the Arduino where data gets shifted out (DIN) 26 | // @param clockPin pin for the clock (CLK) 27 | // @param csPin pin for selecting the device (CS -- chip select pin) 28 | // @param ind index in the devises cascade, if the devise is placed in cascade 29 | // @param cascadeSize count of devices in cascade, if the devise is placed in a cascade 30 | CoreMax72xx(uint8_t dataPin, uint8_t clockPin, uint8_t csPin, uint8_t ind, uint16_t cascadeSize); 31 | 32 | CoreMax72xx(uint8_t dataPin, uint8_t clockPin, uint8_t csPin) : 33 | CoreMax72xx(dataPin, clockPin, csPin, 0, 1) 34 | {} 35 | 36 | // HardWare-SPI constructor 37 | // @param csPin pin for selecting the device (CS -- chip select pin) 38 | // @param ind index in the devises cascade, if the devise is placed in cascade 39 | // @param cascadeSize count of devices in cascade, if the devise is placed in a cascade 40 | CoreMax72xx(uint8_t csPin, uint8_t ind, uint16_t cascadeSize, bool); 41 | 42 | CoreMax72xx(uint8_t csPin) : 43 | CoreMax72xx(csPin, 0, 1, true) 44 | {} 45 | 46 | // Empty constructor 47 | CoreMax72xx() {} 48 | 49 | 50 | // Copy & Move constructors 51 | CoreMax72xx( const CoreMax72xx& ) = default; 52 | CoreMax72xx( CoreMax72xx&& ) = default; 53 | // Copy & Move assigment 54 | CoreMax72xx& operator=(const CoreMax72xx&) = default; 55 | CoreMax72xx& operator=(CoreMax72xx &&) = default; 56 | 57 | // Set the shutdown (power saving) mode for the device 58 | void shutdown() const; 59 | 60 | // Set the wakeup mode for the device 61 | void wakeup() const; 62 | 63 | // Set the brightness of the display. 64 | // @param intensity the brightness of the display. (0..15) 65 | void setIntensity(uint8_t intensity) const; 66 | 67 | // Switch all LEDs on the display to off. 68 | void clear(); 69 | 70 | // Switch all LEDs on the display to on. 71 | void fill(); 72 | 73 | 74 | // Set the status of a single LED. 75 | // @param Row row the row of the Led (0..7) 76 | // @param Col col the column of the Led (0..7) 77 | // @param state If true the led is switched on, if false it is switched off 78 | void set(const Row &row, const Col &col, bool state); 79 | 80 | // Set all LEDs in a row to a new state 81 | // @param row which is to be set (0..7) 82 | // @param value each bit set to 1 will light up the corresponding LED. 83 | void setRow(const Row &row, buint8_t value); 84 | 85 | // Set all LEDs in a column to a new state 86 | // @param col -- column which is to be set (0..7) 87 | // @param value -- each bit set to 1 will light up the corresponding LED. 88 | void setCol(const Col &col, buint8_t value); 89 | 90 | 91 | // Get state of LED point on matrix 92 | // @param row the row of the Led (0..7) 93 | // @param col the column of the Led (0..7) 94 | bool get(const Row &row, const Col &col) const; 95 | 96 | // Get the values on row of LED-matrix 97 | // @param row the row of the Led (0..7) 98 | buint8_t getRow(const Row &row) const; 99 | 100 | // Get the values on colomn of LED-matrix 101 | // @param col the column of the Led (0..7) 102 | buint8_t getCol(const Col &col) const; 103 | 104 | 105 | // get device index in cascade 106 | uint8_t index() const 107 | { 108 | return _index; 109 | } 110 | 111 | 112 | // Make rows and colomns iterable 113 | RowsIterator rows() const 114 | { 115 | return _rows; 116 | } 117 | ColsIterator cols() const 118 | { 119 | return _cols; 120 | } 121 | 122 | 123 | private: 124 | 125 | // Set the number of digits (or rows) to be displayed. 126 | // See datasheet for sideeffects of the scanlimit on the brightness 127 | // of the display. 128 | // @param limit number of digits to be displayed (1..8) 129 | void _setScanLimit(uint8_t limit) const; 130 | 131 | // Send out a single command to the device 132 | void _spiTransfer(uint8_t opcode, uint8_t data) const; 133 | 134 | // Initialize the chip 135 | void _initialize(); 136 | 137 | 138 | protected: 139 | 140 | // Rows and colomns iterators 141 | RowsIterator _rows{}; 142 | ColsIterator _cols{}; 143 | 144 | // Size of matrix (the length of the row and column of a square matrix) 145 | constexpr static uint8_t _size = 8; 146 | 147 | 148 | private: 149 | 150 | // The maximum number of matrices 151 | constexpr static uint8_t _limit = 8; 152 | 153 | // The maximum of posible intensity 154 | constexpr static uint8_t _maxIntensity = 16; 155 | 156 | // This array contains the statuses of all points of LED matrix 157 | buint8_t _status[_size]; 158 | 159 | // Pins interactor 160 | DirectInteract _pins; 161 | 162 | // If the matrix is placed in cascade, _index is a index in the cascade. 163 | uint8_t _index = 0; 164 | 165 | // If the matrix is placed in a cascade, cascadeSize is count of devices. 166 | uint16_t _cascadeSize = 1; 167 | 168 | bool _isHardwareSPI = false; 169 | }; 170 | 171 | -------------------------------------------------------------------------------- /src/DirectInteract.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * DirectInteract this is a helper class to direct interaction with a set of Arduino pins. 4 | * 5 | * @author Valeriy V Dmitriev aka valmat 6 | * @coauthor Nikolai Tikhonov aka Dragon_Knight , https://vk.com/globalzone_edev 7 | * @licenses MIT https://opensource.org/licenses/MIT 8 | * @repo https://github.com/valmat/LedMatrix 9 | * 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "DirectPin.h" 15 | 16 | class DirectInteract 17 | { 18 | public: 19 | DirectInteract(uint8_t dataPin, uint8_t clockPin, uint8_t csPin) : 20 | _data(dataPin, OUTPUT), 21 | _clock(clockPin, OUTPUT), 22 | _cs(csPin, OUTPUT) 23 | {} 24 | 25 | // Simplified constructor. For hardware SPI. 26 | DirectInteract(uint8_t csPin) : 27 | _cs(csPin, OUTPUT) 28 | {} 29 | 30 | // Empty constructor 31 | DirectInteract() {} 32 | 33 | // Enable the line 34 | void enable() const 35 | { 36 | _cs.off(); 37 | } 38 | 39 | // Latch the data into chip 40 | void latch() const 41 | { 42 | _cs.on(); 43 | } 44 | 45 | void transfer(uint8_t data) const 46 | { 47 | _data.shiftOut(_clock, data); 48 | } 49 | 50 | private: 51 | 52 | // A pin on the Arduino where data gets shifted out (DIN). 53 | // Data is shifted out of this pin 54 | DirectPin _data; 55 | 56 | // The clock is signaled on this pin (CLK) 57 | DirectPin _clock; 58 | 59 | // This one is driven LOW for chip selection (CS) 60 | DirectPin _cs; 61 | }; 62 | -------------------------------------------------------------------------------- /src/DirectPin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * DirectPin this is a helper class to direct manipulation pins bypassing additional checks. 4 | * The purpose of this class is to increase speed by eliminating unnecessary in this case checks. 5 | * Not all methods are implemented, but only those that are needed within the library. 6 | * 7 | * @author Valeriy V Dmitriev aka valmat 8 | * @coauthor Nikolai Tikhonov aka Dragon_Knight , https://vk.com/globalzone_edev 9 | * @licenses MIT https://opensource.org/licenses/MIT 10 | * @repo https://github.com/valmat/LedMatrix 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "Arduino.h" 17 | 18 | class DirectPin 19 | { 20 | public: 21 | 22 | // Constructor 23 | DirectPin(uint8_t pinNom) 24 | // : 25 | // _baseReg( portInputRegister( digitalPinToPort(pinNom) ) ), 26 | // _bitMask( (uint8_t)digitalPinToBitMask((uint8_t)pinNom) ) 27 | { 28 | _baseReg = reinterpret_cast(portInputRegister( 29 | digitalPinToPort(pinNom) 30 | )); 31 | _bitMask = (uint8_t)digitalPinToBitMask((uint8_t)pinNom); 32 | } 33 | 34 | // Сonstructor initializes the pins as a mode 35 | DirectPin(uint8_t pinNom, uint8_t mode) : 36 | DirectPin(pinNom) 37 | { 38 | setMode(mode); 39 | } 40 | 41 | // Empty constructor 42 | DirectPin() : 43 | _baseReg(nullptr), 44 | _bitMask(0) 45 | {} 46 | 47 | // Directly set mode as `OUTPUT` 48 | void modeOut(bool mode) const 49 | { 50 | *(_baseReg + 1) |= _bitMask; 51 | } 52 | 53 | // Directly set mode as `INPUT` 54 | void modeIn() const 55 | { 56 | *(_baseReg + 1) &= ~_bitMask; 57 | } 58 | 59 | // Directly set mode as `OUTPUT` 60 | void modeOut() const 61 | { 62 | *(_baseReg + 1) |= _bitMask; 63 | } 64 | 65 | // Directly set mode 66 | void setMode(uint8_t mode) const 67 | { 68 | if(OUTPUT == mode) { 69 | modeOut(); 70 | } else { 71 | modeIn(); 72 | } 73 | } 74 | 75 | // Directly turn the pin to `HIGH` voltage level 76 | void on() const 77 | { 78 | *(_baseReg + 2) |= _bitMask; 79 | } 80 | 81 | // Directly turn the pin off by making the voltage level `LOW` 82 | void off() const 83 | { 84 | *(_baseReg + 2) &= ~_bitMask; 85 | } 86 | 87 | // turn the pin to a value 88 | void turn(bool value) const 89 | { 90 | if(value) { 91 | on(); 92 | } else { 93 | off(); 94 | } 95 | } 96 | 97 | // Shifts out a byte of data one bit at a time 98 | // bitOrder == MSBFIRST 99 | void shiftOut(const DirectPin &clock, uint8_t val) const 100 | { 101 | for(uint8_t i = 0; i < 8; ++i) { 102 | turn(val & (1 << (7 - i))); 103 | clock.on(); 104 | clock.off(); 105 | } 106 | } 107 | 108 | // Shifts out a byte of data one bit at a time 109 | // bitOrder == LSBFIRST 110 | void shiftOutRe(const DirectPin &clock, uint8_t val) const 111 | { 112 | for(uint8_t i = 0; i < 8; ++i) { 113 | turn(val & (1 << i)); 114 | clock.on(); 115 | clock.off(); 116 | } 117 | } 118 | 119 | private: 120 | volatile uint8_t *_baseReg; 121 | uint8_t _bitMask; 122 | }; 123 | -------------------------------------------------------------------------------- /src/LedMatrix.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * LedMatrix is a class to control 8-bit LED matrix on controller MAX7219 and MAX7221. 4 | * This class manages only the LED-matrix, but does it well. 5 | * 6 | * @author Valeriy V Dmitriev aka valmat , http://valmat.ru/ 7 | * @licenses MIT https://opensource.org/licenses/MIT 8 | * @repo https://github.com/valmat/LedMatrix 9 | * 10 | * 11 | */ 12 | 13 | #include "LedMatrix.h" 14 | 15 | void LedMatrix::set(const Row &row, const Col &col, bool state) 16 | { 17 | // Set the value to the desired position depending on the seted rotation value 18 | if( 1 == _rotate ) { 19 | core::set(col, !row, state); 20 | } else if( 2 == _rotate ) { 21 | core::set(!row, !col, state); 22 | } else if( 3 == _rotate ) { 23 | core::set(!col, row, state); 24 | } else { // If _rotate == 0 25 | core::set(row, col, state); 26 | } 27 | } 28 | 29 | // Set all LEDs in a row to a new state 30 | void LedMatrix::set(const Row &row, buint8_t value) 31 | { 32 | // Set the value to the desired position depending on the seted rotation value 33 | if( 1 == _rotate ) { 34 | core::setCol(!row, value); 35 | } else if( 2 == _rotate ) { 36 | core::setRow(!row, !value); 37 | } else if( 3 == _rotate ) { 38 | core::setCol(row, !value); 39 | } else { // If _rotate == 0 40 | core::setRow(row, value); 41 | } 42 | } 43 | 44 | // Set all LEDs in a column to a new state 45 | void LedMatrix::set(const Col &col, buint8_t value) 46 | { 47 | // Set the value to the desired position depending on the seted rotation value 48 | if( 1 == _rotate ) { 49 | core::setRow(col, !value); 50 | } else if( 2 == _rotate ) { 51 | core::setCol(!col, !value); 52 | } else if( 3 == _rotate ) { 53 | core::setRow(!col, value); 54 | } else { // If _rotate == 0 55 | core::setCol(col, value); 56 | } 57 | } 58 | 59 | // Allows to initialize the values of all points of the matrix 60 | void LedMatrix::set(const uint8_t arr[]) 61 | { 62 | for(auto &row: _rows) { 63 | set(row, arr[row]); 64 | } 65 | } 66 | 67 | // Get state of LED point on matrix 68 | bool LedMatrix::get(const Row &row, const Col &col) const 69 | { 70 | // Get the value to the desired position depending on the seted rotation value 71 | if( 1 == _rotate ) { 72 | return core::get(col, !row); 73 | } else if( 2 == _rotate ) { 74 | return core::get(!row, !col); 75 | } else if( 3 == _rotate ) { 76 | return core::get(!col, row); 77 | } else { // If _rotate == 0 78 | return core::get(row, col); 79 | } 80 | } 81 | 82 | // Get the values on row of LED-matrix 83 | buint8_t LedMatrix::get(const Row &row) const 84 | { 85 | // Set the value to the desired position depending on the seted rotation value 86 | if( 1 == _rotate ) { 87 | return core::getCol(!row); 88 | } else if( 2 == _rotate ) { 89 | return !core::getRow(!row); 90 | } else if( 3 == _rotate ) { 91 | return !core::getCol(row); 92 | } else { // If _rotate == 0 93 | return core::getRow(row); 94 | } 95 | } 96 | 97 | // Get the values on colomn of LED-matrix 98 | buint8_t LedMatrix::get(const Col &col) const 99 | { 100 | // Set the value to the desired position depending on the seted rotation value 101 | if( 1 == _rotate ) { 102 | return !core::getRow(col); 103 | } else if( 2 == _rotate ) { 104 | return !core::getCol(!col); 105 | } else if( 3 == _rotate ) { 106 | return core::getRow(!col); 107 | } else { // If _rotate == 0 108 | return core::getCol(col); 109 | } 110 | } 111 | 112 | // Invert all points of matrix 113 | void LedMatrix::invert() 114 | { 115 | for(auto &row: _rows) { 116 | // Using core methods is more effecient 117 | core::setRow(row, ~core::getRow(row)); 118 | } 119 | } 120 | 121 | // Invert current point on matrix 122 | void LedMatrix::invert(const Row &row, const Col &col) 123 | { 124 | set(row, col, !get(row, col)); 125 | } 126 | 127 | // Invert row on matrix 128 | void LedMatrix::invert(const Row &row) 129 | { 130 | set(row, ~get(row)); 131 | } 132 | 133 | // Invert colomn on matrix 134 | void LedMatrix::invert(const Col &col) 135 | { 136 | set(col, ~get(col)); 137 | } 138 | 139 | // Shift matrix 140 | buint8_t LedMatrix::shiftUp(buint8_t value) 141 | { 142 | buint8_t rez = getRow(0); 143 | for(uint8_t i = 0; i < _size-1; i++) { 144 | setRow(i, getRow(i+1)); 145 | } 146 | setRow(_size-1, value); 147 | return rez; 148 | } 149 | 150 | buint8_t LedMatrix::shiftDown(buint8_t value) 151 | { 152 | buint8_t rez = getRow(_size-1); 153 | for(uint8_t i = _size-1; i > 0; i--) { 154 | setRow(i, getRow(i-1)); 155 | } 156 | setRow(0, value); 157 | return rez; 158 | } 159 | 160 | buint8_t LedMatrix::shiftLeft(buint8_t value) 161 | { 162 | buint8_t rez = getCol(0); 163 | for(uint8_t i = 0; i < _size-1; i++) { 164 | setCol(i, getCol(i+1)); 165 | } 166 | setCol(_size-1, value); 167 | return rez; 168 | } 169 | 170 | buint8_t LedMatrix::shiftRight(buint8_t value) 171 | { 172 | buint8_t rez = getCol(_size-1); 173 | for(uint8_t i = _size-1; i > 0; i--) { 174 | setCol(i, getCol(i-1)); 175 | } 176 | setCol(0, value); 177 | return rez; 178 | } 179 | 180 | 181 | -------------------------------------------------------------------------------- /src/LedMatrix.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * LedMatrix is a class to control 8-bit LED matrix on controller MAX7219 and MAX7221. 4 | * This class manages only the LED-matrix, but does it well. 5 | * 6 | * @author Valeriy V Dmitriev aka valmat , http://valmat.ru/ 7 | * @licenses MIT https://opensource.org/licenses/MIT 8 | * @repo https://github.com/valmat/LedMatrix 9 | * 10 | * 11 | */ 12 | 13 | #pragma once 14 | 15 | #include "Arduino.h" 16 | #include "RowCol.h" 17 | #include "RowColIterator.h" 18 | #include "CoreMax72xx.h" 19 | #include "initializer_list.h" 20 | #include "move.h" 21 | 22 | // forward declaration 23 | template 24 | class MatrixCascade; 25 | 26 | 27 | class LedMatrix : public CoreMax72xx 28 | { 29 | 30 | using core = CoreMax72xx; 31 | 32 | public: 33 | 34 | // Software-SPI Constructor 35 | // @param dataPin pin on the Arduino where data gets shifted out (DIN) 36 | // @param clockPin pin for the clock (CLK) 37 | // @param csPin pin for selecting the device (CS - chip select pin) 38 | LedMatrix(uint8_t data, uint8_t clk, uint8_t cs) : 39 | LedMatrix(data, clk, cs, 0, 1) 40 | {} 41 | 42 | // HardWare-SPI Constructor 43 | // @param csPin pin for selecting the device (CS -- chip select pin) 44 | LedMatrix(uint8_t cs) : 45 | LedMatrix(cs, 0, 1, true) 46 | {} 47 | 48 | // Copy & Move constructors 49 | LedMatrix( const LedMatrix& ) = delete; 50 | LedMatrix( LedMatrix&& ) = default; 51 | // Copy & Move assigment 52 | LedMatrix& operator=(const LedMatrix&) = delete; 53 | LedMatrix& operator=(LedMatrix &&) = default; 54 | 55 | 56 | // Set the status of a single LED. 57 | // @param Row row the row of the Led (0..7) 58 | // @param Col col the column of the Led (0..7) 59 | // @param state If true the led is switched on, if false it is switched off 60 | void set(const Row &row, const Col &col, bool state); 61 | 62 | // Turn on LED at a point 63 | // @param Row row the row of the Led (0..7) 64 | // @param Col col the column of the Led (0..7) 65 | void on(const Row &row, const Col &col) 66 | { 67 | set(row, col, true); 68 | } 69 | // Turn off LED at a point 70 | // @param Row row the row of the Led (0..7) 71 | // @param Col col the column of the Led (0..7) 72 | void off(const Row &row, const Col &col) 73 | { 74 | set(row, col, false); 75 | } 76 | 77 | // Set all LEDs in a row to a new state 78 | // @param row which is to be set (0..7) 79 | // @param value each bit set to 1 will light up the corresponding LED. 80 | void set(const Row &row, buint8_t value); 81 | 82 | // Set all LEDs in a column to a new state 83 | // @param col -- column which is to be set (0..7) 84 | // @param value -- each bit set to 1 will light up the corresponding LED. 85 | void set(const Col &col, buint8_t value); 86 | 87 | // Set all LEDs in a row to a new state 88 | // @param row which is to be set (0..7) 89 | // @param value each bit set to 1 will light up the corresponding LED. 90 | void setRow(const Row &row, buint8_t value) 91 | { 92 | set(row, value); 93 | } 94 | 95 | // Set all LEDs in a column to a new state 96 | // @param col -- column which is to be set (0..7) 97 | // @param value -- each bit set to 1 will light up the corresponding LED. 98 | void setCol(const Col &col, buint8_t value) 99 | { 100 | set(col, value); 101 | } 102 | 103 | // Allows to initialize the values of all points of the matrix 104 | // @param initializer_list instance 105 | template 106 | void set(const std::initializer_list &disp) 107 | { 108 | uint8_t rowNom = 0; 109 | for (auto &&rowVal : disp) { 110 | setRow(rowNom++, rowVal); 111 | } 112 | } 113 | 114 | // Allows to initialize the values of all points of the matrix 115 | // Attention. If you pass an array to this function, strictly follow its length 116 | // @param raw array 117 | void set(const uint8_t arr[]); 118 | 119 | 120 | // Get state of LED point on matrix 121 | // @param row the row of the Led (0..7) 122 | // @param col the column of the Led (0..7) 123 | bool get(const Row &row, const Col &col) const; 124 | 125 | // Get the values on row of LED-matrix 126 | // @param row the row of the Led (0..7) 127 | buint8_t get(const Row &row) const; 128 | 129 | // Get the values on colomn of LED-matrix 130 | // @param col the column of the Led (0..7) 131 | buint8_t get(const Col &col) const; 132 | 133 | // Get the values on row of LED-matrix 134 | // @param row the row of the Led (0..7) 135 | buint8_t getRow(const Row &row) const 136 | { 137 | return get(row); 138 | } 139 | 140 | // Get the values on colomn of LED-matrix 141 | // @param col the column of the Led (0..7) 142 | buint8_t getCol(const Col &col) const 143 | { 144 | return get(col); 145 | } 146 | 147 | 148 | // Invert all points of matrix 149 | void invert(); 150 | 151 | // Invert current point on matrix 152 | // @param row the row of the LED (0..7) 153 | // @param col the column of the LED (0..7) 154 | void invert(const Row &row, const Col &col); 155 | 156 | // Invert row on matrix 157 | // @param row the row of the LED (0..7) 158 | void invert(const Row &row); 159 | 160 | // Invert colomn on matrix 161 | // @param col the column of the LED (0..7) 162 | void invert(const Col &col); 163 | 164 | // Invert row on matrix 165 | // @param row the row of the LED (0..7) 166 | void invertRow(const Row &row) 167 | { 168 | invert(row); 169 | } 170 | 171 | // Invert colomn on matrix 172 | // @param col the column of the LED (0..7) 173 | void invertCol(const Col &col) 174 | { 175 | invert(col); 176 | } 177 | 178 | 179 | // Shift matrix 180 | // @param value is shifting value 181 | // @return shifted value 182 | buint8_t shiftUp(buint8_t value = 0); 183 | buint8_t shiftDown(buint8_t value = 0); 184 | buint8_t shiftLeft(buint8_t value = 0); 185 | buint8_t shiftRight(buint8_t value = 0); 186 | 187 | 188 | // Set how many times to rotate the matrix clockwise 189 | // @param From 0 to 3 190 | void setRotation(uint8_t times = 1) 191 | { 192 | _rotate += times; 193 | _rotate = _rotate % 4; 194 | } 195 | 196 | // Reset rotation flag to default 197 | void resetRotation() 198 | { 199 | _rotate = 0; 200 | } 201 | 202 | // Get how many times the matrix was rotated clockwise 203 | uint8_t getRotation() const 204 | { 205 | return _rotate; 206 | } 207 | 208 | 209 | // get device index in cascade 210 | uint16_t index() const 211 | { 212 | return _index; 213 | } 214 | 215 | 216 | private: 217 | 218 | // set device index in cascade 219 | void index(uint16_t ind) 220 | { 221 | _index = ind; 222 | } 223 | 224 | // Private empty constructor 225 | // Only MatrixCascade can use it 226 | LedMatrix() {} 227 | 228 | // Private Software-SPI Constructor 229 | // Only MatrixCascade can use it 230 | // @param dataPin pin on the Arduino where data gets shifted out (DIN) 231 | // @param clockPin pin for the clock (CLK) 232 | // @param csPin pin for selecting the device (CS -- chip select pin) 233 | // @param ind index in the devises cascade, if the devise is placed in cascade 234 | // @param cascadeSize count of devices in cascade, if the devise is placed in a cascade 235 | LedMatrix(uint8_t data, uint8_t clk, uint8_t cs, uint8_t ind, uint16_t cascadeSize) : 236 | core(data, clk, cs, ind, cascadeSize), 237 | _index(ind) 238 | {} 239 | 240 | // Private HardWare-SPI Constructor 241 | // Only MatrixCascade can use it 242 | // @param csPin pin for selecting the device (CS -- chip select pin) 243 | // @param ind index in the devises cascade, if the devise is placed in cascade 244 | // @param cascadeSize count of devices in cascade, if the devise is placed in a cascade 245 | LedMatrix(uint8_t cs, uint8_t ind, uint16_t cascadeSize, bool) : 246 | core(cs, ind, cascadeSize, true), 247 | _index(ind) 248 | {} 249 | 250 | private: 251 | // Rotate index. How many times to rotate the matrix clockwise 252 | uint8_t _rotate = 0; 253 | 254 | // If the matrix is placed in cascade, _index is a index in the cascade. 255 | // The variable _index is already in the parent class CoreMax72xx. 256 | // But we can not use it, if cascade is united in supercascade. 257 | // Therefore, this class contains its own variable _index 258 | uint16_t _index = 0; 259 | 260 | 261 | template 262 | friend class MatrixCascade; 263 | }; 264 | 265 | 266 | -------------------------------------------------------------------------------- /src/MatrixCascade.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * MatrixCascade is a class to easy control LED matrixes that are combined in a cascade. 4 | * 5 | * @author Valeriy V Dmitriev aka valmat , http://valmat.ru/ 6 | * @licenses MIT https://opensource.org/licenses/MIT 7 | * @repo https://github.com/valmat/LedMatrix 8 | * 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "LedMatrix.h" 14 | #include "Traits.h" 15 | 16 | 17 | template 18 | class MatrixCascade { 19 | public: 20 | 21 | // Software-SPI Constructor 22 | // @param dataPin pin on the Arduino where data gets shifted out 23 | // @param clockPin pin for the clock 24 | // @param csPin pin for selecting the device (chip select pin) 25 | MatrixCascade(uint8_t data, uint8_t clk, uint8_t cs) 26 | { 27 | // Fill cascade on startup 28 | for(uint16_t i = 0; i < cascadeSize; i++) { 29 | matrixes[i] = LedMatrix(data, clk, cs, i, cascadeSize); 30 | } 31 | } 32 | 33 | // HardWare-SPI Constructor 34 | // @param csPin pin for selecting the device (CS -- chip select pin) 35 | MatrixCascade(uint8_t cs) 36 | { 37 | // Fill cascade on startup 38 | for(uint16_t i = 0; i < cascadeSize; i++) { 39 | matrixes[i] = LedMatrix(cs, i, cascadeSize, true); 40 | } 41 | } 42 | 43 | // A template constructor that allows to join several cascades in one 44 | template 45 | MatrixCascade(MatrixCascade&& arg0, MatrixCascade&& ...args) 46 | { 47 | static_assert(cascadeSize == SumTrait::sum, 48 | "Inconsistency sizes. cascadeSize should be the sum of the cascadeSize of its arguments."); 49 | 50 | _fillBySubCascades(0, std::move(arg0), std::move(args)...); 51 | } 52 | 53 | // Copy & Move constructors 54 | MatrixCascade( const MatrixCascade& ) = delete; 55 | MatrixCascade( MatrixCascade&& ) = default; 56 | // Copy & Move assigment 57 | MatrixCascade& operator=(const MatrixCascade&) = delete; 58 | MatrixCascade& operator=(MatrixCascade &&) = default; 59 | 60 | 61 | // Returns the number of devices on this MatrixCascade 62 | constexpr uint16_t size() const 63 | { 64 | return cascadeSize; 65 | } 66 | 67 | // This can be used for accessing to the LedMatrix arrays 68 | // @param index -- index of matrix in cascade 69 | LedMatrix& get(uint16_t index) 70 | { 71 | return matrixes[ ( (index < cascadeSize) ? index : 0 ) ]; 72 | } 73 | 74 | // Array access operator 75 | // This can be used for accessing to the LedMatrix arrays 76 | // @param index -- index of matrix in cascade 77 | LedMatrix& operator[](uint16_t index) 78 | { 79 | return get(index); 80 | } 81 | 82 | // 83 | // Group methods: 84 | // 85 | 86 | // Set the shutdown (power saving) mode for all devices 87 | void shutdown() const 88 | { 89 | for(auto &matrix: *this) { 90 | matrix.shutdown(); 91 | } 92 | } 93 | 94 | // Set the wakeup mode for all devices 95 | void wakeup() const 96 | { 97 | for(const auto &matrix: *this) { 98 | matrix.wakeup(); 99 | } 100 | } 101 | 102 | // Set the brightness of all displays. 103 | // @param intensity the brightness of the display. (0..15) 104 | void setIntensity(uint8_t intensity) const 105 | { 106 | for(const auto &matrix: *this) { 107 | matrix.setIntensity(intensity); 108 | } 109 | } 110 | 111 | // Switch all LEDs on all displays to off. 112 | void clear() 113 | { 114 | for(auto &matrix: *this) { 115 | matrix.clear(); 116 | } 117 | } 118 | 119 | // Switch all LEDs on all displays to on. 120 | void fill() 121 | { 122 | for(auto &matrix: *this) { 123 | matrix.fill(); 124 | } 125 | } 126 | 127 | // Invert all points of all matrixes 128 | void invert() 129 | { 130 | for(auto &matrix: *this) { 131 | matrix.invert(); 132 | } 133 | } 134 | 135 | // How many times to rotate all matrixes clockwise 136 | // @param From 0 to 3 137 | void setRotation(uint8_t times = 1) 138 | { 139 | for(auto &matrix: *this) { 140 | matrix.setRotation(times); 141 | } 142 | } 143 | 144 | // Reset rotation flag for all matrixes to default 145 | void resetRotation() 146 | { 147 | for(auto &matrix: *this) { 148 | matrix.resetRotation(); 149 | } 150 | } 151 | 152 | // 153 | // Iterator methods: 154 | // 155 | 156 | // Make iterable 157 | LedMatrix* begin() 158 | { 159 | return matrixes; 160 | } 161 | LedMatrix* end() 162 | { 163 | return matrixes + cascadeSize; 164 | } 165 | const LedMatrix* begin() const 166 | { 167 | return matrixes; 168 | } 169 | const LedMatrix* end() const 170 | { 171 | return matrixes + cascadeSize; 172 | } 173 | 174 | private: 175 | 176 | // Helper functions for combining multiple MatrixCascade to one 177 | template 178 | void _fillBySubCascades(uint16_t offset, MatrixCascade&& arg0, MatrixCascade&& ...args) 179 | { 180 | for (uint16_t i = 0; i < N0; ++i) 181 | { 182 | matrixes[offset + i] = std::move(arg0.matrixes[i]); 183 | matrixes[offset + i].index(offset + i); 184 | } 185 | _fillBySubCascades(N0, std::move(args)...); 186 | } 187 | template 188 | void _fillBySubCascades(uint16_t offset, MatrixCascade&& arg0) 189 | { 190 | for (uint16_t i = 0; i < N0; ++i) 191 | { 192 | matrixes[offset + i] = std::move(arg0.matrixes[i]); 193 | matrixes[offset + i].index(offset + i); 194 | } 195 | } 196 | 197 | 198 | private: 199 | 200 | // Size of matrix (the length of the row and column of a square matrix) 201 | constexpr static uint8_t _matrixSize = 8; 202 | 203 | // The maximum number of matrices 204 | constexpr static uint8_t _matrixLimit = 8; 205 | 206 | // Cascade array 207 | LedMatrix matrixes[cascadeSize]; 208 | 209 | 210 | template 211 | friend class MatrixCascade; 212 | }; 213 | 214 | template 215 | constexpr MatrixCascade< SumTrait::sum > 216 | combineCascades(MatrixCascade&& arg0, MatrixCascade&& ...args) 217 | { 218 | return MatrixCascade< SumTrait::sum >(std::move(arg0), std::move(args)...); 219 | } -------------------------------------------------------------------------------- /src/RowCol.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * RowCol is a generic name for the two classes. Row and Col. 4 | * These classes are for convenient control the rows and columns 5 | * of the LED matrix using thr LedMatrix class. 6 | * 7 | * @author Valeriy V Dmitriev aka valmat , http://valmat.ru/ 8 | * @licenses MIT https://opensource.org/licenses/MIT 9 | * @repo https://github.com/valmat/LedMatrix 10 | * 11 | */ 12 | 13 | #pragma once 14 | 15 | // Forward declaration 16 | template 17 | struct RowColIterator; 18 | 19 | 20 | template 21 | class RowCol { 22 | public: 23 | // Constructor 24 | constexpr RowCol(uint8_t nom) : 25 | // If out of matrix range 26 | _valid(nom < maxRows), 27 | _nom(_valid ? nom : 0) 28 | {} 29 | 30 | // Copy & Move constructors 31 | constexpr RowCol( const RowCol& that) : 32 | _valid(that._valid), 33 | _nom(that._nom) 34 | {} 35 | constexpr RowCol ( RowCol&& that) : 36 | _valid(that._valid), 37 | _nom(that._nom) 38 | {} 39 | 40 | // if the Row/Col object is valid 41 | constexpr bool isValid() const 42 | { 43 | return _valid; 44 | } 45 | 46 | // Cast to a number 47 | constexpr operator uint8_t () const 48 | { 49 | return _nom; 50 | } 51 | 52 | // Cast to a ... RowCol 53 | // Row -> Col, Col -> Row 54 | template 55 | constexpr operator RowCol () const 56 | { 57 | return RowCol(_nom); 58 | } 59 | 60 | // Reverse operator 61 | constexpr RowCol operator!() const 62 | { 63 | return maxRows - 1 - _nom; 64 | } 65 | 66 | // 67 | // Iterator operators 68 | // Folowing operators needs to RowColIterator 69 | // 70 | 71 | // Increment position (pre-increment) 72 | RowCol &operator++() 73 | { 74 | ++_nom; 75 | return *this; 76 | } 77 | 78 | // Increment position (post-increment) 79 | RowCol operator++(int) 80 | { 81 | RowCol copy(*this); 82 | ++(*this); 83 | return copy; 84 | } 85 | 86 | // Decrement position (pre-decrement) 87 | RowCol &operator--() 88 | { 89 | --_nom; 90 | return *this; 91 | } 92 | 93 | // Increment position (post-decrement) 94 | RowCol operator--(int) 95 | { 96 | RowCol copy(*this); 97 | --(*this); 98 | return copy; 99 | } 100 | 101 | // Compare with other iterator 102 | constexpr bool operator==(const RowCol &rhs) const 103 | { 104 | return (_nom == rhs._nom); 105 | } 106 | 107 | // Compare with other iterator 108 | constexpr bool operator!=(const RowCol &rhs) const 109 | { 110 | return (_nom != rhs._nom); 111 | } 112 | 113 | // Dereference as a current object 114 | constexpr const RowCol &operator*() const 115 | { 116 | return *this; 117 | } 118 | 119 | private: 120 | // Novalidateble constructor 121 | constexpr RowCol(uint8_t nom, bool valid) : _valid(valid), _nom(nom) {} 122 | 123 | const bool _valid = true; 124 | uint8_t _nom; 125 | 126 | template 127 | friend struct RowColIterator; 128 | }; 129 | 130 | 131 | using Row = RowCol<8, true>; 132 | using Col = RowCol<8, false>; 133 | 134 | -------------------------------------------------------------------------------- /src/RowColIterator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Makes rows and colomns of LedMatrix iterable 4 | * Helper class. 5 | * 6 | * @author Valeriy V Dmitriev aka valmat , http://valmat.ru/ 7 | * @licenses MIT https://opensource.org/licenses/MIT 8 | * @repo https://github.com/valmat/LedMatrix 9 | * 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "RowCol.h" 15 | 16 | template 17 | struct RowColIterator { 18 | // Constructor 19 | constexpr RowColIterator() {} 20 | 21 | constexpr uint8_t size() const 22 | { 23 | return maxRows; 24 | } 25 | 26 | // Make iterable 27 | constexpr RowCol begin() const 28 | { 29 | return RowCol(0, true); 30 | } 31 | constexpr RowCol end() const 32 | { 33 | return RowCol(maxRows, false); 34 | } 35 | }; 36 | 37 | using RowsIterator = RowColIterator<8, true>; 38 | using ColsIterator = RowColIterator<8, false>; 39 | 40 | -------------------------------------------------------------------------------- /src/Traits.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Traits to compile time template calculating 4 | * 5 | * @author Valeriy V Dmitriev aka valmat , http://valmat.ru/ 6 | * @licenses MIT https://opensource.org/licenses/MIT 7 | * @repo https://github.com/valmat/LedMatrix 8 | * 9 | */ 10 | 11 | // SumTrait is a trait to compile time calculate total cascade size 12 | template 13 | struct SumTrait 14 | { 15 | constexpr static int sum = SumTrait::sum + SumTrait::sum; 16 | }; 17 | 18 | template 19 | struct SumTrait 20 | { 21 | constexpr static int sum = N; 22 | }; 23 | 24 | 25 | // SizeTrait is a trait to compile time calculate template integer argument 26 | template 27 | struct SizeTrait; 28 | 29 | template < template class T, int N> 30 | struct SizeTrait< T > 31 | { 32 | constexpr static int size = N; 33 | }; 34 | template 35 | struct SizeTrait 36 | { 37 | constexpr static int size = SizeTrait< typename std::remove_reference::type >::size; 38 | }; -------------------------------------------------------------------------------- /src/initializer_list.h: -------------------------------------------------------------------------------- 1 | // std::initializer_list support -*- C++ -*- 2 | 3 | // Copyright (C) 2008-2013 Free Software Foundation, Inc. 4 | // 5 | // This file is part of GCC. 6 | // 7 | // GCC is free software; you can redistribute it and/or modify 8 | // it under the terms of the GNU General Public License as published by 9 | // the Free Software Foundation; either version 3, or (at your option) 10 | // any later version. 11 | // 12 | // GCC is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | // GNU General Public License for more details. 16 | // 17 | // Under Section 7 of GPL version 3, you are granted additional 18 | // permissions described in the GCC Runtime Library Exception, version 19 | // 3.1, as published by the Free Software Foundation. 20 | 21 | // You should have received a copy of the GNU General Public License and 22 | // a copy of the GCC Runtime Library Exception along with this program; 23 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 | // . 25 | 26 | /** @file initializer_list 27 | * This is a Standard C++ Library header. 28 | */ 29 | 30 | #ifndef _INITIALIZER_LIST 31 | #define _INITIALIZER_LIST 32 | 33 | //#pragma GCC system_header 34 | 35 | 36 | //#pragma GCC visibility push(default) 37 | 38 | //#include 39 | 40 | namespace std 41 | { 42 | /// initializer_list 43 | template 44 | class initializer_list 45 | { 46 | public: 47 | typedef _E value_type; 48 | typedef const _E& reference; 49 | typedef const _E& const_reference; 50 | typedef size_t size_type; 51 | typedef const _E* iterator; 52 | typedef const _E* const_iterator; 53 | 54 | private: 55 | iterator _M_array; 56 | size_type _M_len; 57 | 58 | // The compiler can call a private constructor. 59 | constexpr initializer_list(const_iterator __a, size_type __l) 60 | : _M_array(__a), _M_len(__l) { } 61 | 62 | public: 63 | constexpr initializer_list() noexcept 64 | : _M_array(0), _M_len(0) { } 65 | 66 | // Number of elements. 67 | constexpr size_type 68 | size() const noexcept { return _M_len; } 69 | 70 | // First element. 71 | constexpr const_iterator 72 | begin() const noexcept { return _M_array; } 73 | 74 | // One past the last element. 75 | constexpr const_iterator 76 | end() const noexcept { return begin() + size(); } 77 | }; 78 | 79 | /** 80 | * @brief Return an iterator pointing to the first element of 81 | * the initilizer_list. 82 | * @param __ils Initializer list. 83 | */ 84 | template 85 | constexpr const _Tp* 86 | begin(initializer_list<_Tp> __ils) noexcept 87 | { return __ils.begin(); } 88 | 89 | /** 90 | * @brief Return an iterator pointing to one past the last element 91 | * of the initilizer_list. 92 | * @param __ils Initializer list. 93 | */ 94 | template 95 | constexpr const _Tp* 96 | end(initializer_list<_Tp> __ils) noexcept 97 | { return __ils.end(); } 98 | } 99 | 100 | //#pragma GCC visibility pop 101 | 102 | 103 | #endif // _INITIALIZER_LIST 104 | -------------------------------------------------------------------------------- /src/move.h: -------------------------------------------------------------------------------- 1 | #ifndef _MOVE 2 | #define _MOVE 3 | 4 | #ifndef _GLIBCXX_TYPE_TRAITS 5 | 6 | namespace std 7 | { 8 | // std::remove_reference 9 | template< class T > struct remove_reference {typedef T type;}; 10 | template< class T > struct remove_reference {typedef T type;}; 11 | template< class T > struct remove_reference {typedef T type;}; 12 | 13 | // std::move 14 | template 15 | constexpr typename remove_reference<_Tp>::type&& 16 | move(_Tp&& __t) noexcept 17 | { return static_cast::type&&>(__t); } 18 | 19 | 20 | /// integral_constant 21 | template 22 | struct integral_constant 23 | { 24 | static constexpr _Tp value = __v; 25 | typedef _Tp value_type; 26 | typedef integral_constant<_Tp, __v> type; 27 | constexpr operator value_type() { return value; } 28 | }; 29 | 30 | template 31 | constexpr _Tp integral_constant<_Tp, __v>::value; 32 | 33 | /// The type used as a compile-time boolean with true value. 34 | typedef integral_constant true_type; 35 | 36 | /// The type used as a compile-time boolean with false value. 37 | typedef integral_constant false_type; 38 | 39 | 40 | 41 | // is_lvalue_reference 42 | template struct is_lvalue_reference : public false_type { }; 43 | template struct is_lvalue_reference<_Tp&> : public true_type { }; 44 | 45 | // std::forward 46 | template 47 | constexpr _Tp&& 48 | forward(typename std::remove_reference<_Tp>::type&& __t) noexcept 49 | { 50 | static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument" 51 | " substituting _Tp is an lvalue reference type"); 52 | return static_cast<_Tp&&>(__t); 53 | } 54 | 55 | } 56 | 57 | #endif // _GLIBCXX_TYPE_TRAITS 58 | 59 | #endif // _MOVE 60 | --------------------------------------------------------------------------------