Светофор на ардуино с цветным дисплеем TFT 1.8″ ST7735

Пин дисплеяПин Arduino UNO
VCC5V
GNDGND
SCL (SCK)13
SDA (MOSI)11
RST (RES)9
DC (RS)8
CS10
BLK (LED)3.3V или 5V (подсветка)

Я сделал новый интересный проект — светофор на ардуино. Светофор отображается на цветном дисплее, максимально копируя настоящие светофоры.

На картинке показано, как выглядят цифры и сигналы на дисплее с этим скетчем. Вертикальная ориентация, верх со стороны пинов.

Распиновка, подключение дисплея в таблице справа. Проект собран на Arduino Uno/Nano и дисплее TFT LCD 1.8″ ST7735 SPI.

Скетч ниже:

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>

#define TFT_CS   10
#define TFT_DC   8
#define TFT_RST  9

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

#define COLOR_BG      ST77XX_BLACK
#define COLOR_GRAY    tft.color565(0x30, 0x30, 0x30)
#define COLOR_RED     ST77XX_RED
#define COLOR_YELLOW  ST77XX_YELLOW
#define COLOR_GREEN   ST77XX_GREEN

const int CENTER_X = 64;
const int TOP_Y = 25;
const int MID_Y = 80;
const int BOT_Y = 135;

int RedSig = 5;
int GreenSig = 15;

void drawSignal(int x, int y, uint16_t color, bool state) {
  uint16_t drawColor = state ? color : COLOR_GRAY;
  const int radius = 22;
  
  tft.fillCircle(x, y, radius, COLOR_BG);
  
  int rings[7] = {42, 36, 30, 24, 16, 10, 4};
  float ringRadii[7] = {25, 21, 17, 13, 9, 5, 2.5};

  for (int ring = 0; ring < 6; ring++) {
    int numPoints = rings[ring];
    float r = ringRadii[ring];
    
    for (int i = 0; i < numPoints; i++) {
      float angle = (TWO_PI * i) / numPoints - PI/2; 
      
      int px = x + round(r * cos(angle));
      int py = y + round(r * sin(angle));
      
      // Точка 3x3 крестиком
      tft.drawPixel(px, py, drawColor);
      tft.drawPixel(px - 1, py - 1, drawColor);
      tft.drawPixel(px + 1, py - 1, drawColor);
      tft.drawPixel(px - 1, py + 1, drawColor);
      tft.drawPixel(px + 1, py + 1, drawColor);
    }
  }
}

void drawDot(int x, int y, uint16_t color) {
  tft.drawPixel(x, y, color);
  tft.drawPixel(x - 1, y - 1, color);
  tft.drawPixel(x + 1, y - 1, color);
  tft.drawPixel(x - 1, y + 1, color);
  tft.drawPixel(x + 1, y + 1, color);
}

void drawSegment(int x, int y, int w, int h, uint16_t color) {
  int spacing = 2;
  
  for (int row = 0; row < h; row++) {
    for (int col = 0; col < w; col++) {
      int px = x + col * spacing * 2;
      int py = y + row * spacing * 2;
      drawDot(px, py, color);
    }
  }
}

