С одной стороны, учимся писать библиотеку на C++ для Arduino, с другой стороны, пишем очень полезную, маленькую библиотеку для LED дисплея 8x8 с микросхемой MAX7219.
Благодаря такой постановке задачи, библиотека будет максимально понятной и ничего лишнего.
Название библиотеки MaxAndMatrix следует из назначения библиотеки. Микросхема MAX7219 может управлять 8-ю семи-сегментными светодиодными индикаторами или светодиодной матрицей 8х8 светодиодов. У нас дисплей из микросхемы MAX и светодиодная матрица, отсюда и название библиотеки MaxAndMatrix.
Создадим файл MaxAndMatrix.h. Файл библиотеки с расширением h, обычно содержит определения классов и прототипы функций.
#ifndef MaxAndMatrix_h
#define MaxAndMatrix_h
#include <Arduino.h>
class MaxAndMatrix {
private :
int din;
int clk;
int cs;
int nturns = 0; // Число поворотов на 90 против часовой
public:
MaxAndMatrix(int dinPin, int clkPin, int csPin);
void begin(bool testMatrix = 0); // зажечь все светодиоды если testMatrix = 1
void loadByte(int addr, byte data = 0); // загрузить одну строку addr = [0...7]
void setRotation(int numberOFturns); // установить число поворотов матрицы на 90
void loadMatrix(byte matrix[]); // загрузить все 8 регистров LED матрицы
void force(int powerOFlight); // яркость powerOFlight = [0...15]
void onOff(bool HighLow); // включить/выключить LED
void clear(void); // очистить все 8 регистров LED матрицы
};
#endif //MaxAndMatrix.h
Скетч 1. Файл MaxAndMatrix.h
В файле MaxAndMatrix.h объявлен класс MaxAndMatrix. Внутри этого класса будут использованы несколько переменных и будет создано несколько функций (методов) для управления свойствами и поведением объектами класса MaxAndMatrix. Вместо функций, в файл с расширением h, обычно помещают только прототипы функций, их заголовки (заготовки).
Пишем файл MaxAndMatrix.cpp, в нём функции наполняем телами.
#include "MaxAndMatrix.h"
// Register Address-1
#define DECODEMODE 0x9-1
#define INTENSITY 0xA-1
#define SCANLIMIT 0xB-1
#define SHUTDOWN 0xC-1
#define DISPLAYTEST 0xF-1
MaxAndMatrix:: MaxAndMatrix(int dinPin, int clkPin, int csPin) {
din = dinPin;
clk = clkPin;
cs = csPin;
}
void MaxAndMatrix::loadByte(int addr, byte data = 0) { // загрузка байта в регистры микросхемы MAX7219
digitalWrite(cs, LOW);
shiftOut(din, clk, MSBFIRST, addr + 1); // В MAX7219 нумерация аресов регистров строк LED начинается с 1
shiftOut(din, clk, MSBFIRST, data);
digitalWrite(cs, HIGH);
}
void MaxAndMatrix::setRotation(int numberOFturns) {
nturns = numberOFturns % 4; // Вращаем только 3 раза. numberOFturns=0 без вращения
} // 1 на 90° против часовой стрелки, 2 на 180°, 3 на 270°
void MaxAndMatrix::loadMatrix(byte matrix[]) {
byte rmatrix[8]; // вспомогательная матрица.
byte zmatrix[8]; // копия матрицы пользователя, пользовательскую не портим.
for (int i = 0 ; i < 8; i++) {
zmatrix[i] = matrix[i]; // создание копии матрицы пользователя
}
for (int r = 1; r <= nturns; r++) { // вращение матрицы nturns раз
for (int i = 0; i < 8; i++) { // вращение на 90° против часовой стрелки один раз
rmatrix[i] = 0;
for (int j = 0; j < 8; j++) {
rmatrix[i] |= ((zmatrix[7 - j] & (1 << i)) >> i) << j;
}
}
for (int i = 0; i < 8; i++) {
zmatrix[i] = rmatrix[i]; // копирование повёрнутой матрицы в исходную
} // после каждого поворота
}
for (int i = 0 ; i < 8; i++) {
loadByte(i, zmatrix[i]); // загрузка матрицы в микросхему MAX7219
}
}
void MaxAndMatrix::clear(void) {
for (int i = 0 ; i < 8; i++) {
loadByte(i, 0); // загрузка 0 в регистры микросхемы MAX7219 по адресам LED
}
}
void MaxAndMatrix::begin(bool testMatrix = 0) {
pinMode(din , OUTPUT);
pinMode(clk, OUTPUT);
pinMode(cs, OUTPUT);
clear(); // очистить LED регистры микросхемы MAX7219
loadByte(DECODEMODE, 0); // 0 для матриц, остальное для семисегментных индикаторов
loadByte(INTENSITY, 7); // средняя яркость
loadByte(SCANLIMIT, 7); // количество рядов в LED матрице
loadByte(SHUTDOWN , 1); // включить матрицу
loadByte(DISPLAYTEST, 0); // запретить тест LED матрицы
if (testMatrix) { // тестировать LED матрицу 3сек. если begin(1)
loadByte(DISPLAYTEST, 1);
delay(3000);
loadByte(DISPLAYTEST, 0);
}
}
void MaxAndMatrix::force(int powerOFlight) {
loadByte(INTENSITY, powerOFlight); // меняем яркость свечения светодиодов powerOFlight=[0...15]
}
void MaxAndMatrix::onOff(bool HighLow) {
loadByte(SHUTDOWN, HighLow); // включить/выключить LED матрицу
}
Скетч 2. Файл MaxAndMatrix.cpp.
Функция begin содержит инструкции для микросхемы MAX7219. Подробнее см. в статье MAX7219 и Arduino.
В библиотеке MaxAndMatrix функция loadMatrix() получилась избыточно сложной, но в ней мы позаботились о повороте изображения на угол 0°, 90°, 180° и 270°, не изменяя содержимое матрицы (массива) пользователя. Такой поворот изображения, скорее всего, пригодится в дальнейшем, ведь ориентирует LED матрицу в пространстве конструктор, а генерирует изображение программист. Чтобы программы были универсальными и чтобы любые дисплеи работали с нашей программой мы добавили возможность предварительно настроенного с помощью функции setRotation() поворота изображения на угол 0°, 90°, 180° или 270° в момент вывода на LED матрицу.
Пишем пример, с использованием библиотеки MaxAndMatrix в Arduino IDE.
#include "MaxAndMatrix.h"
int dataPin = 12; // DIN
int clockPin = 11; // CLK
int csPin = 10; // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);
byte matrix[8] = {0b01110001,
0b11011011,
0b10001110,
0b10001100,
0b10001000,
0b11111111,
0b10000001,
0b11111111
};
void setup() {
led88.begin(0);
led88.force(0);
}
void loop() {
for (int i=0; i<4; i++) {
led88.setRotation(i);
led88.loadMatrix(matrix);
delay(700);
}
}
Скетч 2. Файл RotateR.ino
В программе скетч 2, массив matrix[8] содержит битовый образ изображения буквы R, построенный как показано на рисунке 1.
Рис. 1. Битовый образ изображения буквы R.
С таким же успехом массив matrix[8] можно было построить как показано на рисунке 2, библиотека MaxAndMatrix позволяет нам это делать.
Рис. 2. Битовый образ изображения буквы R.
Сохраняем все файлы проекта в папке RotateR. Arduino IDE сохранила файл RotateR.ino в этой папке, а мы добавили туда файлы библиотеки MaxAndMatrix.h и MaxAndMatrix.cpp.
Закройте все окна Arduino и опять откройте программу RotateR. Теперь в Arduino IDE доступны для редактирования все три файла проекта.
Рис. 3. Arduino IDE.
Собираем схему и тестируем ПО.
Рис. 4. Принципиальная электрическая схема LED дисплея 8x8 с микросхемой MAX7219 управляемого микроконтроллером ATtiny88.
Рис. 5. Макет микроконтроллер ATtiny88 и LED дисплей 8x8 с микросхемой MAX7219.
Ещё один пример использования библиотеки MaxAndMatrix, игра пинг-понг.
/*
* Pong a ping-pong game for one person
* This is my version of the ping-pong program
*
* Created on august 24, 2021.
* Author of this program code : Diorditsa A.
* I thank Sergey Polozkov for checking the code for hidden errors
*
* pong.ino is distributed in the hope that it will be useful, but
* WITHOUT WARRANTY OF ANY KIND; not even an implied warranty
* MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See. See the GNU General Public License for more information.
* You can get a copy of the GNU General Public License
* by link http://www.gnu.org/licenses/
*/
#include "MaxAndMatrix.h"
int dataPin = 12; // DIN
int clockPin = 11; // CLK
int csPin = 10; // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);
byte matrix[8] = {0, 0, 0, 0, 0, 0, 0, 0};
int xBall, yBall, temp , vx, vy, racket;
int k1pin = 6; int k2pin = 5; // Кнопки, замыкающие на минус
void setup() {
pinMode(k1pin, INPUT_PULLUP);
pinMode(k2pin, INPUT_PULLUP);
led88.begin(0);
led88.force(0);
led88.setRotation(1);
led88.loadMatrix(matrix);
xBall = 3; yBall = 0; vx = 1; vy = 1; temp = 250;
racket = 2;
}
void loop() {
if (!digitalRead(k1pin) and racket < 6) {
racket++;
}
if (!digitalRead(k2pin) and racket > 0) {
racket--;
}
matrix[7] = 0;
matrix[yBall] = 1 << xBall;
matrix[7] |= B11 << racket;
led88.loadMatrix(matrix);
matrix[yBall] = 0;
delay (temp);
if (yBall == 6) {
if (xBall == racket or xBall == racket + 1) {
vy = -1;
}
if (xBall == racket - 1 and vx == 1) {
vy = -1; vx = -1;
}
if (xBall == racket + 2 and vx == -1) {
vy = -1; vx = 1;
}
}
if (yBall == 7) {
yBall = -1;
}
if (xBall == 0) {
vx = 1;
}
if (xBall == 7) {
vx = -1;
}
yBall += vy; xBall += vx;
if (yBall == 0) {
vy = 1;
}
}
Скетч 4. Файл Pong.ino