• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

LOLIN*WEMIS) D1 R2 & mini проблема с шиной SPI.

enjoynering

Well-known member
У max7219 динамическая индикация - на каждый светодиод подаётся питание с частотой 800гц. Из за это средний ток потребления очень низкий. В моих часах 5 матриц/320 светодиодов и на минимальнрй яркости они по ребляют 60мА, на средней около 150мА. Но китайцы не были бы китайцам - в самом популярном шилде с алишечки проблема с токозадающим резисторм R1. Он там не правильного номинала и через диоды на мах яркости шарашит адский ток. Есть мнение что все мах7219 на китайских площадках лютый фейк и тогда вопрос с правильным номиналом стоит ещё острее (не понятно насколько точно они скопировали чип)
 

enjoynering

Well-known member
А ещё (если я правильно помню, тк писал библиотеку под max7219 давно) у каждой микросхемы есть свой sram буфер 8х8=16 байт и сразу после подачи питания там мусор, поэтому экран никогда не включается сам после подачи питания. Ему нужно дать команду, и желательно очистить sram. Но это все есть datasheet, просто его надо открыть и внимательно прочитать.
 
Initial Power-Up
On initial power-up, all control registers are reset, the display is blanked, and the MAX7219/MAX7221 enter shutdown mode. Program the display driver prior to display use. Otherwise, it will initially be set to scan one
digit, it will not decode data in the data registers, and the intensity register will be set to its minimum value.
При первом включении все регистры управления сбрасываются. дисплей гаснет, и MAX7219/MAX7221 входит в режим отключения. Запрограммируйте драйвер дисплея до использование дисплея. В противном случае он изначально будет настроен на сканирование одного цифра, он не будет декодировать данные в регистрах данных, и регистр интенсивности будет установлен на минимальное значение.

Вот про этот момент даташита вы говорили? но я не совсем понимаю, что значит:"Запрограммируйте драйвер дисплея до использование дисплея." Понятное дело, что инициализируется он у меня до его использования. К стати о двойной инициализации я тоже думал.
 
А ещё (если я правильно помню, тк писал библиотеку под max7219 давно) у каждой микросхемы есть свой sram буфер 8х8=16 байт и сразу после подачи питания там мусор, поэтому экран никогда не включается сам после подачи питания. Ему нужно дать команду, и желательно очистить sram.
Это я понимаю. Не понимаю, почему это не делается библиотекой? Возможно конечно у меня некачественно написаная библиотека (та которую я юзаю), но она мне больше всего подошла. Дело в том, что когда я начинал заниматься этими матрицами, я почему-то подумал, что они все одинаковые (технически) и купил матрицы с общим анодом. Не то что я хотел такие купить, просто такие попались. Тупо их было больше (как я потом понял). А VAX7219 я так понимаю разработана для общего катода. Я конечно разводку поменял, но вот библиотек для общего анода не нашел. И у меня получались всегда перепутаные координаты. А вот эта библиотека, которую я нашел позволяет в настройках указать порядок матриц и в итоге оси координат у меня встали как положено и я смог написать код.
 
Хм. Хотел 2 раза инициировать матрицу, а в этой библиотеке нет как таковой инициализации! Попробовал сделать
Код:
matrix.shutdown(true);
delay(1000);
matrix.shutdown(false);
Матрица засветилась, но начала выдавать не осмысленные символы, а какие-то полоски, как будто символ 3х6 скажем превратился в 1х6.
Архив библиотеки вот так называется - arduino-Max72xxPanel-master. Сама библиотека прописывается #include <Max72xxPanel.h>
Собственно вот он этот файл
Код:
/******************************************************************
A library for controling a set of 8x8 LEDs with a MAX7219 or
MAX7221 displays.

This is a plugin for Adafruit's core graphics library, providing
basic graphics primitives (points, lines, circles, etc.).
You need to download and install Adafruit_GFX to use this library.

Adafruit invests time and resources providing this open
source code, please support Adafruit and open-source hardware
by purchasing products from Adafruit!

Written by Mark Ruys, 2013.
BSD license, check license.txt for more information.
All text above must be included in any redistribution.

Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf

******************************************************************/

#ifndef Max72xxPanel_h
#define Max72xxPanel_h

#if (ARDUINO >= 100)
  #include <Arduino.h>
#else
  #include <WProgram.h>
  #include "pins_arduino.h"
#endif

class Max72xxPanel : public Adafruit_GFX {

public:

  /*
   * Create a new controler
   * Parameters:
   * csPin        pin for selecting the device
   * hDisplays  number of displays horizontally
   * vDisplays  number of displays vertically
   */
  Max72xxPanel(byte csPin, byte hDisplays=1, byte vDisplays=1);

    /*
     * Define how the displays are ordered. The first display (0)
     * is the one closest to the Arduino.
     */
    void setPosition(byte display, byte x, byte y);

