Переход с УНО на ESP32

Да ладно, GPS сам не быстро выдаёт скоростя. Зато видно будет отлично. Реально спидометр на лодке нужен немного меньше, чем козе баян или зайцу стоп-сигнал. Но прикольно.

Ещё можно по прямому назначению - как электронную книгу сделать, страница 15 кб всего. Хотя для детских книжек цветной экран лучше.

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

А так спидометр сделать это в основном отображением заняться: надо бы конечно ещё и графически изобразить спидометр, будет ваще козырно. GPSов у меня штуки 3 лежат, начать да кончить.

Это просто фоновая картинка, а вот анимация стрелки интересна.

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

Питание акк 4.2в - стаб 3.3в; включается полевиком, откл через N минут при скорости около нуля. Перед отключением выводить типа путь, макс скорость.

Гармин, например, использует т.н. трансрефлективные дешевые дисплеи, они, во-первых цветные, во вторых - чем ярче солнце - тем лучше видно :slight_smile:

Из тех транс-ЖК что я видел, эл. бумага ярче на солнце. Ну и гармин непонятно что тогда рукож-ть )) неспортивно.

И да, может где-то их можно куплять? Можно тогда посмотреть. Отдельно дисплеи в смысле.

Не видал таких в продаже.
…ещё можно копилку афоризмов на каждый день сделать :slight_smile:




… и для спидометра, типа - тише едешь, дальше будешь.

От того места к которому едешь.

похоже они все были трезвенниками

Не факт, но возможно :slight_smile:

Тогда вот ещё немного мудрости от Ильича :rofl:

Ну, да. Сначала западаешь на содержание мысли, а уже потом смотришь кто сказал :slight_smile:


Решил повозиться с 4 цветами, расширить возможности исходного ПО. Пока добрался до рисования пикселей заданным цветом по координатам. Сделал, но не понимаю почему так, а не по другому.

#include <SPI.h>
#include "epd4in2_V2.h"
#include "imagedata.h"

unsigned char bufer[30000];// массив для данных цвета пикселей экрана
 Epd epd;
void setup() {
 /////////////////////
 epd.Init_4Gray();
 /*
 Dis_Cvet(3);Buf_Ris();
 delay(2000);
  Dis_Cvet(2);Buf_Ris();
 delay(2000);
  Dis_Cvet(1);Buf_Ris();
 delay(2000);
  Dis_Cvet(0);Buf_Ris();
 delay(2000);
 */
 //Dis_Cvet(3);Pixel(0,0,0);Pixel(399,0,0);Pixel(0,299,0);Pixel(399,299,0);
  
 for(int i=0;i<400;i++){
  for(int j=0;j<300;j++){
  if(i%60<30&&j%60<30){Pixel(i,j,0);}
  if(i%60<60&&i%60>=30&&j%60<30){Pixel(i,j,2);}
  if(i%60<60&&i%60>=30&&j%60>=30&&j%60<60){Pixel(i,j,1);}
  if(i%60<30&&j%60>=30&&j%60<60){Pixel(i,j,3);}      
 }
 }
 
 Buf_Ris();
 // epd.Clear();
////////////////
epd.Sleep();
}

void loop() {
  // put your main code here, to run repeatedly:
}
/////////////////////
void Buf_Ris(){//
 epd.Buf_4GrayDisplay(bufer,0,0,400,300);// самописная функция на основе штатной epd.Set_4GrayDisplay(gImage_4in2_4Gray4, 0, 0, 400, 300); 
}
/////////////////////
void Dis_Cvet(int cvet){//раскраска экрана заданным цветом
for(int k=0;k<30000;k++){
if(cvet==3){bufer[k]=0b00000000;}//белый цвет
if(cvet==0){bufer[k]=0b11111111;}//чёрный цвет
if(cvet==2){bufer[k]=0b01010101;}//светло-серый цвет
if(cvet==1){bufer[k]=0b10101010;}// тёмно-серый цвет    
}
}
/////////////////////
void Pixel(int x,int y,int cvet){//рисование пикселя по координатам заданным цветом
if(x<400&&y<300){
//bitWrite(value, bit, bitvalue)  Ставит бит под номером bit в состояние bitvalue (0 или 1) в числе value  
if(cvet==3){bitWrite(bufer[(2*400*y+2*x+1)/8],7-(2*400*y+2*x+1)%8 ,0);bitWrite(bufer[(2*400*y+2*x+1)/8],7-((2*400*y+2*x+1)%8)+1 ,0);}//белый цвет
if(cvet==0){bitWrite(bufer[(2*400*y+2*x+1)/8],7-(2*400*y+2*x+1)%8 ,1);bitWrite(bufer[(2*400*y+2*x+1)/8],7-((2*400*y+2*x+1)%8)+1 ,1);}//чёрный цвет
if(cvet==2){bitWrite(bufer[(2*400*y+2*x+1)/8],7-(2*400*y+2*x+1)%8 ,1);bitWrite(bufer[(2*400*y+2*x+1)/8],7-((2*400*y+2*x+1)%8)+1 ,0);}//светло-серый цвет
if(cvet==1){bitWrite(bufer[(2*400*y+2*x+1)/8],7-(2*400*y+2*x+1)%8 ,0);bitWrite(bufer[(2*400*y+2*x+1)/8],7-((2*400*y+2*x+1)%8)+1 ,1);}// тёмно-серый цвет     
}
}
/////////////////////