void drawDigit(int x, int y, int digit, uint16_t color) {
  int spacing = 2;
  int segLen = 5 * spacing * 2; // 20 пикселей
  int gap = 2;
  
  int aX = x + gap;          int aY = y;                      // A - верх
  int bX = x + segLen + gap; int bY = y + gap;               // B - правый верх
  int cX = x + segLen + gap; int cY = y + segLen + gap * 2;  // C - правый низ
  int dX = x + gap;          int dY = y + segLen * 2 + gap * 3; // D - низ
  int eX = x;                int eY = y + segLen + gap * 2;  // E - левый низ
  int fX = x;                int fY = y + gap;               // F - левый верх
  int gX = x + gap;          int gY = y + segLen + gap;      // G - середина
  
  bool seg[10][7] = {
    {1,1,1,1,1,1,0}, // 0
    {0,1,1,0,0,0,0}, // 1
    {1,1,0,1,1,0,1}, // 2
    {1,1,1,1,0,0,1}, // 3
    {0,1,1,0,0,1,1}, // 4
    {1,0,1,1,0,1,1}, // 5
    {1,0,1,1,1,1,1}, // 6
    {1,1,1,0,0,0,0}, // 7
    {1,1,1,1,1,1,1}, // 8
    {1,1,1,1,0,1,1}  // 9
  };
  
  uint16_t col;
  
  col = seg[digit][0] ? color : COLOR_GRAY;
  drawSegment(aX, aY, 6, 1, col); // A
  col = seg[digit][1] ? color : COLOR_GRAY;
  drawSegment(bX, bY, 1, 6, col); // B
  col = seg[digit][2] ? color : COLOR_GRAY;
  drawSegment(cX, cY, 1, 6, col); // C
  col = seg[digit][3] ? color : COLOR_GRAY;
  drawSegment(dX, dY, 6, 1, col); // D
  col = seg[digit][4] ? color : COLOR_GRAY;
  drawSegment(eX, eY, 1, 6, col); // E
  col = seg[digit][5] ? color : COLOR_GRAY;
  drawSegment(fX, fY, 1, 6, col); // F
  col = seg[digit][6] ? color : COLOR_GRAY;
  drawSegment(gX, gY, 6, 1, col); // G
}

void drawNumber(int value, char color) {
  int x = CENTER_X;
  int y = MID_Y;
  
  uint16_t digitColor;
  if (color == 'R') {
    digitColor = COLOR_RED;
  } else if (color == 'G') {
    digitColor = COLOR_GREEN;
  } else {
    digitColor = COLOR_YELLOW;
  }
  
  int spacing = 2;
  int segLen = 5 * spacing * 2; // 20
  int gap = 2;
  int digitW = segLen + gap * 2; // 24
  int digitH = segLen * 2 + gap * 3; // 46
  int totalW = digitW * 2 + 4;
  int startX = x - totalW / 2;
  int startY = y - digitH / 2;
  
  if (value == -1) {
    drawDigit(startX, startY, 8, COLOR_GRAY);
    drawDigit(startX + digitW + 4, startY, 8, COLOR_GRAY);
    return;
  }
  
  if (value < 0) value = 0;
  if (value > 99) value = 99;
  
  int tens = value / 10;
  int units = value % 10;
  
  drawDigit(startX, startY, 8, COLOR_GRAY);
  drawDigit(startX + digitW + 4, startY, 8, COLOR_GRAY);

  drawDigit(startX, startY, tens, digitColor);
  drawDigit(startX + digitW + 4, startY, units, digitColor);
}

void setup() {
  tft.initR(INITR_BLACKTAB);
  tft.setRotation(2);
  tft.fillScreen(COLOR_BG);
  
  drawSignal(CENTER_X, TOP_Y, COLOR_GRAY, 0);
  drawSignal(CENTER_X, MID_Y, COLOR_GRAY, 0);
  drawSignal(CENTER_X, BOT_Y, COLOR_GRAY, 0);
}

void loop() {
  drawSignal(CENTER_X, MID_Y, COLOR_GRAY, 0);
  drawSignal(CENTER_X, TOP_Y, COLOR_RED, 1);
  
  for (int i = RedSig; i >= 1; i--) {
    drawNumber(i, 'R');
    delay(1000);
  }
  
  drawSignal(CENTER_X, TOP_Y, COLOR_GRAY, 0);
  drawSignal(CENTER_X, BOT_Y, COLOR_GREEN, 1);
  
  for (int i = GreenSig; i >= 4; i--) {
    drawNumber(i, 'G');
    delay(1000);
  }

  for (int i = 3; i >= 1; i--) {
    drawNumber(i, 'G');
    drawSignal(CENTER_X, BOT_Y, COLOR_GREEN, 1);
    delay(500);

    drawNumber(-1, 'G');
    drawSignal(CENTER_X, BOT_Y, COLOR_GREEN, 0);

    delay(500);
  }

  drawNumber(-1, 'G');
  drawSignal(CENTER_X, MID_Y, COLOR_YELLOW, 1);
  delay(2000);
}

Похожие записи

Добавить комментарий