Освой Arduino играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

LED-матрица 8×8

07.Display: RowColumnScanning
Бегущие огни
Матрица с драйвером MAX7219
Драйвер MAX7219 и библиотека LedControl
Библиотека LEDMatrixDriver

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

Светодиодные матрицы бывают одноцветными, двухцветными и RGB (позволяют получать любой цвет). /p>

Очень популярна разновидность матричного индикатора, имеющего восемь рядов и восемь столбцов с красными или зелёными светодиодами (общее число 64). Все светодиоды в матрице соединены по схеме с общим катодом.

LED-матрица

Принципиальная схема выглядит немного запутано.

LED-матрица 8×8

Fritzing: led matrix display

Если смотреть с обратной стороны матрицы, вывод 1 будет находиться справа внизу. Иногда у вывода можно увидеть маленькую цифру 1. Либо имеется дополнительная выемка на стороне матрицы. Выводы нумеруются в направлении по часовой стрелке (если смотреть со стороны выводов), то есть вывод 8 находится слева внизу, а вывод 16 — справа вверху.

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

LED-матрица 8×8

Пробное подключение

У матрицы шестнадцать выводов, что представляет определённую проблему при прототипировании. Приходится задействовать практически все выводы платы. Но так как все светодиоды в матрице независимы, мы можем поиграться с одной. Соединим матрицу с платой по следующей схеме: вывод 9 от матрицы соединяем с выводом 2 на плате, а вывод 13 от матрицы с GND через резистор.

LED-матрица 8×8

При таком подключении мы задействуем самый верхний левый светодиод матрицы. Запускаем скетч мигания светодиодом Blink, чтобы увидеть работу одного светодиода.

В реальных проектах мы должны соединить все выводы матрицы. Так как их шестнадцать, то кроме цифровых портов нам нужно задействовать и аналоговые, которые могут работать как цифровые. В этом случае порт A0 становится 14, A1 - 15 и т.д. Соединив все выводы матрицы, можно включить нужный светодиод, подавая HIGH на вывод ряда и LOW на вывод столбца. Включим светодиод из второй строки и первой колонки.


// выводы ряда матрицы
const int matrixPin9 = 13;
const int matrixPin14 = 8;
const int matrixPin8 = 17;
const int matrixPin12 = 10;
const int matrixPin1 = 5;
const int matrixPin7 = 16;
const int matrixPin2 = 4;
const int matrixPin5 = 14;

// выводы колонки матрицы
const int matrixPin13 = 9;
const int matrixPin3 = 3;
const int matrixPin4 = 2;
const int matrixPin10 = 12;
const int matrixPin6 = 15;
const int matrixPin11 = 11;
const int matrixPin15 = 7;
const int matrixPin16 = 6;

void setup(){
	pinMode(matrixPin14, OUTPUT);
	pinMode(matrixPin13, OUTPUT);
}

void loop(){
	digitalWrite(matrixPin14, HIGH);
	digitalWrite(matrixPin13, LOW);	
}

07.Display: RowColumnScanning

В состав Android IDE входит пример для светодиодной матрицы File | Examples | 07.Display | RowColumnScanning. Суть в следующем - с помощью двух потенциометров считываем показания с аналоговых выводов в интервале от 0 до 7. Показания от первого потенциометра указывают на вывод из ряда, а от второго на вывод из колонки матрицы. Таким образом, мы можем крутить ручки двух потенциометров и выбирать, какой светодиод из матрицы следует включить.

Я предлагаю упростить пример. Уберём потенциометры и удалим функцию readSensors() из скетча. Теперь, чтобы включить любой светодиод, нужно указать номер ряда и номер колонки в двумерном массиве и подать на него LOW.

Включим светодиоды по диагонали.


// У вас могут быть другие порты платы для подключения.
// A0-A5 это 14, 15, 16, 17, 18, 19

const int row[8] = {
  13, 8, 17, 10, 5, 16, 4, 14
};

// 2-dimensional array of column pin numbers:
const int col[8] = {
  9, 3, 2, 12, 15, 11, 7, 6
};

// 2-dimensional array of pixels:
int pixels[8][8];

// cursor position:
int x = 5;
int y = 5;