Почему нужна +1 в выражение : bufer[(2400y+2*x+1)/8]? А без неё отображение не корректное.


С рисованием пикселя неясно, зато ясно с остальным - берём файл графики из библиотеки и просто заменяем рисование пикселя на свой вариант во всех желаем функциях типа отрезок, окружность, круг, квадрат, треугольник и т.д.
… видимо производители не писали под ардуино потому, что в ней невозможно вместить буфер экрана…Хотя есть же в ней и ESP32 и RP2040.


Спойлер

#include <SPI.h>
#include "epd4in2_V2.h"
#include "imagedata.h"

unsigned char bufer[30000];// массив для данных цвета пикселей экрана
 Epd epd;
void setup() {
 /////////////////////
 epd.Init_4Gray();
 
  //закраска всего экрана 4 цветами поочерёдно
 Dis_Cvet(3);Buf_Ris();
 delay(2000);
  Dis_Cvet(2);Buf_Ris();
 delay(2000);
  Dis_Cvet(1);Buf_Ris();
 delay(2000);
  Dis_Cvet(0);Buf_Ris();
 delay(2000);
//"шахматное поле 4 цвета"
 for(int i=0;i<400;i++){
  for(int j=0;j<300;j++){
  if(i%60<30&&j%60<30){Pixel(i,j,0);}
  if(i%60<60&&i%60>=30&&j%60<30){Pixel(i,j,2);}
  if(i%60<60&&i%60>=30&&j%60>=30&&j%60<60){Pixel(i,j,1);}
  if(i%60<30&&j%60>=30&&j%60<60){Pixel(i,j,3);}      
 }
 }
  Buf_Ris();
  delay(3000);
 //разноцветные отрезки-лучи
 Dis_Cvet(1);
 for(int i=0;i<400;i=i+20){
 DrawLine(0, 0, i, 299, (i/20)%4);DrawLine(399, 0, i, 299, (i/20)%4);
 if(i<300){ DrawLine(0, 0, 399, i,(i/20)%4); DrawLine(399, 0, 0, i,(i/20)%4);}
 }
// 
 Buf_Ris();
 delay(3000);
//вывод картинок одноцветных заданного цвета изображения и фона
 Dis_Cvet(3);
 drawBitmap(50,50,znak_2,96,96,3,2);
 drawBitmap(150,100,znak_2,96,96,2,1);
 drawBitmap(250,150,znak_2,96,96,3,0);
 Buf_Ris();
 delay(3000);
 //вывод прямоугольников, окружностей, кругов
 Dis_Cvet(3);
  DrawRectangle(10,10,390,290,2);DrawRectangle(20,20,380,280,1);DrawRectangle(30,30,370,270,0);
  DrawFilledRectangle(60,60,340,240,1);
  DrawCircle(200,150,70,2); DrawCircle(200,150,60,0);DrawCircle(200,150,50,3);DrawFilledCircle(200,150,40,0);DrawFilledCircle(200,150,20,1);
 Buf_Ris();
 // epd.Clear();
////////////////
epd.Sleep();//отключение дисплея в сон
}