    /*
     * Define if and how the displays are rotated. The first display
     * (0) is the one closest to the Arduino. rotation can be:
     *   0: no rotation
     *   1: 90 degrees clockwise
     *   2: 180 degrees
     *   3: 90 degrees counter clockwise
     */
    void setRotation(byte display, byte rotation);

    /*
     * Implementation of Adafruit's setRotation(). Probably, you don't
     * need this function as you can achieve the same result by using
     * the previous two functions.
     */
    void setRotation(byte rotation);

  /*
   * Draw a pixel on your canvas. Note that for performance reasons,
   * the pixels are not actually send to the displays. Only the internal
   * bitmap buffer is modified.
   */
  void drawPixel(int16_t x, int16_t y, uint16_t color);

  /*
   * As we can do this much faster then setting all the pixels one by
   * one, we have a dedicated function to clear the screen.
   * The color can be 0 (blank) or non-zero (pixel on).
   */
  void fillScreen(uint16_t color);

  /*
   * Set the shutdown (power saving) mode for the device
   * Paramaters:
   * status    If true the device goes into power-down mode. Set to false
   *        for normal operation.
   */
  void shutdown(boolean status);

  /*
   * Set the brightness of the display.
   * Paramaters:
   * intensity    the brightness of the display. (0..15)
   */
  void setIntensity(byte intensity);

  /*
   * After you're done filling the bitmap buffer with your picture,
   * send it to the display(s).
   */
  void write();

private:
  byte SPI_CS; /* SPI chip selection */

  /* Send out a single command to the device */
  void spiTransfer(byte opcode, byte data=0);

  /* We keep track of the led-status for 8 devices in this array */
  byte *bitmap;
  byte bitmapSize;

  byte hDisplays;
  byte *matrixPosition;
  byte *matrixRotation;
};

#endif    // Max72xxPanel_h
А вот файл cpp
Код:
/******************************************************************
A library for controling a set of 8x8 LEDs with a MAX7219 or
MAX7221 displays.
This is a plugin for Adafruit's core graphics library, providing
basic graphics primitives (points, lines, circles, etc.).
You need to download and install Adafruit_GFX to use this library.

Adafruit invests time and resources providing this open
source code, please support Adafruit and open-source hardware
by purchasing products from Adafruit!

Written by Mark Ruys.
BSD license, check license.txt for more information.
All text above must be included in any redistribution.
******************************************************************/

#include <Adafruit_GFX.h>
#include "Max72xxPanel.h"
#include <SPI.h>

// The opcodes for the MAX7221 and MAX7219
#define OP_NOOP         0
#define OP_DIGIT0       1
#define OP_DIGIT1       2
#define OP_DIGIT2       3
#define OP_DIGIT3       4
#define OP_DIGIT4       5
#define OP_DIGIT5       6
#define OP_DIGIT6       7
#define OP_DIGIT7       8
#define OP_DECODEMODE   9
#define OP_INTENSITY   10
#define OP_SCANLIMIT   11
#define OP_SHUTDOWN    12
#define OP_DISPLAYTEST 15

Max72xxPanel::Max72xxPanel(byte csPin, byte hDisplays, byte vDisplays) : Adafruit_GFX(hDisplays << 3, vDisplays << 3) {

  Max72xxPanel::SPI_CS = csPin;

  byte displays = hDisplays * vDisplays;
  Max72xxPanel::hDisplays = hDisplays;
    Max72xxPanel::bitmapSize = displays << 3;

  Max72xxPanel::bitmap = (byte*)malloc(bitmapSize);
  Max72xxPanel::matrixRotation = (byte*)malloc(displays);
  Max72xxPanel::matrixPosition = (byte*)malloc(displays);

  for ( byte display = 0; display < displays; display++ ) {
      matrixPosition[display] = display;
      matrixRotation[display] = 0;
  }

  SPI.begin();
//SPI.setBitOrder(MSBFIRST);
//SPI.setDataMode(SPI_MODE0);
  pinMode(SPI_CS, OUTPUT);

  // Clear the screen
  fillScreen(0);

  // Make sure we are not in test mode
  spiTransfer(OP_DISPLAYTEST, 0);

  // We need the multiplexer to scan all segments
  spiTransfer(OP_SCANLIMIT, 7);

  // We don't want the multiplexer to decode segments for us
  spiTransfer(OP_DECODEMODE, 0);

  // Enable display
  shutdown(false);

  // Set the brightness to a medium value
  setIntensity(7);
}

void Max72xxPanel::setPosition(byte display, byte x, byte y) {
    matrixPosition[x + hDisplays * y] = display;
}

void Max72xxPanel::setRotation(byte display, byte rotation) {
    matrixRotation[display] = rotation;
}

void Max72xxPanel::setRotation(uint8_t rotation) {
    Adafruit_GFX::setRotation(rotation);
}

void Max72xxPanel::shutdown(boolean b) {
  spiTransfer(OP_SHUTDOWN, b ? 0 : 1);
}

void Max72xxPanel::setIntensity(byte intensity) {
  spiTransfer(OP_INTENSITY, intensity);
}

