Работа с массивом графики

Вопрос чисто практически-экономический возник. Есть к примеру картинка марок.
0
Для вывода каждой марки я делаю вырезку марки и её массив в конверторе к которому обращаюсь в функции библиотеки , например:

tft.bmp16(0, 0, marka_5, 76,  56);

Но так долго. Проще взять массив всех марок и обращаться к массиву не с нулевого элемента, а с 4/5 от номера последнего. Как это сделать простым способом?

а как вы их храните ?)))

  1. поместите каждую марку в свой массив,
    2)или придумайте функцию для вывода картинки начиная с… заканчивая…
    3)поместив их в progmem, вроде вообще нет проблем, вывести на дисплей XY координаты, такую то картинку…
const uint8_t* marks[] = {marka_0, marka_1, marka_2, ..., marka_N};

void draw_marka(int index, int x, int y) {
tft.bmp16(x, y, marks[index], 76, 56);
}
1 лайк

Я так уже делал. Тут функция не моя, а библиотечная. Я спрашиваю синтаксис языка, как конкретно это пишется, а не типа: tft.bmp16(x, y, marks[index], 76, 56);
Так меня компиляция пошлёт подальше и всё, или скомпилируется, а работать не будет.

а библиотека какая?

Библиотека фирменная, кто эти дисплеи продаёт, но у меня не эти :slight_smile: , а похожие.

Спойлер

#ifndef _ST7789H_
#define _ST7789H_

#if ARDUINO >= 100
 #include "Arduino.h"
 #include "Print.h"
#else
 #include "WProgram.h"
#endif
#include "ERGFX.h"

#ifdef __AVR__
 #include <avr/pgmspace.h>
#endif


#define ST7789_TFTWIDTH  76
#define ST7789_TFTHEIGHT 284

#define ST7789_CASET   0x2A
#define ST7789_PASET   0x2B
#define ST7789_RAMWR   0x2C


// Color definitions
#define	ST7789_BLACK   0x0000
#define	ST7789_BLUE    0x001F
#define	ST7789_RED     0xF800
#define	ST7789_GREEN   0x07E0
#define ST7789_CYAN    0x07FF
#define ST7789_MAGENTA 0xF81F
#define ST7789_YELLOW  0xFFE0  
#define ST7789_WHITE   0xFFFF


class ST7789 : public ERGFX {

 public:

  ST7789(int8_t _CS, int8_t _DC, int8_t _MOSI, int8_t _SCLK,
		   int8_t _RST);
  ST7789(int8_t _CS, int8_t _DC, int8_t _RST = -1);

  void     begin(void),
           setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1),
           pushColor(uint16_t color),
           fillScreen(uint16_t color),
           drawPixel(int16_t x, int16_t y, uint16_t color),
           drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color),
           drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color),
           fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
             uint16_t color),
           bmp16(uint16_t x, uint16_t y, const uint8_t *pBmp, uint16_t chWidth, uint16_t chHeight);      
  uint16_t color565(uint8_t r, uint8_t g, uint8_t b);

  /* These are not for current use, 8-bit protocol only! */
  uint8_t  readdata(void),
    readcommand8(uint8_t reg, uint8_t index = 0);
  /*
  uint16_t readcommand16(uint8_t);
  uint32_t readcommand32(uint8_t);
  void     dummyclock(void);
  */  

  void     spiwrite(uint8_t),
    writecommand(uint8_t c),
    writedata(uint8_t d),
    commandList(uint8_t *addr);
  uint8_t  spiread(void);

 private:
  uint8_t  tabcolor;



  boolean  hwSPI;
#if defined (__AVR__) || defined(TEENSYDUINO)

  uint8_t mySPCR;
  volatile uint8_t *mosiport, *clkport, *dcport, *rsport, *csport;
  int8_t  _cs, _dc, _rst, _mosi, _sclk;
  uint8_t  mosipinmask, clkpinmask, cspinmask, dcpinmask;
  
#elif defined (__arm__)
    volatile RwReg *mosiport, *clkport, *dcport, *rsport, *csport;
    uint32_t  _cs, _dc, _rst, _mosi, _sclk;
    uint32_t  mosipinmask, clkpinmask, cspinmask, dcpinmask;