void setup() {
	// initialize the I/O pins as outputs iterate over the pins:
	for (int thisPin = 0; thisPin < 8; thisPin++) {
		// initialize the output pins:
		pinMode(col[thisPin], OUTPUT);
		pinMode(row[thisPin], OUTPUT);
		// take the col pins (i.e. the cathodes) high to ensure that the LEDS are off:
		digitalWrite(col[thisPin], HIGH);
	}

	// initialize the pixel matrix:
	for (int x = 0; x < 8; x++) {
		for (int y = 0; y < 8; y++) {
			pixels[x][y] = HIGH;
		}
	}
}

void loop() {
	pixels[0][0] = LOW;
	pixels[1][1] = LOW;
	pixels[2][2] = LOW;
	pixels[3][3] = LOW;
	pixels[4][4] = LOW;
	pixels[5][5] = LOW;
	pixels[6][6] = LOW;
	pixels[7][7] = LOW;

	// draw the screen:
	refreshScreen();
}

void refreshScreen() {
	// iterate over the rows (anodes):
	for (int thisRow = 0; thisRow < 8; thisRow++) {
		// take the row pin (anode) high:
		digitalWrite(row[thisRow], HIGH);
		// iterate over the cols (cathodes):
		for (int thisCol = 0; thisCol < 8; thisCol++) {
			// get the state of the current pixel;
			int thisPixel = pixels[thisRow][thisCol];
			// when the row is HIGH and the col is LOW,
			// the LED where they meet turns on:
			digitalWrite(col[thisCol], thisPixel);
			// turn the pixel off:
			if (thisPixel == LOW) {
				digitalWrite(col[thisCol], HIGH);
			}
		}
		// take the row pin low to turn off the whole row:
		digitalWrite(row[thisRow], LOW);
	}
}

LED Matrix

Бегущие огни

Модифицируем скетч, чтобы создать анимацию бегущих огней (источник).


const int row[8] = {
  13, 8, 17, 10, 5, 16, 4, 14
};

// 2-dimensional array of column pin numbers:
const int col[8] = {
  9, 3, 2, 12, 15, 11, 7, 6
};

// 2-dimensional array of pixels:
int pixels[8][8];

// cursor position:
int posX = 7;
int posY = 7;
int count = 30;
bool bg = false;


void setup() {
	// initialize the I/O pins as outputs iterate over the pins:
	for (int thisPin = 0; thisPin < 8; thisPin++) {
		// initialize the output pins:
		pinMode(col[thisPin], OUTPUT);
		pinMode(row[thisPin], OUTPUT);
		// take the col pins (i.e. the cathodes) high to ensure that the LEDS are off:
		digitalWrite(col[thisPin], HIGH);
	}

	// initialize the pixel matrix:
	/*for (int x = 0; x < 8; x++) {
		for (int y = 0; y < 8; y++) {
			pixels[x][y] = HIGH;
		}
	}*/

	setupScreen();
}

void loop() {
	// draw the screen:
	refreshScreen();

	if (count-- == 0) {
		count = 500;
		if (posX-- == 0) {
			posX = 7;
			if (posY-- == 0) {
				posY = 7;
				bg = !bg;
			}
		}
		setupScreen();

	}
}

void refreshScreen() {
	// iterate over the rows (anodes):
	for (int thisRow = 0; thisRow < 8; thisRow++) {
		// take the row pin (anode) high:
		digitalWrite(row[thisRow], HIGH);
		// iterate over the cols (cathodes):
		for (int thisCol = 0; thisCol < 8; thisCol++) {
			// get the state of the current pixel;
			int thisPixel = pixels[thisRow][thisCol];
			// when the row is HIGH and the col is LOW,
			// the LED where they meet turns on:
			digitalWrite(col[thisCol], thisPixel);
			// turn the pixel off:
			if (thisPixel == LOW) {
				digitalWrite(col[thisCol], HIGH);
			}
		}
		// take the row pin low to turn off the whole row:
		digitalWrite(row[thisRow], LOW);
	}
}

void setupScreen() {
	if (bg) {
		//ON all others
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				pixels[x][y] = LOW;
			}
		}

		//OFF current pos
		pixels[posX][posY] = HIGH;
	}
	else {
		//OFF all others
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				pixels[x][y] = HIGH;
			}
		}

		//ON current pos
		pixels[posX][posY] = LOW;
	}
}

Создаём битовую карту для символов

Можно заранее подготовить некоторые наборы включённых и выключенных светодиодов для отображения символов. Сделаем карту для символов A, B, C, D, E.


