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

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

Шкодим

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

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

07.Display: RowColumnScanning
Бегущие огни

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

Светодиодные матрицы бывают одноцветными, двухцветными и 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.

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

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 (исходники)

Реклама