#elif defined(ESP32)

   volatile uint32_t  *mosiport, *clkport, *dcport, *rsport, *csport;
    uint32_t  _cs, _dc, _rst, _mosi, _sclk;
    uint32_t  mosipinmask, clkpinmask, cspinmask, dcpinmask;
#endif
};

#endif

Спойлер
/*************************************************** 
  www.buydisplay.com
 ****************************************************/

#include "TFTM2.25-1.h"
#include <limits.h>
#include "pins_arduino.h"
#include "wiring_private.h"
#include <SPI.h>
 #include "Arduino.h"

// Constructor when using software SPI.  All output pins are configurable.
ST7789::ST7789(int8_t cs, int8_t dc, int8_t mosi,
				   int8_t sclk, int8_t rst) : ERGFX(ST7789_TFTWIDTH, ST7789_TFTHEIGHT) {
  _cs   = cs;
  _dc   = dc;
  _mosi  = mosi;
  _sclk = sclk;
  _rst  = rst;
  hwSPI = false;
}


// Constructor when using hardware SPI.  Faster, but must use SPI pins
// specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.)
ST7789::ST7789(int8_t cs, int8_t dc, int8_t rst) : ERGFX(ST7789_TFTWIDTH, ST7789_TFTHEIGHT) {
  _cs   = cs;
  _dc   = dc;
  _rst  = rst;
  hwSPI = true;
  _mosi  = _sclk = 0;
}

void ST7789::spiwrite(uint8_t c) {

  //Serial.print("0x"); Serial.print(c, HEX); Serial.print(", ");

  if (hwSPI) {
#if defined (__AVR__)
      uint8_t backupSPCR = SPCR;
    SPCR = mySPCR;
    SPDR = c;
    while(!(SPSR & _BV(SPIF)));
    SPCR = backupSPCR;
#elif defined(ESP32)|| defined(TEENSYDUINO)
    SPI.transfer(c);
#elif defined (__arm__)
    SPI.setClockDivider(11); // 8-ish MHz (full! speed!)
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
    SPI.transfer(c);
#endif
  } else {
    // Fast SPI bitbang swiped from LPD8806 library
    for(uint8_t bit = 0x80; bit; bit >>= 1) {
      if(c & bit) {
	//digitalWrite(_mosi, HIGH); 
	*mosiport |=  mosipinmask;
      } else {
	//digitalWrite(_mosi, LOW); 
	*mosiport &= ~mosipinmask;
      }
      //digitalWrite(_sclk, LOW);
      *clkport &= ~clkpinmask;
       //digitalWrite(_sclk, HIGH);
      *clkport |=  clkpinmask;
    }
  }
}


void ST7789::writecommand(uint8_t c) {
  *dcport &=  ~dcpinmask;
  //digitalWrite(_dc, LOW);
  //*clkport &= ~clkpinmask; // clkport is a NULL pointer when hwSPI==true
  //digitalWrite(_sclk, LOW);
  *csport &= ~cspinmask;
  //digitalWrite(_cs, LOW);

  spiwrite(c);

  *csport |= cspinmask;
  //digitalWrite(_cs, HIGH);
}


void ST7789::writedata(uint8_t c) {
  *dcport |=  dcpinmask;
  //digitalWrite(_dc, HIGH);
  //*clkport &= ~clkpinmask; // clkport is a NULL pointer when hwSPI==true
  //digitalWrite(_sclk, LOW);
  *csport &= ~cspinmask;
  //digitalWrite(_cs, LOW);
  
  spiwrite(c);

  //digitalWrite(_cs, HIGH);
  *csport |= cspinmask;
} 
/*
// If the SPI library has transaction support, these functions
// establish settings and protect from interference from other
// libraries.  Otherwise, they simply do nothing.
#ifdef SPI_HAS_TRANSACTION
static inline void spi_begin(void) __attribute__((always_inline));
static inline void spi_begin(void) {
  SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
}
static inline void spi_end(void) __attribute__((always_inline));
static inline void spi_end(void) {
  SPI.endTransaction();
}
#else
#define spi_begin()
#define spi_end()
#endif
*/