void loop() {
  // put your main code here, to run repeatedly:
}
/////////////////////
void Buf_Ris(){//
 epd.Buf_4GrayDisplay(bufer,0,0,400,300);// самописная функция на основе штатной epd.Set_4GrayDisplay(gImage_4in2_4Gray4, 0, 0, 400, 300); 
}
/////////////////////
void Dis_Cvet(int cvet){//раскраска экрана заданным цветом
for(int k=0;k<30000;k++){
if(cvet==3){bufer[k]=0b00000000;}//белый цвет
if(cvet==0){bufer[k]=0b11111111;}//чёрный цвет
if(cvet==2){bufer[k]=0b01010101;}//светло-серый цвет
if(cvet==1){bufer[k]=0b10101010;}// тёмно-серый цвет    
}
}
/////////////////////
void Pixel(int x,int y,int cvet){//рисование пикселя по координатам заданным цветом
if(x<400&&y<300){
//bitWrite(value, bit, bitvalue)  Ставит бит под номером bit в состояние bitvalue (0 или 1) в числе value  
if(cvet==3){bitWrite(bufer[(2*400*y+2*x+1)/8],7-(2*400*y+2*x+1)%8 ,0);bitWrite(bufer[(2*400*y+2*x+1)/8],7-((2*400*y+2*x+1)%8)+1 ,0);}//белый цвет
if(cvet==0){bitWrite(bufer[(2*400*y+2*x+1)/8],7-(2*400*y+2*x+1)%8 ,1);bitWrite(bufer[(2*400*y+2*x+1)/8],7-((2*400*y+2*x+1)%8)+1 ,1);}//чёрный цвет
if(cvet==2){bitWrite(bufer[(2*400*y+2*x+1)/8],7-(2*400*y+2*x+1)%8 ,1);bitWrite(bufer[(2*400*y+2*x+1)/8],7-((2*400*y+2*x+1)%8)+1 ,0);}//светло-серый цвет
if(cvet==1){bitWrite(bufer[(2*400*y+2*x+1)/8],7-(2*400*y+2*x+1)%8 ,0);bitWrite(bufer[(2*400*y+2*x+1)/8],7-((2*400*y+2*x+1)%8)+1 ,1);}// тёмно-серый цвет     
}
}
/////////////////////
void DrawLine(int x0, int y0, int x1, int y1, int colored) {//рисование отрезка
    /* Bresenham algorithm */
    int dx = x1 - x0 >= 0 ? x1 - x0 : x0 - x1;
    int sx = x0 < x1 ? 1 : -1;
    int dy = y1 - y0 <= 0 ? y1 - y0 : y0 - y1;
    int sy = y0 < y1 ? 1 : -1;
    int err = dx + dy;

    while((x0 != x1) && (y0 != y1)) {
        //DrawPixel(x0, y0 , colored);
          Pixel(x0,y0,colored);
        if (2 * err >= dy) {     
            err += dy;
            x0 += sx;
        }
        if (2 * err <= dx) {
            err += dx; 
            y0 += sy;
        }
    }
}
/////////////////////

void DrawHorizontalLine(int x, int y, int line_width, int colored) {//рисование горизонтального отрезка
    int i;
    for (i = x; i < x + line_width; i++) {
        Pixel(i, y, colored);
    }
}
void DrawVerticalLine(int x, int y, int line_height, int colored) {//рисование вертикального отрезка
    int i;
    for (i = y; i < y + line_height; i++) {
        Pixel(x, i, colored);
    }
}
void DrawRectangle(int x0, int y0, int x1, int y1, int colored) {//рисование прямоугольника
    int min_x, min_y, max_x, max_y;
    min_x = x1 > x0 ? x0 : x1;
    max_x = x1 > x0 ? x1 : x0;
    min_y = y1 > y0 ? y0 : y1;
    max_y = y1 > y0 ? y1 : y0;
    
    DrawHorizontalLine(min_x, min_y, max_x - min_x + 1, colored);
    DrawHorizontalLine(min_x, max_y, max_x - min_x + 1, colored);
    DrawVerticalLine(min_x, min_y, max_y - min_y + 1, colored);
    DrawVerticalLine(max_x, min_y, max_y - min_y + 1, colored);
}
void DrawFilledRectangle(int x0, int y0, int x1, int y1, int colored) {//рисование закрашенного прямоугольника
    int min_x, min_y, max_x, max_y;
    int i;
    min_x = x1 > x0 ? x0 : x1;
    max_x = x1 > x0 ? x1 : x0;
    min_y = y1 > y0 ? y0 : y1;
    max_y = y1 > y0 ? y1 : y0;
    
    for (i = min_x; i <= max_x; i++) {
      DrawVerticalLine(i, min_y, max_y - min_y + 1, colored);
    }
}
void DrawCircle(int x, int y, int radius, int colored) {//рисование окружности
 // Bresenham algorithm 
    int x_pos = -radius;
    int y_pos = 0;
    int err = 2 - 2 * radius;
    int e2;

    do {
        Pixel(x - x_pos, y + y_pos, colored);
        Pixel(x + x_pos, y + y_pos, colored);
        Pixel(x + x_pos, y - y_pos, colored);
        Pixel(x - x_pos, y - y_pos, colored);
        e2 = err;
        if (e2 <= y_pos) {
            err += ++y_pos * 2 + 1;
            if(-x_pos == y_pos && e2 <= x_pos) {
              e2 = 0;
            }
        }
        if (e2 > x_pos) {
            err += ++x_pos * 2 + 1;
        }
    } while (x_pos <= 0);
}
void DrawFilledCircle(int x, int y, int radius, int colored) {//рисование круга
    // Bresenham algorithm 
    int x_pos = -radius;
    int y_pos = 0;
    int err = 2 - 2 * radius;
    int e2;

    do {
        Pixel(x - x_pos, y + y_pos, colored);
        Pixel(x + x_pos, y + y_pos, colored);
        Pixel(x + x_pos, y - y_pos, colored);
        Pixel(x - x_pos, y - y_pos, colored);
        DrawHorizontalLine(x + x_pos, y + y_pos, 2 * (-x_pos) + 1, colored);
        DrawHorizontalLine(x + x_pos, y - y_pos, 2 * (-x_pos) + 1, colored);
        e2 = err;
        if (e2 <= y_pos) {
            err += ++y_pos * 2 + 1;
            if(-x_pos == y_pos && e2 <= x_pos) {
                e2 = 0;
            }
        }
        if(e2 > x_pos) {
            err += ++x_pos * 2 + 1;
        }
    } while(x_pos <= 0);
}