const int row[8] = {
  13, 8, 17, 10, 5, 16, 4, 14
};

// 2-dimensional array of column pin numbers:
const int col[8] = {
  9, 3, 2, 12, 15, 11, 7, 6
};

// 2-dimensional array of pixels:
int pixels[8][8];

int count = 1000;

char str[] = "EDCBA";
int strLen = sizeof(str);
int ptrChar = 0;

typedef bool charMapType[8][8];

const charMapType charDummy = {
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0}
};

const charMapType charA = {
  {0, 0, 0, 1, 1, 0, 0, 0},
  {0, 0, 0, 1, 1, 0, 0, 0},
  {0, 0, 1, 0, 0, 1, 0, 0},
  {0, 0, 1, 0, 0, 1, 0, 0},
  {0, 1, 1, 1, 1, 1, 1, 0},
  {0, 1, 0, 0, 0, 0, 1, 0},
  {1, 1, 0, 0, 0, 0, 1, 1},
  {1, 0, 0, 0, 0, 0, 0, 1}
};

const charMapType charB = {
  {1, 1, 1, 1, 1, 1, 0, 0},
  {0, 1, 0, 0, 0, 0, 1, 0},
  {0, 1, 0, 0, 0, 0, 0, 1},
  {0, 1, 1, 1, 1, 1, 1, 0},
  {0, 1, 0, 0, 0, 0, 0, 1},
  {0, 1, 0, 0, 0, 0, 0, 1},
  {0, 1, 0, 0, 0, 0, 1, 0},
  {1, 1, 1, 1, 1, 1, 0, 0}
};

const charMapType charC = {
  {0, 1, 1, 1, 1, 1, 1, 0},
  {1, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 0},
  {1, 0, 0, 0, 0, 0, 0, 0},
  {1, 0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 0, 0, 0, 0, 1},
  {0, 1, 1, 1, 1, 1, 1, 0}
};

const charMapType charD = {
  {1, 1, 1, 1, 1, 1, 1, 0},
  {0, 1, 0, 0, 0, 0, 0, 1},
  {0, 1, 0, 0, 0, 0, 0, 1},
  {0, 1, 0, 0, 0, 0, 0, 1},
  {0, 1, 0, 0, 0, 0, 0, 1},
  {0, 1, 0, 0, 0, 0, 0, 1},
  {0, 1, 0, 0, 0, 0, 0, 1},
  {1, 1, 1, 1, 1, 1, 1, 0}
};

const charMapType charE = {
  {1, 1, 1, 1, 1, 1, 1, 1},
  {0, 1, 0, 0, 0, 0, 0, 0},
  {0, 1, 0, 0, 0, 0, 0, 0},
  {0, 1, 1, 1, 1, 1, 1, 0},
  {0, 1, 0, 0, 0, 0, 0, 0},
  {0, 1, 0, 0, 0, 0, 0, 0},
  {0, 1, 0, 0, 0, 0, 0, 0},
  {1, 1, 1, 1, 1, 1, 1, 1}
};

const charMapType *charMap[5] = { &charA, &charB, &charC, &charD, &charE };

void setup() {
	// initialize the I/O pins as outputs iterate over the pins:
	for (int thisPin = 0; thisPin < 8; thisPin++) {
		// initialize the output pins:
		pinMode(col[thisPin], OUTPUT);
		pinMode(row[thisPin], OUTPUT);
		// take the col pins (i.e. the cathodes) high to ensure that the LEDS are off:
		digitalWrite(col[thisPin], HIGH);
	}

	// initialize the pixel matrix:
	/*for (int x = 0; x < 8; x++) {
		for (int y = 0; y < 8; y++) {
			pixels[x][y] = HIGH;
		}
	}*/

	setupChar();
}

void loop() {
	// draw the screen:
	refreshScreen();

	if (count-- == 0) {
		count = 1000;
		setupChar();
	}
}

void refreshScreen() {
	// iterate over the rows (anodes):
	for (int thisRow = 0; thisRow < 8; thisRow++) {
		// take the row pin (anode) high:
		digitalWrite(row[thisRow], HIGH);
		// iterate over the cols (cathodes):
		for (int thisCol = 0; thisCol < 8; thisCol++) {
			// get the state of the current pixel;
			int thisPixel = pixels[thisRow][thisCol];
			// when the row is HIGH and the col is LOW,
			// the LED where they meet turns on:
			digitalWrite(col[thisCol], thisPixel);
			// turn the pixel off:
			if (thisPixel == LOW) {
				digitalWrite(col[thisCol], HIGH);
			}
		}
		// take the row pin low to turn off the whole row:
		digitalWrite(row[thisRow], LOW);
	}
}