void ST7789::begin(void) {
  if (_rst > 0) {
    pinMode(_rst, OUTPUT);
    digitalWrite(_rst, LOW);
  }

  pinMode(_dc, OUTPUT);
  pinMode(_cs, OUTPUT);
  
  csport    = portOutputRegister(digitalPinToPort(_cs));
  cspinmask = digitalPinToBitMask(_cs);
  dcport    = portOutputRegister(digitalPinToPort(_dc));
  dcpinmask = digitalPinToBitMask(_dc);

  if(hwSPI) { // Using hardware SPI
#if defined (__AVR__)
    SPI.begin();
    SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!)
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
    mySPCR = SPCR;
#elif defined(ESP32)
    SPI.begin();
  SPI.beginTransaction(SPISettings(40000000, MSBFIRST, SPI_MODE0));  
   // SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!)
   // SPI.setBitOrder(MSBFIRST);
   // SPI.setDataMode(SPI_MODE0);

#elif defined(TEENSYDUINO)
    SPI.begin();
    SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!)
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
#elif defined (__arm__)
      SPI.begin();
      SPI.setClockDivider(11); // 8-ish MHz (full! speed!)
      SPI.setBitOrder(MSBFIRST);
      SPI.setDataMode(SPI_MODE0);
#endif
  } else {
    pinMode(_sclk, OUTPUT);
    pinMode(_mosi, OUTPUT);

    clkport     = portOutputRegister(digitalPinToPort(_sclk));
    clkpinmask  = digitalPinToBitMask(_sclk);
    mosiport    = portOutputRegister(digitalPinToPort(_mosi));
    mosipinmask = digitalPinToBitMask(_mosi);
    *clkport   &= ~clkpinmask;
    *mosiport  &= ~mosipinmask;
  }

  // toggle RST low to reset
  if (_rst > 0) {
    digitalWrite(_rst, HIGH);
    delay(5);
    digitalWrite(_rst, LOW);
    delay(20);
    digitalWrite(_rst, HIGH);
    delay(150);
  }

  if (hwSPI) SPI.begin();

 
	writecommand(0xB2);
	writedata(0x0C);
	writedata(0x0C);
	writedata(0x00);
	writedata(0x33);
	writedata(0x33);

	writecommand(0xB0);
	writedata(0x00);
	writedata(0xE0);

	writecommand(0x36);
                            // writedata(0x40|0x80|0x00);//ЗДЕСЬ ИСПРАВЛЕНО !!! БЫЛО 0x00 
                             writedata(0xC0);//тоже самое (0x40|0x80|0x00)  
        
	writecommand(0x3A);
	writedata(0x05);

	writecommand(0xB7);
	writedata(0x45);

	writecommand(0xBB);
	writedata(0x1D);

	writecommand(0xC0);
	writedata(0x2C);

	writecommand(0xC2);
	writedata(0x01);

	writecommand(0xC3);
	writedata(0x19);

	writecommand(0xC4);
	writedata(0x20);

	writecommand(0xC6);
	writedata(0x0F);

	writecommand(0xD0);
	writedata(0xA4);
	writedata(0xA1);

	writecommand(0xD6);
	writedata(0xA1);

	writecommand(0xE0);
	writedata(0xD0);
	writedata(0x10);
	writedata(0x21);
	writedata(0x14);
	writedata(0x15);
	writedata(0x2D);
	writedata(0x41);
	writedata(0x44);
	writedata(0x4F);
	writedata(0x28);
	writedata(0x0E);
	writedata(0x0C);
	writedata(0x1D);
	writedata(0x1F);

	writecommand(0xE1);
	writedata(0xD0);
	writedata(0x0F);
	writedata(0x1B);
	writedata(0x0D);
	writedata(0x0D);
	writedata(0x26);
	writedata(0x42);
	writedata(0x54);
	writedata(0x50);
	writedata(0x3E);
	writedata(0x1A);
	writedata(0x18);
	writedata(0x22);
	writedata(0x25);

        writecommand(0x11);    //Exit Sleep 
      //  if (hwSPI) spi_end();
        delay(120); 		
      //  if (hwSPI) spi_begin();
        writecommand(0x29);    //Display on 
      //  if (hwSPI) spi_end();

}


void ST7789::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1,
 uint16_t y1) {
 x0+=0x52; x1+=0x52;   y0+=0x12; y1+=0x12;
  writecommand(ST7789_CASET); // Column addr set
  writedata(x0 >> 8);
  writedata(x0);     // XSTART 
  writedata(x1 >> 8);
  writedata(x1);     // XEND

  writecommand(ST7789_PASET); // Row addr set
  writedata(y0>>8);
  writedata(y0);     // YSTART
  writedata(y1>>8);
  writedata(y1);     // YEND

  writecommand(ST7789_RAMWR); // write to RAM
}