/////////////////////
void drawBitmap(int16_t x, int16_t y,const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) {//вывод картинки по координатам, заданного размера и цветов изображения-фона

  int16_t i, j, byteWidth = (w + 7) / 8;
  uint8_t byte;

  for(j=0; j<h; j++) {
    for(i=0; i<w; i++ ) {
      if(i & 7) byte <<= 1;
      else      byte   = pgm_read_byte(bitmap + j * byteWidth + i / 8);
      if(byte & 0x80) Pixel(x+i, y+j, color);
      else            Pixel(x+i, y+j, bg);
    }
  }
}
/////////////////////

Ну вот, доделал ПО китайцев как надо. Остались молчаливые недоделки на любителя, но это уже по необходимости, если возникнет :slight_smile:

Пришёл модуль Pcf8563. Пока не работает. Время устанавливается, после повторной загрузки скетча с закоментированными строками настройки время сбрасывается в 11111…
Аналогично, после установки и отключения модуля.

Спойлер
/* Demonstration of Rtc_Pcf8563 Date Time individual functions. 
 * Set the clock to a time then loop over reading time and 
 * output the time and date to the serial console.
 *
 * I used a RBBB with Arduino IDE, the pins are mapped a 
 * bit differently. Change for your hw
 * SCK - A5, SDA - A4, INT - D3/INT1
 *
 * After loading and starting the sketch, use the serial monitor
 * to see the clock output.
 * 
 * setup:  see Pcf8563 data sheet.
 *         1x 10Kohm pullup on Pin3 INT
 *         No pullups on Pin5 or Pin6 (I2C internals used)
 *         1x 0.1pf on power
 *         1x 32khz chrystal
 *
 * Joe Robertson, jmr
 * orbitalair@gmail.com
 */ 
#include <Wire.h>
#include "Rtc_Pcf8563.h"
//SDA-A4,SCL-A5
//init the real time clock
Rtc_Pcf8563 rtc;

void setup()
{
  Serial.begin(9600);
 // Serial.println("Date and Time function test.");
  //clear out the registers
  rtc.initClock();
  //set a time to start with.
  //day, weekday, month, century(1=1900, 0=2000), year(0-99)
  rtc.setDate(10, 6, 11, 1, 24);
  //hr, min, sec
  rtc.setTime(12, 7, 45);
  
 // Serial.println("Date set to: Sunday(6) March(3) 14, 2010.  Time set to:  1:15:00 am.");
  
 // Serial.println("Now reading back from chip.");
  
}

void loop()
{
  //both format functions call the internal getTime() so that the 
  //formatted strings are at the current time/date.
  Serial.print("Hour:");
  Serial.println(rtc.getHour());
  Serial.print("Minute:");
  Serial.println(rtc.getMinute());
  Serial.print("Second:");
  Serial.println(rtc.getSecond());
  Serial.print("Weekday:");
  Serial.println(rtc.getWeekday());
  Serial.print("Day:");
  Serial.println(rtc.getDay());
  Serial.print("Month:");
  Serial.println(rtc.getMonth());
  Serial.print("Year:");
  Serial.println(rtc.getYear());
  delay(1000);
}




А кварц то внешний!


Добавил возможность вывода более одной картинки в оттенках серого.

Да, снаружи баллончик с ножками.