void setupChar() {
	char c = str[ptrChar];
	int offset = c - 'A';

	const charMapType *cMap = charMap[offset];
	//charMapType *cMap = &charDummy;

	for (int x = 0; x < 8; x++) {
		for (int y = 0; y < 8; y++) {
			bool v = (*cMap)[x][y];

			if (v) {
				pixels[x][y] = LOW;
			}
			else {
				pixels[x][y] = HIGH;
			}
		}
	}

	ptrChar++;
	if (ptrChar >= strLen - 1) {
		ptrChar = 0;
	}
}

Источник (с видео)

Управление через сдвиговый регистр

Отдельное подключение каждого вывода матрицы к отдельным выводам платы не слишком удобно. Поэтому применяют сдвиговые регистры. Это тема отдельного разговора.

Находим выводы 1 и 16 с помощью мультиметра

Прозвонка

Если у вашей LED-матрицы нет маркировки, то определить выводы 1 и 16 можно с помощью мультиметра. Включите его в режим прозвонки диодов и приставьте щупы к крайним выводам в разных комбинациях. Одна из комбинаций включит светодиод (5 ряд, 8 столбец). Красный щуп укажет на первый вывод, чёрный - на 16.

Матрица с драйвером MAX7219

Существует более удобный вариант матрицы с драйвером MAX7219 в виде отдельного модуля. Есть полностью готовые модули, а есть вариант, когда детали поставляются в разобранном виде и нужно самостоятельно паять.

MAX7219

Купить на AliExpress

Благодаря применению SPI модуль имеет только пять выводов с двух сторон: питание, земля и три цифровых вывода.


 MAX7219 | Arduino 
------------------
     VCC | 5V 
     GND | GND 
DIN/DOUT | D
      CS | D 
     CLK | D

Модули можно соединять между собой, получая большое табло.

Сначала попробуем вариант включения любого светодиода матрицы вручную. В коде используются несколько функций. Для одиночного модуля вызываем функцию maxSingle(). Если используется несколько модулей, то уберите комментарии с вызовов функций maxAll(), maxOne().

При вызове функции maxSingle() в первом аргументе указываем номер ряда, во втором число в степени двойки - 1, 2, 4, 8 и т.д.


int dataIn = 2; // DIN
int load = 3;  // CS
int clock = 4; // CLK

int maxInUse = 1;    //change this variable to set how many MAX7219's you'll use

int e = 0;           // just a varialble

// define max7219 registers
byte max7219_reg_noop        = 0x00;
byte max7219_reg_digit0      = 0x01;
byte max7219_reg_digit1      = 0x02;
byte max7219_reg_digit2      = 0x03;
byte max7219_reg_digit3      = 0x04;
byte max7219_reg_digit4      = 0x05;
byte max7219_reg_digit5      = 0x06;
byte max7219_reg_digit6      = 0x07;
byte max7219_reg_digit7      = 0x08;
byte max7219_reg_decodeMode  = 0x09;
byte max7219_reg_intensity   = 0x0a;
byte max7219_reg_scanLimit   = 0x0b;
byte max7219_reg_shutdown    = 0x0c;
byte max7219_reg_displayTest = 0x0f;

void putByte(byte data) {
  byte i = 8;
  byte mask;
  while (i > 0) {
    mask = 0x01 << (i - 1);      // get bitmask
    digitalWrite( clock, LOW);   // tick
    if (data & mask) {           // choose bit
      digitalWrite(dataIn, HIGH);// send 1
    } else {
      digitalWrite(dataIn, LOW); // send 0
    }
    digitalWrite(clock, HIGH);   // tock
    --i;                         // move to lesser bit
  }
}

void maxSingle( byte reg, byte col) {
  //maxSingle is the "easy"  function to use for a     //single max7219

  digitalWrite(load, LOW);       // begin
  putByte(reg);                  // specify register
  putByte(col);//((data & 0x01) * 256) + data >> 1); // put data
  digitalWrite(load, LOW);       // and load da shit
  digitalWrite(load, HIGH);
}