void ST7789::pushColor(uint16_t color) {
  //if (hwSPI) spi_begin();
  //digitalWrite(_dc, HIGH);
  *dcport |=  dcpinmask;
  //digitalWrite(_cs, LOW);
  *csport &= ~cspinmask;

  spiwrite(color >> 8);
  spiwrite(color);

  *csport |= cspinmask;
  //digitalWrite(_cs, HIGH);
 // if (hwSPI) spi_end();
}

void ST7789::drawPixel(int16_t x, int16_t y, uint16_t color) {

  if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;

  //if (hwSPI) spi_begin();
  setAddrWindow(x,y,x+1,y+1);

  //digitalWrite(_dc, HIGH);
  *dcport |=  dcpinmask;
  //digitalWrite(_cs, LOW);
  *csport &= ~cspinmask;

  spiwrite(color >> 8);
  spiwrite(color);

  *csport |= cspinmask;
  //digitalWrite(_cs, HIGH);
 // if (hwSPI) spi_end();
}


void ST7789::drawFastVLine(int16_t x, int16_t y, int16_t h,
 uint16_t color) {

  // Rudimentary clipping
  if((x >= _width) || (y >= _height)) return;

  if((y+h-1) >= _height) 
    h = _height-y;

  //if (hwSPI) spi_begin();
  setAddrWindow(x, y, x, y+h-1);

  uint8_t hi = color >> 8, lo = color;

  *dcport |=  dcpinmask;
  //digitalWrite(_dc, HIGH);
  *csport &= ~cspinmask;
  //digitalWrite(_cs, LOW);

  while (h--) {
    spiwrite(hi);
    spiwrite(lo);
  }
  *csport |= cspinmask;
  //digitalWrite(_cs, HIGH);
 // if (hwSPI) spi_end();
}


void ST7789::drawFastHLine(int16_t x, int16_t y, int16_t w,
  uint16_t color) {

  // Rudimentary clipping
  if((x >= _width) || (y >= _height)) return;
  if((x+w-1) >= _width)  w = _width-x;
  //if (hwSPI) spi_begin();
  setAddrWindow(x, y, x+w-1, y);

  uint8_t hi = color >> 8, lo = color;
  *dcport |=  dcpinmask;
  *csport &= ~cspinmask;
  //digitalWrite(_dc, HIGH);
  //digitalWrite(_cs, LOW);
  while (w--) {
    spiwrite(hi);
    spiwrite(lo);
  }
  *csport |= cspinmask;
  //digitalWrite(_cs, HIGH);
  //if (hwSPI) spi_end();
}

void ST7789::fillScreen(uint16_t color) {
  fillRect(0, 0,  _width, _height, color);
}

// fill a rectangle
void ST7789::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
  uint16_t color) {

  // rudimentary clipping (drawChar w/big text requires this)
  if((x >= _width) || (y >= _height)) return;
  if((x + w - 1) >= _width)  w = _width  - x;
  if((y + h - 1) >= _height) h = _height - y;

 // if (hwSPI) spi_begin();
  setAddrWindow(x, y, x+w-1, y+h-1);

  uint8_t hi = color >> 8, lo = color;

  *dcport |=  dcpinmask;
  //digitalWrite(_dc, HIGH);
  *csport &= ~cspinmask;
  //digitalWrite(_cs, LOW);

  for(y=h; y>0; y--) {
    for(x=w; x>0; x--) {
      spiwrite(hi);
      spiwrite(lo);
    }
  }
  //digitalWrite(_cs, HIGH);
  *csport |= cspinmask;
  //if (hwSPI) spi_end();
}

void ST7789::bmp16(uint16_t x, uint16_t y, const uint8_t *pBmp, uint16_t chWidth, uint16_t chHeight) {
    uint16_t i, j;
    uint16_t hwColor;
     uint8_t hi , lo ;

  // rudimentary clipping (drawChar w/big text requires this)
  if((x >= _width) || (y >= _height)) return;
  if((x + chWidth - 1) >= _width)  chWidth = _width  - x;
  if((y + chHeight - 1) >= _height) chHeight = _height - y;

 // if (hwSPI) SPI.begin();
    setAddrWindow(x, y, x+chWidth-1, y+chHeight-1);

  *dcport |=  dcpinmask;
  //digitalWrite(_dc, HIGH);
  *csport &= ~cspinmask;
  //digitalWrite(_cs, LOW);

    for(j = 0; j < chHeight; j++) {
        for(i = 0; i < chWidth; i++) {
          hi= pgm_read_byte(pBmp++);lo= pgm_read_byte(pBmp++);
          spiwrite(hi);
          spiwrite(lo);
        }
    }
   //digitalWrite(_cs, HIGH);
  *csport |= cspinmask;
 // if (hwSPI) SPI.end();   
}