void Max72xxPanel::fillScreen(uint16_t color) {
  memset(bitmap, color ? 0xff : 0, bitmapSize);
}

void Max72xxPanel::drawPixel(int16_t xx, int16_t yy, uint16_t color) {
    // Operating in bytes is faster and takes less code to run. We don't
    // need values above 200, so switch from 16 bit ints to 8 bit unsigned
    // ints (bytes).
    int8_t x = xx;
    byte y = yy;
    byte tmp;

    if ( rotation ) {
        // Implement Adafruit's rotation.
        if ( rotation >= 2 ) {                                        // rotation == 2 || rotation == 3
            x = _width - 1 - x;
        }

        if ( rotation == 1 || rotation == 2 ) {        // rotation == 1 || rotation == 2
            y = _height - 1 - y;
        }

        if ( rotation & 1 ) {                                     // rotation == 1 || rotation == 3
            tmp = x; x = y; y = tmp;
        }
    }

    if ( x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT ) {
        // Ignore pixels outside the canvas.
        return;
    }

    // Translate the x, y coordinate according to the layout of the
    // displays. They can be ordered and rotated (0, 90, 180, 270).

    byte display = matrixPosition[(x >> 3) + hDisplays * (y >> 3)];
    x &= 0b111;
    y &= 0b111;

    byte r = matrixRotation[display];
    if ( r >= 2 ) {                                           // 180 or 270 degrees
        x = 7 - x;
    }
    if ( r == 1 || r == 2 ) {                     // 90 or 180 degrees
        y = 7 - y;
    }
    if ( r & 1 ) {                                        // 90 or 270 degrees
        tmp = x; x = y; y = tmp;
    }

    byte d = display / hDisplays;
    x += (display - d * hDisplays) << 3; // x += (display % hDisplays) * 8
    y += d << 3;                                                 // y += (display / hDisplays) * 8

    // Update the color bit in our bitmap buffer.

    byte *ptr = bitmap + x + WIDTH * (y >> 3);
    byte val = 1 << (y & 0b111);

    if ( color ) {
        *ptr |= val;
    }
    else {
        *ptr &= ~val;
    }
}

void Max72xxPanel::write() {
    // Send the bitmap buffer to the displays.

    for ( byte row = OP_DIGIT7; row >= OP_DIGIT0; row-- ) {
        spiTransfer(row);
    }
}

void Max72xxPanel::spiTransfer(byte opcode, byte data) {
    // If opcode > OP_DIGIT7, send the opcode and data to all displays.
    // If opcode <= OP_DIGIT7, display the column with data in our buffer for all displays.
    // We do not support (nor need) to use the OP_NOOP opcode.

    // Enable the line
    digitalWrite(SPI_CS, LOW);

    // Now shift out the data, two bytes per display. The first byte is the opcode,
    // the second byte the data.
    byte end = opcode - OP_DIGIT0;
    byte start = bitmapSize + end;
    do {
        start -= 8;
        SPI.transfer(opcode);
        SPI.transfer(opcode <= OP_DIGIT7 ? bitmap[start] : data);
    }
    while ( start > end );

    // Latch the data onto the display(s)
    digitalWrite(SPI_CS, HIGH);
}
 

ghost21

Member
могу и код приложить. просто он большой, в 6 или 7 файлах.
А никому эти 6 или 7 файлов и не нужны. Выбросить из кода все что не касается матриц. Оставь только вывод "привет мир!", скомпилируй, загрузи и посмотри как будет работать. Если так же, тогда показывай этот урезанный код, может кто-то и посоветует что с ним делать.
Если заработает нормально добавляй по кусочку работу с датчиками и т.д. пока не начнутся глюки. А дальше опять же или показываешь этот код или разбираешься сам.
 

CodeNameHawk

Moderator
Команда форума
Наконец руки дошли. Вот код. Только WiFi, OTA и ИК пульт пришлось оставить.
Код:
#include <font12.h>
#include <Adafruit_GFX.h> //new
#include <Max72xxPanel.h> //new
#include "ArduinoOTA.h"
#include <ESP8266WiFi.h>
#include <IRrecv.h>

const uint8_t CS_PIN_DISPL = 15;

const int symbols[] = {32, 37, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 194};

const uint8_t X_DEVICES = 2;
const uint8_t Y_DEVICES = 8;
const uint8_t MATRIX_WIDTH = 64, MATRIX_HEIGHT = 16; //Общие размеры матрицы дисплея
Max72xxPanel matrix = Max72xxPanel(CS_PIN_DISPL, Y_DEVICES, X_DEVICES);

//ИК приемник
const uint16_t RECV_PIN = 2;
IRrecv irrecv(RECV_PIN);
decode_results results;

byte sl;
int curX, curY, tw;
int startRunLineX = MATRIX_WIDTH - 1; //Стартовое положение надписи на дисплее по оси Y
int XStart = 0;
int YStart = 1;