void maxAll (byte reg, byte col) {    // initialize  all  MAX7219's in the system
  int c = 0;
  digitalWrite(load, LOW);  // begin
  for ( c = 1; c <= maxInUse; c++) {
    putByte(reg);  // specify register
    putByte(col);//((data & 0x01) * 256) + data >> 1); // put data
  }
  digitalWrite(load, LOW);
  digitalWrite(load, HIGH);
}

void maxOne(byte maxNr, byte reg, byte col) {
  //maxOne is for adressing different MAX7219's,
  //whilele having a couple of them cascaded

  int c = 0;
  digitalWrite(load, LOW);  // begin

  for ( c = maxInUse; c > maxNr; c--) {
    putByte(0);    // means no operation
    putByte(0);    // means no operation
  }

  putByte(reg);  // specify register
  putByte(col);//((data & 0x01) * 256) + data >> 1); // put data

  for ( c = maxNr - 1; c >= 1; c--) {
    putByte(0);    // means no operation
    putByte(0);    // means no operation
  }

  digitalWrite(load, LOW); // and load da shit
  digitalWrite(load, HIGH);
}

void setup () {
  pinMode(dataIn, OUTPUT);
  pinMode(clock,  OUTPUT);
  pinMode(load,   OUTPUT);

  //beginSerial(9600);
  //digitalWrite(13, HIGH);

  //initiation of the max 7219
  maxAll(max7219_reg_scanLimit, 0x07);
  maxAll(max7219_reg_decodeMode, 0x00);  // using an led matrix (not digits)
  maxAll(max7219_reg_shutdown, 0x01);    // not in shutdown mode
  maxAll(max7219_reg_displayTest, 0x00); // no display test
  for (e = 1; e <= 8; e++) { // empty registers, turn all LEDs off
    maxAll(e, 0);
  }
  maxAll(max7219_reg_intensity, 0x0f & 0x0f);    // the first 0x0f is the value you can set
  // range: 0x00 to 0x0f
}

void loop () {
  //if you use just one MAX7219 it should look like this
  maxSingle(1, 128);                      //  + - - - - - - -
  maxSingle(2, 64);                       //  - + - - - - - -
  maxSingle(3, 32);                       //  - - + - - - - -
  maxSingle(4, 16);                       //  - - - + - - - -
  maxSingle(5, 8);                        //  - - - - + - - -
  maxSingle(6, 4);                        //  - - - - - + - -
  maxSingle(7, 2);                        //  - - - - - - + -
  maxSingle(8, 1);                        //  - - - - - - - +


  /*
    //if you use more than one MAX7219, it should look like this

    maxAll(1, 1);                      //  + - - - - - - -
    maxAll(2, 3);                      //  + + - - - - - -
    maxAll(3, 7);                      //  + + + - - - - -
    maxAll(4, 15);                     //  + + + + - - - -
    maxAll(5, 31);                     //  + + + + + - - -
    maxAll(6, 63);                     //  + + + + + + - -
    maxAll(7, 127);                    //  + + + + + + + -
    maxAll(8, 255);                    //  + + + + + + + +


    //if you use more then one max7219 the second one should look like this
    maxOne(2, 1, 1);                     //  + - - - - - - -
    maxOne(2, 2, 2);                     //  - + - - - - - -
    maxOne(2, 3, 4);                     //  - - + - - - - -
    maxOne(2, 4, 8);                     //  - - - + - - - -
    maxOne(2, 5, 16);                    //  - - - - + - - -
    maxOne(2, 6, 32);                    //  - - - - - + - -
    maxOne(2, 7, 64);                    //  - - - - - - + -
    maxOne(2, 8, 128);                   //  - - - - - - - +
  */

  delay(2000);

}

Драйвер MAX7219 и библиотека LedControl

Управлять светодиодной матрицей можно не только самостоятельно, но и с помощью различных библиотек. Одна из таких библиотек LedControl (не обновляется с 2015 года). Библиотека доступна через менеджер библиотек (LedControl by Eberhard Fahle Version 1.0.6).

Основные функции библиотеки: setLed(), setRow(), setColumn().

Синтаксис функции setLed():


setLed(addr, row, col, state)

В параметре add указывается адрес матрицы. Если матрица одна, то значение должно быть равно 0.