// Pass 8-bit (each) R,G,B, get back 16-bit packed color
uint16_t ST7789::color565(uint8_t r, uint8_t g, uint8_t b) {
  return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}

 


так и пишется

пробовали? Покажите

1 лайк

Если функция требует именно константные указатели-
можно объявить их заранее, и обащаться через них к любому элементу массива

const uint8_t tabl[] = {0, 1, 2,  3, 4, 5};
const uint8_t * n_tabl = &tabl[3];

void setup() {
  Serial.begin(9600);
  Serial.println(*n_tabl);

}

void loop() {
  // put your main code here, to run repeatedly:

}

Screenshot_312 - копия

насколько я понял, отдельные указатели у него уже сейчас есть.

Ему хочется иметь их в массиве и работать как с массивом:


// bitmap images to show
const uint16_t vyshivka_64_32[2048] PROGMEM={
0x0000, 0x0000, 0x0000, 0x0000, 0xC880, 0xC880 ..... };

const uint16_t evening_64_32[2048] PROGMEM={
0x0000, 0x0000, 0x0000, 0x0000, 0xC880, 0xC880 ..... };


// array of bitmap pointers
const uint16_t* bitmaps[] = {evening_64_32, vyshivka_64_32};

void loop(void)
{
  static uint8_t ptr =0;
  if (ptr == (sizeof(bitmaps)/ sizeof(bitmaps[0]))) ptr =0;
  
  // draw image starting from 0,0, width 64 height 32
  dmd.drawRGBBitmap(dmd.width() - 64, 0, bitmaps[ptr], 64, 32);
  
  // show the image during 15sec
  delay(15000);
  
// blank screen 2sec
  dmd.clearScreen(true);
  delay(2000);

  // increment image pointer
  ptr++;
}