void setup() {
  Serial.begin(115200);
  //Инициируем дисплей
  sl = sizeof(symbols) / sizeof(symbols[0]);
  matrix.setIntensity(1);
  matrix.setPosition(0,7,0);
  matrix.setPosition(1,7,1);
  matrix.setPosition(2,6,0);
  matrix.setPosition(3,6,1);
  matrix.setPosition(4,5,0);
  matrix.setPosition(5,5,1);
  matrix.setPosition(6,4,0);
  matrix.setPosition(7,4,1);
  matrix.setPosition(8,3,0);
  matrix.setPosition(9,3,1);
  matrix.setPosition(10,2,0);
  matrix.setPosition(11,2,1);
  matrix.setPosition(12,1,0);
  matrix.setPosition(13,1,1);
  matrix.setPosition(14,0,0);
  matrix.setPosition(15,0,1);

  //Запускаем OTA
  ArduinoOTA.onStart([]() {
    Serial.println("Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();

  irrecv.enableIRIn();
}

void loop() {
  ArduinoOTA.handle();
  matrix.fillScreen(0);
  runText("Hello World!", 0, 7, true);
  matrix.write();

  //Работа с пультом
  if (irrecv.decode(&results)) {
    switch (results.value) {
      /*case 16738455: pultcode = 1; break; //1-температура на улице
      case 16750695: pultcode = 2; break; //2-влажность на улице
      case 16756815: pultcode = 3; break; //3-давление
      case 16724175: pultcode = 4; break; //4-температура 1 этаж
      case 16718055: pultcode = 5; break; //5-влажность 1 этаж
      case 16743045: pultcode = 6; break; //6-температура 2 этаж
      case 16716015: pultcode = 7; break; //7-влажность 2 этаж
      case 16726215: pultcode = 8; break; //8-время
      case 16734885: pultcode = 9; break; //9-дата
      case 16730805: pultcode = 10; break; //10-IP адрес
      case 16728765: pultcode = 11; break; //*-синхронизация времени с интернетом
      case 16732845: pultcode = 12; break; //#-
      case 16720605: pultcode = 13; break; //влево-
      case 16736925: pultcode = 14; break; //вверх-
      case 16761405: pultcode = 15; break; //вправо-
      case 16754775: pultcode = 16; break; //вниз-*/
      case 16712445: ESP.restart(); break; //ОК-перезагрузка
    }
    irrecv.resume();  // Receive the next value
  }
}

bool runText(String text, int startX, int startY, bool state){//вывод статического текста
  int i;
  byte n;
  uint32_t vertPixels;
  byte fin = 0;
  unsigned long tp;
  tw = countFraseLength(text);
  curX=startX + startRunLineX;
  curY=startY;
  for (i=0;i<text.length();i++){
    byte sym = (byte)text[i];
    if ((sym == 208) || ((sym == 209)))
    {
      i++;
      sym = (byte)text[i];
    }
    if (sym == 194){
      i++;
    }
    n=getArrayIndex(sym,sl,1);
    for (byte j=0;j<12;j++){
      vertPixels=pgm_read_word(&(font12[n][j]));
      if ((j==0)||(vertPixels>0)){//только первая колонка и не пустые колонки
        getPixel12 (vertPixels, startY, state);
      }
    }
    curX++;
  }
  if (startRunLineX >= 0 - tw){//каждый кадр смещаем начало отрисовки бегущей строки на 1 пиксель влево от правого края матрицы
    startRunLineX--;
  }
  else {startRunLineX = MATRIX_WIDTH - 1; fin = 1;}
  tp = millis();
  while (millis() - tp != 25){}
  return fin;
}

byte getPixel12 (uint32_t vertPixels, byte startY, bool tstate) {
   byte pixel;
   for (int k = 0; k < 10; k++) {
        pixel = ((vertPixels >> k) & 0x01);
        if (pixel==1){
          //if (curX >= 0 && curX < MATRIX_WIDTH && curY >=0 && curY < MATRIX_HEIGHT){
            //leds[curY][curX] = tstate;
            matrix.drawPixel(curX,curY,tstate);
          //}
        }
        curY++;
    }
    curY=startY;
    curX++;
}

byte getArrayIndex(byte znach, byte ln, byte an){
  for (byte n=0;n<ln;n++) {
    if (an == 1){
      if (symbols[n] == znach){
       return n;
      }
    }
    else {
      /*if (smallnum[n] == znach){
        return n;
      }*/
    }
  }
}

int countFraseLength(String text){//считаем длину строки
    int i, n;
    uint32_t vertPixels;

    int l=0;
    for (i=0;i<text.length();i++){
      byte sym = (byte)text[i];
      if ((sym == 208) || ((sym == 209)))
      {
        i++;
        sym = (byte)text[i];
      }
      if (sym == 194){
        i++;
      }

      n=getArrayIndex(sym,sl,1);
      for (byte j=0;j<12;j++){
         vertPixels=pgm_read_word(&(font12[n][j]));
         if ((j==0)||(vertPixels>0)){//только первая колонка и не пустые колонки
             l++;
         }
         if (j==11){//в конце каждого символа добавляем пробел
            l++;
         }
       }
    }
  return l;
}

void WIFIinit() {
  WiFi.mode(WIFI_STA);
  byte tries = 60;
  String _ssid = "DVKH24";
  String _password = "Njrvfrjdf_1947";
  WiFi.begin(_ssid.c_str(), _password.c_str());
  while (--tries && WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(1000);
  }
  if (WiFi.status() != WL_CONNECTED)
  {
    // Если не удалось подключиться запускаем в режиме AP
    StartAPMode();
  }
  else {
    // Иначе удалось подключиться отправляем сообщение
    // о подключении и выводим адрес IP
    delay(1000);
  }
}


bool StartAPMode() {
  int IP1 = 10;
  int IP2 = 10;
  int IP3 = 10;
  int IP4 = 10;
  IPAddress apIP(IP1, IP2, IP3, IP4);
  // Отключаем WIFI
  WiFi.disconnect();
  // Меняем режим на режим точки доступа
  WiFi.mode(WIFI_AP);
  // Задаем настройки сети
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  // Включаем WIFI в режиме точки доступа с именем и паролем
  // хронящихся в переменных _ssidAP _passwordAP
  String _ssidAP = "MYDev";
  String _passwordAP = "123";
  WiFi.softAP(_ssidAP.c_str(), _passwordAP.c_str());
}
Все как и в основном скетче. При включении питания на экране пусто. Делаю сброс с пульта, надпись бежит. Перепрошиваю, надпись бежит.
 
Чия библиотека?
.setIntensity(7);
Это не пробовали?
Ну и
Все выбросить не могу (имею в виду WiFI, OTA и ИК). Плата уже в корпусе, не смогу прошить через USB и сделать сброс кнопкой.
.setIntensity у меня в программе регулируется автоматом в зависимости от освещения. Ранее пробовал разные значения.
 

ghost21

Member
Все выбросить не могу (имею в виду WiFI, OTA и ИК). Плата уже в корпусе, не смогу прошить через USB
Значит для чистоты эксперимента нужно разобрать. И скажу так что ОТА это не выход. У меня тоже так плата в корпусе висела. Поначалу все было хорошо. А потом в один прекрасный момент (где-то через год) захотелось кое-что добавить, а она по ОТА отказывается прошиваться. Пришлось материться и лезть доставать ее из корпуса. И это все зимой, на улице. Так что лучше заранее предусмотреть возможность подключения по шнурку не разбирая корпус.
 

CodeNameHawk

Moderator
Команда форума
Сами же просили выкинуть все по максимуму.
Да, но вы этого не сделали.
А тут нету, а вы что пробуете отдалить тот код или этот?
Что бы не терять время, показывайте скриншот скетча, перед заливкой, включите вывод отладочной информации и скриншот сюда.
Если это не возможно, то просто залейте пример из библиотеки...
 
Код:
#include <font12.h>
#include <Adafruit_GFX.h> //new
#include <Max72xxPanel.h> //new
#include "ArduinoOTA.h"
#include <ESP8266WiFi.h>
#include <IRrecv.h>

const uint8_t CS_PIN_DISPL = 15;

const int symbols[] = {32, 37, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 194};

const uint8_t X_DEVICES = 2;
const uint8_t Y_DEVICES = 8;
const uint8_t MATRIX_WIDTH = 64, MATRIX_HEIGHT = 16; //Общие размеры матрицы дисплея
Max72xxPanel matrix = Max72xxPanel(CS_PIN_DISPL, Y_DEVICES, X_DEVICES);

//ИК приемник
const uint16_t RECV_PIN = 2;
IRrecv irrecv(RECV_PIN);
decode_results results;

byte sl;
int curX, curY, tw;
int startRunLineX = MATRIX_WIDTH - 1; //Стартовое положение надписи на дисплее по оси Y
int XStart = 0;
int YStart = 1;

void setup() {
  Serial.begin(115200);
  //Инициируем дисплей
  sl = sizeof(symbols) / sizeof(symbols[0]);
  matrix.setIntensity(1);
  matrix.setPosition(0,7,0);
  matrix.setPosition(1,7,1);
  matrix.setPosition(2,6,0);
  matrix.setPosition(3,6,1);
  matrix.setPosition(4,5,0);
  matrix.setPosition(5,5,1);
  matrix.setPosition(6,4,0);
  matrix.setPosition(7,4,1);
  matrix.setPosition(8,3,0);
  matrix.setPosition(9,3,1);
  matrix.setPosition(10,2,0);
  matrix.setPosition(11,2,1);
  matrix.setPosition(12,1,0);
  matrix.setPosition(13,1,1);
  matrix.setPosition(14,0,0);
  matrix.setPosition(15,0,1);

  //Запускаем OTA
  ArduinoOTA.onStart([]() {
    Serial.println("Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();

  irrecv.enableIRIn();
}

void loop() {
  ArduinoOTA.handle();
  matrix.fillScreen(0);
  matrix.setIntensity(7);
  runText("Hello World!", 0, 7, true);
  matrix.write();

  //Работа с пультом
  if (irrecv.decode(&results)) {
    switch (results.value) {
      /*case 16738455: pultcode = 1; break; //1-температура на улице
      case 16750695: pultcode = 2; break; //2-влажность на улице
      case 16756815: pultcode = 3; break; //3-давление
      case 16724175: pultcode = 4; break; //4-температура 1 этаж
      case 16718055: pultcode = 5; break; //5-влажность 1 этаж
      case 16743045: pultcode = 6; break; //6-температура 2 этаж
      case 16716015: pultcode = 7; break; //7-влажность 2 этаж
      case 16726215: pultcode = 8; break; //8-время
      case 16734885: pultcode = 9; break; //9-дата
      case 16730805: pultcode = 10; break; //10-IP адрес
      case 16728765: pultcode = 11; break; //*-синхронизация времени с интернетом
      case 16732845: pultcode = 12; break; //#-
      case 16720605: pultcode = 13; break; //влево-
      case 16736925: pultcode = 14; break; //вверх-
      case 16761405: pultcode = 15; break; //вправо-
      case 16754775: pultcode = 16; break; //вниз-*/
      case 16712445: ESP.restart(); break; //ОК-перезагрузка
    }
    irrecv.resume();  // Receive the next value
  }
}

bool runText(String text, int startX, int startY, bool state){//вывод статического текста
  int i;
  byte n;
  uint32_t vertPixels;
  byte fin = 0;
  unsigned long tp;
  tw = countFraseLength(text);
  curX=startX + startRunLineX;
  curY=startY;
  for (i=0;i<text.length();i++){
    byte sym = (byte)text[i];
    if ((sym == 208) || ((sym == 209)))
    {
      i++;
      sym = (byte)text[i];
    }
    if (sym == 194){
      i++;
    }
    n=getArrayIndex(sym,sl,1);
    for (byte j=0;j<12;j++){
      vertPixels=pgm_read_word(&(font12[n][j]));
      if ((j==0)||(vertPixels>0)){//только первая колонка и не пустые колонки
        getPixel12 (vertPixels, startY, state);
      }
    }
    curX++;
  }
  if (startRunLineX >= 0 - tw){//каждый кадр смещаем начало отрисовки бегущей строки на 1 пиксель влево от правого края матрицы
    startRunLineX--;
  }
  else {startRunLineX = MATRIX_WIDTH - 1; fin = 1;}
  tp = millis();
  while (millis() - tp != 25){}
  return fin;
}

byte getPixel12 (uint32_t vertPixels, byte startY, bool tstate) {
   byte pixel;
   for (int k = 0; k < 10; k++) {
        pixel = ((vertPixels >> k) & 0x01);
        if (pixel==1){
          //if (curX >= 0 && curX < MATRIX_WIDTH && curY >=0 && curY < MATRIX_HEIGHT){
            //leds[curY][curX] = tstate;
            matrix.drawPixel(curX,curY,tstate);
          //}
        }
        curY++;
    }
    curY=startY;
    curX++;
}

byte getArrayIndex(byte znach, byte ln, byte an){
  for (byte n=0;n<ln;n++) {
    if (an == 1){
      if (symbols[n] == znach){
       return n;
      }
    }
    else {
      /*if (smallnum[n] == znach){
        return n;
      }*/
    }
  }
}

int countFraseLength(String text){//считаем длину строки
    int i, n;
    uint32_t vertPixels;

    int l=0;
    for (i=0;i<text.length();i++){
      byte sym = (byte)text[i];
      if ((sym == 208) || ((sym == 209)))
      {
        i++;
        sym = (byte)text[i];
      }
      if (sym == 194){
        i++;
      }

      n=getArrayIndex(sym,sl,1);
      for (byte j=0;j<12;j++){
         vertPixels=pgm_read_word(&(font12[n][j]));
         if ((j==0)||(vertPixels>0)){//только первая колонка и не пустые колонки
             l++;
         }
         if (j==11){//в конце каждого символа добавляем пробел
            l++;
         }
       }
    }
  return l;
}

void WIFIinit() {
  WiFi.mode(WIFI_STA);
  byte tries = 60;
  String _ssid = "DVKH24";
  String _password = "Njrvfrjdf_1947";
  WiFi.begin(_ssid.c_str(), _password.c_str());
  while (--tries && WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(1000);
  }
  if (WiFi.status() != WL_CONNECTED)
  {
    // Если не удалось подключиться запускаем в режиме AP
    StartAPMode();
  }
  else {
    // Иначе удалось подключиться отправляем сообщение
    // о подключении и выводим адрес IP
    delay(1000);
  }
}


bool StartAPMode() {
  int IP1 = 10;
  int IP2 = 10;
  int IP3 = 10;
  int IP4 = 10;
  IPAddress apIP(IP1, IP2, IP3, IP4);
  // Отключаем WIFI
  WiFi.disconnect();
  // Меняем режим на режим точки доступа
  WiFi.mode(WIFI_AP);
  // Задаем настройки сети
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  // Включаем WIFI в режиме точки доступа с именем и паролем
  // хронящихся в переменных _ssidAP _passwordAP
  String _ssidAP = "MYDev";
  String _passwordAP = "123";
  WiFi.softAP(_ssidAP.c_str(), _passwordAP.c_str());
}
Вот вставил и прошил, чтобы проверить на всякий случай. Разницы нет, да и не должно было быть. Ведь в библиотеке при инициализации класса задается яркость 7.
 
Вот убрал все. разобрал корпус и прошил. Для организации сброса сделал его после 1 минуты после включения питания. Как и раньше по включении на экране ничего нет, после сброса через минуту на экране как и положено бежит строка.
Код:
#include <font12.h>
#include <Adafruit_GFX.h> //new
#include <Max72xxPanel.h> //new

const uint8_t CS_PIN_DISPL = 15;

const int symbols[] = {32, 37, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 194};

const uint8_t X_DEVICES = 2;
const uint8_t Y_DEVICES = 8;
const uint8_t MATRIX_WIDTH = 64, MATRIX_HEIGHT = 16; //Общие размеры матрицы дисплея
Max72xxPanel matrix = Max72xxPanel(CS_PIN_DISPL, Y_DEVICES, X_DEVICES);

byte sl;
int curX, curY, tw;
int startRunLineX = MATRIX_WIDTH - 1; //Стартовое положение надписи на дисплее по оси Y
int XStart = 0;
int YStart = 1;

void setup() {
  Serial.begin(115200);
  //Инициируем дисплей
  sl = sizeof(symbols) / sizeof(symbols[0]);
  matrix.setIntensity(1);
  matrix.setPosition(0,7,0);
  matrix.setPosition(1,7,1);
  matrix.setPosition(2,6,0);
  matrix.setPosition(3,6,1);
  matrix.setPosition(4,5,0);
  matrix.setPosition(5,5,1);
  matrix.setPosition(6,4,0);
  matrix.setPosition(7,4,1);
  matrix.setPosition(8,3,0);
  matrix.setPosition(9,3,1);
  matrix.setPosition(10,2,0);
  matrix.setPosition(11,2,1);
  matrix.setPosition(12,1,0);
  matrix.setPosition(13,1,1);
  matrix.setPosition(14,0,0);
  matrix.setPosition(15,0,1);

}

void loop() {
  matrix.fillScreen(0);
  matrix.setIntensity(7);
  runText("Hello World!", 0, 7, true);
  matrix.write();
  if (millis() > 60000) {
    ESP.restart();
 }
}

bool runText(String text, int startX, int startY, bool state){//вывод статического текста
  int i;
  byte n;
  uint32_t vertPixels;
  byte fin = 0;
  unsigned long tp;
  tw = countFraseLength(text);
  curX=startX + startRunLineX;
  curY=startY;
  for (i=0;i<text.length();i++){
    byte sym = (byte)text[i];
    if ((sym == 208) || ((sym == 209)))
    {
      i++;
      sym = (byte)text[i];
    }
    if (sym == 194){
      i++;
    }
    n=getArrayIndex(sym,sl,1);
    for (byte j=0;j<12;j++){
      vertPixels=pgm_read_word(&(font12[n][j]));
      if ((j==0)||(vertPixels>0)){//только первая колонка и не пустые колонки
        getPixel12 (vertPixels, startY, state);
      }
    }
    curX++;
  }
  if (startRunLineX >= 0 - tw){//каждый кадр смещаем начало отрисовки бегущей строки на 1 пиксель влево от правого края матрицы
    startRunLineX--;
  }
  else {startRunLineX = MATRIX_WIDTH - 1; fin = 1;}
  tp = millis();
  while (millis() - tp != 25){}
  return fin;
}

byte getPixel12 (uint32_t vertPixels, byte startY, bool tstate) {
   byte pixel;
   for (int k = 0; k < 10; k++) {
        pixel = ((vertPixels >> k) & 0x01);
        if (pixel==1){
          //if (curX >= 0 && curX < MATRIX_WIDTH && curY >=0 && curY < MATRIX_HEIGHT){
            //leds[curY][curX] = tstate;
            matrix.drawPixel(curX,curY,tstate);
          //}
        }
        curY++;
    }
    curY=startY;
    curX++;
}

byte getArrayIndex(byte znach, byte ln, byte an){
  for (byte n=0;n<ln;n++) {
    if (an == 1){
      if (symbols[n] == znach){
       return n;
      }
    }
    else {
      /*if (smallnum[n] == znach){
        return n;
      }*/
    }
  }
}

int countFraseLength(String text){//считаем длину строки
    int i, n;
    uint32_t vertPixels;

    int l=0;
    for (i=0;i<text.length();i++){
      byte sym = (byte)text[i];
      if ((sym == 208) || ((sym == 209)))
      {
        i++;
        sym = (byte)text[i];
      }
      if (sym == 194){
        i++;
      }

      n=getArrayIndex(sym,sl,1);
      for (byte j=0;j<12;j++){
         vertPixels=pgm_read_word(&(font12[n][j]));
         if ((j==0)||(vertPixels>0)){//только первая колонка и не пустые колонки
             l++;
         }
         if (j==11){//в конце каждого символа добавляем пробел
            l++;
         }
       }
    }
  return l;
}
 
Вот обычный статичный текст. Хотя разница не велика, функция на показ текста отличается только тем, что отрисовывает текст без сдвига.
Код:
#include <font12.h>
#include <Adafruit_GFX.h> //new
#include <Max72xxPanel.h> //new

const uint8_t CS_PIN_DISPL = 15;

const int symbols[] = {32, 37, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 194};

const uint8_t X_DEVICES = 2;
const uint8_t Y_DEVICES = 8;
const uint8_t MATRIX_WIDTH = 64, MATRIX_HEIGHT = 16; //Общие размеры матрицы дисплея
Max72xxPanel matrix = Max72xxPanel(CS_PIN_DISPL, Y_DEVICES, X_DEVICES);

byte sl;
int curX, curY, tw;
int startRunLineX = MATRIX_WIDTH - 1; //Стартовое положение надписи на дисплее по оси Y
int XStart = 0;
int YStart = 1;

void setup() {
  Serial.begin(115200);
  //Инициируем дисплей
  sl = sizeof(symbols) / sizeof(symbols[0]);
  matrix.setIntensity(1);
  matrix.setPosition(0,7,0);
  matrix.setPosition(1,7,1);
  matrix.setPosition(2,6,0);
  matrix.setPosition(3,6,1);
  matrix.setPosition(4,5,0);
  matrix.setPosition(5,5,1);
  matrix.setPosition(6,4,0);
  matrix.setPosition(7,4,1);
  matrix.setPosition(8,3,0);
  matrix.setPosition(9,3,1);
  matrix.setPosition(10,2,0);
  matrix.setPosition(11,2,1);
  matrix.setPosition(12,1,0);
  matrix.setPosition(13,1,1);
  matrix.setPosition(14,0,0);
  matrix.setPosition(15,0,1);

}

void loop() {
  matrix.fillScreen(0);
  matrix.setIntensity(7);
  showText12("Hello World", 1, 3, true);
  matrix.write();
  if (millis() > 60000) {
    ESP.restart();
 }
}

void showText12(String text, int startX, int startY, bool state){//вывод статического текста
  int i;
  byte n;
  uint32_t vertPixels;
  curX=startX;
  curY=startY;
  for (i=0;i<text.length();i++){
    byte sym = (byte)text[i];
    if ((sym == 208) || ((sym == 209)))
    {
      i++;
      sym = (byte)text[i];
    }
    if (sym == 194){
      i++;
    }
    n=getArrayIndex(sym,sl,1);
      for (byte j=0;j<12;j++){
        vertPixels=pgm_read_word(&(font12[n][j]));
        if ((j==0)||(vertPixels>0)){//только первая колонка и не пустые колонки
          getPixel12 (vertPixels, startY, state);
        }
      }
      curX++;
  }
}

byte getPixel12 (uint32_t vertPixels, byte startY, bool tstate) {
   byte pixel;
   for (int k = 0; k < 10; k++) {
        pixel = ((vertPixels >> k) & 0x01);
        if (pixel==1){
          //if (curX >= 0 && curX < MATRIX_WIDTH && curY >=0 && curY < MATRIX_HEIGHT){
            //leds[curY][curX] = tstate;
            matrix.drawPixel(curX,curY,tstate);
          //}
        }
        curY++;
    }
    curY=startY;
    curX++;
}

byte getArrayIndex(byte znach, byte ln, byte an){
  for (byte n=0;n<ln;n++) {
    if (an == 1){
      if (symbols[n] == znach){
       return n;
      }
    }
    else {
      /*if (smallnum[n] == znach){
        return n;
      }*/
    }
  }
}

int countFraseLength(String text){//считаем длину строки
    int i, n;
    uint32_t vertPixels;

    int l=0;
    for (i=0;i<text.length();i++){
      byte sym = (byte)text[i];
      if ((sym == 208) || ((sym == 209)))
      {
        i++;
        sym = (byte)text[i];
      }
      if (sym == 194){
        i++;
      }

      n=getArrayIndex(sym,sl,1);
      for (byte j=0;j<12;j++){
         vertPixels=pgm_read_word(&(font12[n][j]));
         if ((j==0)||(vertPixels>0)){//только первая колонка и не пустые колонки
             l++;
         }
         if (j==11){//в конце каждого символа добавляем пробел
            l++;
         }
       }
    }
  return l;
}
Результат тот же.
 
Сверху Снизу