Параметр row отвечает за ряд, параметр col за столбец. Параметр state отвечает за состояние светодиода: true или 1 включает его, а false или 0 - выключает.

Функции setRow(addr, row, value) и setCol(addr, column, value) работают непосредственно с рядами или столбцами.

Скетч с применением библиотеки. Будет запущена небольшая анимация.


#include "LedControl.h"

/*
  Now we need a LedControl to work with.
 ***** These pin numbers will probably not work with your hardware *****
  pin 2 is connected to the DataIn
  pin 4 is connected to the CLK
  pin 3 is connected to LOAD
  We have only a single MAX72XX.
*/
LedControl lc = LedControl(2, 4, 3, 1);

/* we always wait a bit between updates of the display */
unsigned long delaytime = 100;

void setup() {
  /*
    The MAX72XX is in power-saving mode on startup,
    we have to do a wakeup call
  */
  lc.shutdown(0, false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0, 8);
  /* and clear the display */
  lc.clearDisplay(0);
}

/*
  This method will display the characters for the
  word "Arduino" one after the other on the matrix.
  (you need at least 5x7 leds to see the whole chars)
*/
void writeArduinoOnMatrix() {
  /* here is the data for the characters */
  byte a[5] = {B01111110, B10001000, B10001000, B10001000, B01111110};
  byte r[5] = {B00111110, B00010000, B00100000, B00100000, B00010000};
  byte d[5] = {B00011100, B00100010, B00100010, B00010010, B11111110};
  byte u[5] = {B00111100, B00000010, B00000010, B00000100, B00111110};
  byte i[5] = {B00000000, B00100010, B10111110, B00000010, B00000000};
  byte n[5] = {B00111110, B00010000, B00100000, B00100000, B00011110};
  byte o[5] = {B00011100, B00100010, B00100010, B00100010, B00011100};

  /* now display them one by one with a small delay */
  lc.setRow(0, 0, a[0]);
  lc.setRow(0, 1, a[1]);
  lc.setRow(0, 2, a[2]);
  lc.setRow(0, 3, a[3]);
  lc.setRow(0, 4, a[4]);
  delay(delaytime);
  lc.setRow(0, 0, r[0]);
  lc.setRow(0, 1, r[1]);
  lc.setRow(0, 2, r[2]);
  lc.setRow(0, 3, r[3]);
  lc.setRow(0, 4, r[4]);
  delay(delaytime);
  lc.setRow(0, 0, d[0]);
  lc.setRow(0, 1, d[1]);
  lc.setRow(0, 2, d[2]);
  lc.setRow(0, 3, d[3]);
  lc.setRow(0, 4, d[4]);
  delay(delaytime);
  lc.setRow(0, 0, u[0]);
  lc.setRow(0, 1, u[1]);
  lc.setRow(0, 2, u[2]);
  lc.setRow(0, 3, u[3]);
  lc.setRow(0, 4, u[4]);
  delay(delaytime);
  lc.setRow(0, 0, i[0]);
  lc.setRow(0, 1, i[1]);
  lc.setRow(0, 2, i[2]);
  lc.setRow(0, 3, i[3]);
  lc.setRow(0, 4, i[4]);
  delay(delaytime);
  lc.setRow(0, 0, n[0]);
  lc.setRow(0, 1, n[1]);
  lc.setRow(0, 2, n[2]);
  lc.setRow(0, 3, n[3]);
  lc.setRow(0, 4, n[4]);
  delay(delaytime);
  lc.setRow(0, 0, o[0]);
  lc.setRow(0, 1, o[1]);
  lc.setRow(0, 2, o[2]);
  lc.setRow(0, 3, o[3]);
  lc.setRow(0, 4, o[4]);
  delay(delaytime);
  lc.setRow(0, 0, 0);
  lc.setRow(0, 1, 0);
  lc.setRow(0, 2, 0);
  lc.setRow(0, 3, 0);
  lc.setRow(0, 4, 0);
  delay(delaytime);
}

/*
  This function lights up a some Leds in a row.
  The pattern will be repeated on every row.
  The pattern will blink along with the row-number.
  row number 4 (index==3) will blink 4 times etc.
*/
void rows() {
  for (int row = 0; row < 8; row++) {
    delay(delaytime);
    lc.setRow(0, row, B10100000);
    delay(delaytime);
    lc.setRow(0, row, (byte)0);
    for (int i = 0; i < row; i++) {
      delay(delaytime);
      lc.setRow(0, row, B10100000);
      delay(delaytime);
      lc.setRow(0, row, (byte)0);
    }
  }
}