Насколько я понял - надо обращаться к разным частям массива, а функция не позвооляет почему-то это сделать( как в #6).
Или я ошибаюсь.

мы можем долго гадать, пока ТС не прояснит свои хотелки

Хорошо, попробую, если сработает, это в принципе то, что нужно. Посмотрю примеры ниже, спасибо. Сама функция такая:

void ST7789::bmp16(uint16_t x, uint16_t y, const uint8_t *pBmp, uint16_t chWidth, uint16_t chHeight) {
    uint16_t i, j;
    uint16_t hwColor;
     uint8_t hi , lo ;

  // rudimentary clipping (drawChar w/big text requires this)
  if((x >= _width) || (y >= _height)) return;
  if((x + chWidth - 1) >= _width)  chWidth = _width  - x;
  if((y + chHeight - 1) >= _height) chHeight = _height - y;

 // if (hwSPI) SPI.begin();
    setAddrWindow(x, y, x+chWidth-1, y+chHeight-1);

  *dcport |=  dcpinmask;
  //digitalWrite(_dc, HIGH);
  *csport &= ~cspinmask;
  //digitalWrite(_cs, LOW);

    for(j = 0; j < chHeight; j++) {
        for(i = 0; i < chWidth; i++) {
          hi= pgm_read_byte(pBmp++);lo= pgm_read_byte(pBmp++);
          spiwrite(hi);
          spiwrite(lo);
        }
    }
   //digitalWrite(_cs, HIGH);
  *csport |= cspinmask;
 // if (hwSPI) SPI.end();   
}

На другом дисплее, с другой библиотекой я писал сам так:

//функция вывода фрагмента фотокартинки размером w*h,x,y - положение фрагмента на экране, x1,y1,w1,h1 - выбор фрагмента из массива
void drawFoto_fragment(int x,int y, const uint8_t *bitmap,int w,int h,int x1,int y1,int w1,int h1) {
if(x<0||x+w1>240||y<0||y+h1>320){return;} 
// tft.setAddrWindow(x,y,w1,h1);
 SPI.beginTransaction(SPISettings(40000000, MSBFIRST, SPI_MODE0));
  digitalWrite(TFT_DC, HIGH);
  digitalWrite(TFT_CS, LOW);
  tft.setAddrWindow(x,y,w1,h1); 
 for(int j=0; j<h; j++) {
    for(int i=0; i<2*w; i=i+2) {
      if(i>=2*x1&&i<2*(x1+w1)&&j>=y1&&j<y1+h1){
       SPI.transfer(bitmap[i+1+j*2*w]);SPI.transfer(bitmap[i+j*2*w]);
      }  
   }
  }
  digitalWrite(TFT_CS, HIGH);
  SPI.endTransaction();
 //  
}

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

Не совсем понятно, что именно “это”.
Для начала нужно решить, как вообще организовано хранение марок.
Можно, например, хранить каждую марку в своем массиве. Тогда доступ к ней будет наиболее естественным (через массив указателей), но зато придется для рисунка из пяти марок пять раз обращаться к процедуре вывода одной марки.
Можно хранить блоки по 5 марок, но тогда для вывода единственной марки (опять же вопрос - такое может понадобиться?) нужно будет написать процедуру (если ее еще нет в библиотеке) вывода на экран фрагмента картинки.
Все зависит от того, что именно Вам нужно, но Вы забыли написать, прикрывшись словом “это” - мол пусть кто как хочет, так и понимает.

В любом случае, что бы Вы ни делали, начинать, как правило, следует с четкой формулировке по-русски - что же именно Вы хотите сделать.

если уже объявлено, и поскольку я как раз сижу с тфт дисплеями, вот может будет полезно, у кого то в сети подрезал, и чуть переписал, из за того что не запускалось

// Вывод кадра
 tft.pushImage(
30, 15,                   // Позиция X,Y
animation_width,          // Ширина
animation_height,         // Высота
walk[i]                   // Данные кадра
 );

код вывода картинки из progmem управляется через i (два файла должны лежать вместе)

https://transfiles.ru/u6ayz

#include <TFT_eSPI.h>
#include "animation_data.h"  // Подключаем данные анимации

/*
SCK → D5 (GPIO14)
MOSI → D7 (GPIO13)//sda
CS → D8 (GPIO15)
DC → D4 (GPIO2)//rs
RESET → D3 (GPIO0)
LEDA →D0
*/
//#define TFT_CS    D8  // GPIO15
//#define TFT_DC    D4  // GPIO2
//#define TFT_RST   D3  // GPIO0
#define TFT_LED   D0  // Подсветка

TFT_eSPI tft = TFT_eSPI();

void setup() {
Serial.begin(115200);
tft.init();
tft.setRotation(1);
// Управление подсветкой
pinMode(TFT_LED, OUTPUT);
digitalWrite(TFT_LED, HIGH);
tft.setTextSize(1);
tft.fillScreen(TFT_BLACK);
Serial.printf("Free RAM: %d bytes\n", ESP.getFreeHeap());
Serial.printf("Frames: %d\n", frames);
}

void loop() {
for (int i = 0; i < frames; i++) {
tft.pushImage(30, 15, animation_width, animation_height, walk[i]);
delay(40); }
}

там же и программа для создания, у кого то все подрезал в сети, но не могу найти… и чуть пришлось переделать код, иначе не работал, запускал на есп 8266

может будет полезно…

гит хаб найти не могу, а подрезал у него кажется http://www.youtube.com/watch?v=-h9Vm0Ow_Is возможно есть под видео ссылка на оригинальный проект

Мне одному непонятно, как комилятор допускает, что треий параметр в функции(#11), объявленный как константный,

void ST7789::bmp16(uint16_t x, uint16_t y, const uint8_t *pBmp, uint16_t chWidth, uint16_t chHeight) {

изменяется в стр.21?

   hi= pgm_read_byte(pBmp++);lo= pgm_read_byte(pBmp++);

P.S. Попробовал проверить на примерах. Получаеся “const” здесь относится лишь к содержимому ячейки(ячеек)памяти, на которую указывает указатель. Содержимое менять нельзя (read only), а сам указатель - можно. Не знал этого.

Если использовать dma в esp32, то можно красиво сделать.

Нет, не компилируется, а именно так понятней всего, типа начни с 1000-ного элемента, пройди 76 раз по 76 элементов…

digitalWrite(TFT_CS1,LOW);tft.bmp16(0,0,ris_0[1000],76, 76); digitalWrite(TFT_CS1,HIGH);
invalid conversion from 'unsigned char' to 'const uint8_t* {aka const unsigned char*}' [-fpermissive]

а ежели принудительно привести вот так:

digitalWrite(TFT_CS1,LOW);(const uint8_t*)(tft.bmp16(0,0,ris_0[1000],76, 76)); digitalWrite(TFT_CS1,HIGH);

Вот так компиляция прошла, на картинках проверю после работы.

digitalWrite(TFT_CS1,LOW);tft.bmp16(0,0,(const uint8_t*)ris_0[1000],76, 76); digitalWrite(TFT_CS1,HIGH);

ЫЫ справился ?)))