/*
  This function lights up a some Leds in a column.
  The pattern will be repeated on every column.
  The pattern will blink along with the column-number.
  column number 4 (index==3) will blink 4 times etc.
*/
void columns() {
  for (int col = 0; col < 8; col++) {
    delay(delaytime);
    lc.setColumn(0, col, B10100000);
    delay(delaytime);
    lc.setColumn(0, col, (byte)0);
    for (int i = 0; i < col; i++) {
      delay(delaytime);
      lc.setColumn(0, col, B10100000);
      delay(delaytime);
      lc.setColumn(0, col, (byte)0);
    }
  }
}

/*
  This function will light up every Led on the matrix.
  The led will blink along with the row-number.
  row number 4 (index==3) will blink 4 times etc.
*/
void single() {
  for (int row = 0; row < 8; row++) {
    for (int col = 0; col < 8; col++) {
      delay(delaytime);
      lc.setLed(0, row, col, true);
      delay(delaytime);
      for (int i = 0; i < col; i++) {
        lc.setLed(0, row, col, false);
        delay(delaytime);
        lc.setLed(0, row, col, true);
        delay(delaytime);
      }
    }
  }
}

void loop() {
  writeArduinoOnMatrix();
  rows();
  columns();
  single();
}

Хотя в предыдущем примере использовались порты 2, 3 и 4, принято для матрицы использовать порты 9 (CS), 11 (DIN), 13 (CLK) или другие варианты. Ещё один скетч, который будет поочерёдно выводить смайлики трёх видов: грустный, нейтральный, весёлый.


#include "LedControl.h"
#include "binary.h"
/*
  DIN connects to pin 11
  CLK connects to pin 13
  CS connects to pin 9
*/
LedControl lc = LedControl(11, 13, 9, 1);
// delay time between faces
unsigned long delaytime = 1000;

// happy face
byte hf[8] = {B00111100, B01000010, B10100101, B10000001, B10100101, B10011001, B01000010, B00111100};
// neutral face
byte nf[8] = {B00111100, B01000010, B10100101, B10000001, B10111101, B10000001, B01000010, B00111100};
// sad face
byte sf[8] = {B00111100, B01000010, B10100101, B10000001, B10011001, B10100101, B01000010, B00111100};

void setup() {
  lc.shutdown(0, false);
  // Set brightness to a medium value
  lc.setIntensity(0, 8);
  // Clear the display
  lc.clearDisplay(0);
}

void drawFaces() {
  // Display sad face
  lc.setRow(0, 0, sf[0]);
  lc.setRow(0, 1, sf[1]);
  lc.setRow(0, 2, sf[2]);
  lc.setRow(0, 3, sf[3]);
  lc.setRow(0, 4, sf[4]);
  lc.setRow(0, 5, sf[5]);
  lc.setRow(0, 6, sf[6]);
  lc.setRow(0, 7, sf[7]);
  delay(delaytime);

  // Display neutral face
  lc.setRow(0, 0, nf[0]);
  lc.setRow(0, 1, nf[1]);
  lc.setRow(0, 2, nf[2]);
  lc.setRow(0, 3, nf[3]);
  lc.setRow(0, 4, nf[4]);
  lc.setRow(0, 5, nf[5]);
  lc.setRow(0, 6, nf[6]);
  lc.setRow(0, 7, nf[7]);
  delay(delaytime);

  // Display happy face
  lc.setRow(0, 0, hf[0]);
  lc.setRow(0, 1, hf[1]);
  lc.setRow(0, 2, hf[2]);
  lc.setRow(0, 3, hf[3]);
  lc.setRow(0, 4, hf[4]);
  lc.setRow(0, 5, hf[5]);
  lc.setRow(0, 6, hf[6]);
  lc.setRow(0, 7, hf[7]);
  delay(delaytime);
}

void loop() {
  drawFaces();
}

Дополнительные материалы для изучения библиотеки доступны на отдельном сайте.

Визуальный редактор

Рассмотрим ещё один пример создания бегущей строки со словами "Я ❤ кота". Символы для фразы уже подготовлены. Вы можете создать собственные символы и добавить в код.

Редактор для создания собственных символов для матрицы с драйвером MAX7219

Щёлкайте по квадратам для генерации кода.

Знакоместо












Результат

byte customChar[8] = {
	B00000000,
	B00000000,
	B00000000,
	B00000000,
	B00000000,
	B00000000,
	B00000000,
	B00000000
};
8x8 MAX7219 Arduino Pin
DIN
CLK
CS

Код для скетча Arduino

#include "LedControl.h"

// initialize the library
/*
  pin 12 is connected to the DIN
  pin 11 is connected to the CLK
  pin 10 is connected to CS
*/
LedControl lc = LedControl(12, 11, 10, 1);

/* we always wait a bit between updates of the display */
unsigned long delaytime = 600;
void setup()
{
  lc.shutdown(0, false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0, 8);
  /* and clear the display */
  lc.clearDisplay(0);
}

void loop()
{
  writeText();
}

void writeText() {
  // Символы для фразы Я люблю кота
  byte Ya[8] = { B00111111,B00100001,B00100001,B00111111,B00000101,B00001001,B00010001,B00100001};
  byte love[8] = { B00000000, B01100110, B10011001, B10011001, B10000001, B01000010, B00100100, B00011000};
  byte K[8] = { B01000100,B01001000,B01010000,B01100000,B01010000,B01001000,B01000100,B01000010};
  byte O[8] = {B00011000, B00100100, B01000010, B01000010, B01000010, B01000010, B00100100, B00011000};
  byte T[8] = { B00111110,B00001000,B00001000,B00001000,B00001000,B00001000,B00001000,B00001000};
  byte A[8] = {B00111000, B01000100, B10000010, B11111110, B10000010, B10000010, B10000010, B10000010};

  
  /* Я */
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, Ya[i]);
  }

  delay(delaytime);
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, 0); // this is for blank
  }

  /* love */
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, love[i]);
  }

  delay(delaytime);
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, 0); // this is for blank
  }
  
  /* K */
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, K[i]);
  }

  delay(delaytime);
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, 0); // this is for blank
  }

  /* O  */
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, O[i]);
  }

  delay(delaytime);
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, 0); // this is for blank
  }

  /* T  */
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, T[i]);
  }

  delay(delaytime);
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, 0); // this is for blank
  }

  /*  A  */
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, A[i]);
  }

  delay(delaytime);
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, 0); // this is for blank
  }

  delay(delaytime);
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, 0); // this is for blank
  }
}

Ещё один визуальный редактор для создания анимационных эффектов LED Matrix Editor.

Библиотека LEDMatrixDriver

В описании говорится, что библиотека LEDMatrixDriver является наследником устаревшей LedControl. Также доступна через менеджер библиотек. На Гитхабе есть несколько примеров с применением библиотеки. Я использовал пример SetPixel, который заполняет все ряды светодиодов светом поочерёдно.

При подключении использовались пины DIN=11, CS=9, CLK=13.


#include <LEDMatrixDriver.hpp>

const uint8_t LEDMATRIX_CS_PIN = 9;

// Number of 8x8 segments you are connecting
const int LEDMATRIX_SEGMENTS = 4;
const int LEDMATRIX_WIDTH    = LEDMATRIX_SEGMENTS * 8;

// The LEDMatrixDriver class instance
LEDMatrixDriver lmd(LEDMATRIX_SEGMENTS, LEDMATRIX_CS_PIN);

void setup() {
  // init the display
  lmd.setEnabled(true);
  lmd.setIntensity(2);   // 0 = low, 10 = high
}

int x = 0, y = 0; // start top left
bool s = true;  // start with led on

void loop() {
  // toggle current pixel in framebuffer
  lmd.setPixel(x, y, s);

  // move to next pixel
  if ( x++ >= LEDMATRIX_WIDTH )
  {
    // Return to left
    x = 0;

    // start new line
    if ( y++ >= 8)
    {
      y = 0;  // need to return to start
      s = !s; // toggle led state
    }
  }


  // Flush framebuffer
  lmd.display();

  delay(1

Дополнительные материалы

Arduino-er: Arduino Uno: scan LED Matrix in Timer Interrupt (+видео)

Arduino-er: Beating Heart animation on 8x8 LED Matrix + Arduino Uno (+видео)

Arduino 8x8 LED Matrix Pong - YouTube (исходники)

Старая библиотека, давно не обновляется.

Реклама