Для оптимизации работы с массивом всех марок и доступа к конкретной марке по смещению, вы можете использовать следующие подходы:
1. Объединение всех марок в один массив с фиксированным размером каждой марки


// Предположим, у вас все марки имеют одинаковый размер 76x56 (4256 пикселей = 8512 байт)
const uint8_t all_marks[] PROGMEM = {
    // Марка 0
    0x00, 0x00, ... // 8512 байт
    // Марка 1
    0x00, 0x00, ... // следующие 8512 байт
    // и так далее...
};

void drawMark(uint8_t markIndex) {
    // Размер одной марки в байтах
    const uint32_t markSize = 76 * 56 * 2;
    
    // Указатель на начало нужной марки
    const uint8_t* markPtr = all_marks + (markIndex * markSize);
    
    tft.bmp16(0, 0, markPtr, 76, 56);
}

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


struct Mark {
    uint8_t width;
    uint8_t height;
    const uint8_t* data;
};

const Mark marks[] PROGMEM = {
    {76, 56, marka_0},
    {76, 56, marka_1},
    // и так далее...
};

void drawMark(uint8_t markIndex) {
    Mark mark;
    memcpy_P(&mark, &marks[markIndex], sizeof(Mark));
    tft.bmp16(0, 0, mark.data, mark.width, mark.height);
}

3. Оптимизированный вариант с предварительным вычислением указателей

// Объявляем все массивы как обычно
const uint8_t marka_0[] PROGMEM = {...};
const uint8_t marka_1[] PROGMEM = {...};
// ...

// Массив указателей на все марки
const uint8_t* const all_marks[] PROGMEM = {
    marka_0,
    marka_1,
    // ...
};

void drawMark(uint8_t markIndex) {
    const uint8_t* markPtr;
    memcpy_P(&markPtr, &all_marks[markIndex], sizeof(markPtr));
    tft.bmp16(0, 0, markPtr, 76, 56);
}

4. Если марки имеют разный размер, но хранятся последовательно

// Все марки объединены в один массив с метаданными
const uint8_t all_marks[] PROGMEM = {
    // Марка 0
    76, 56, // ширина, высота
    0x00, 0x00, ... // данные
    
    // Марка 1
    80, 60, // ширина, высота
    0x00, 0x00, ... // данные
    // и так далее...
};

void drawMark(uint8_t markIndex) {
    const uint8_t* ptr = all_marks;
    uint16_t offset = 0;
    
    // Пропускаем предыдущие марки
    for(uint8_t i = 0; i < markIndex; i++) {
        uint8_t w, h;
        memcpy_P(&w, ptr + offset, 1);
        memcpy_P(&h, ptr + offset + 1, 1);
        offset += 2 + w * h * 2;
    }
    
    // Читаем размер текущей марки
    uint8_t w, h;
    memcpy_P(&w, ptr + offset, 1);
    memcpy_P(&h, ptr + offset + 1, 1);
    
    // Указатель на данные марки
    const uint8_t* markData = ptr + offset + 2;
    
    tft.bmp16(0, 0, markData, w, h);
}

Рекомендация:

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

    Если марки разного размера, используйте четвертый вариант.

    Для AVR-микроконтроллеров не забывайте использовать PROGMEM и функции чтения из программной памяти.

Пример вызова:

// Нарисовать марку с индексом 5
drawMark(5);

Это позволит вам легко обращаться к любой марке по индексу без необходимости хранить отдельные вызовы для каждой марки.

свалить все картинки в одну кучу и вычислять по смещению - это будет работать, но это же банально… Что тут обсуждать-то?