3

Điều khiển led ma trận với esp8266 web server

5 sao

Led ma trận với esp8266 web server. Một đề tài khá thú vị khi giúp bạn hiển thị được các thông tin mà bạn mong muốn (bài viết này là mình sẽ hiển thị các đoạn văn bản) lên thanh led ma trận 32 x 8. Sử dụng web server esp8266 để gửi dữ liệu đến led ma trận. Bạn hoàn toàn có thể nâng cấp lên thành gửi dữ liệu từ app điện thoại hoặc chọn riêng cho mình một server riêng giúp bạn có thể gửi dữ liệu đến led ma trận từ bất cứ đâu miễn sao có internet.

LED RGB module

THÀNH QUẢ CỦA DỰ ÁN

Tìm hiểu phần cứng ESP8266 và Led ma trận (32 x 8)

1. ESP8266

Sơ đồ chân ESP8266

  • Chip: ESP8266EX
  • WiFi: 2.4 GHz hỗ trợ chuẩn 802.11 b/g/n
  • Điện áp hoạt động: 3.3V
  • Điện áp vào: 5V thông qua cổng USB
  • Số chân I/O: 11 (tất cả các chân I/O đều có Interrupt/PWM/I2C/One-wire, trừ chân D0)
  • Số chân Analog Input: 1 (điện áp vào tối đa 3.3V)
  • Bộ nhớ Flash: 4MB
  • Giao tiếp: Cable Micro USB
  • Hỗ trợ bảo mật: WPA/WPA2
  • Tích hợp giao thức TCP/IP
  • Lập trình trên các ngôn ngữ: C/C++, Micropython, NodeMCU – Lua

Lưu ý: Khi code trên Arduino IDE thì khai báo các chân của ESP8266 NodeMCU các bạn khai báo theo tên ghi trên Board

chứ không phải là tên GPIO như trong sơ đồ chân.

#define Led_Pin 2

Ví dụ trên là khai báo chân cho đèn led nằm trên board, chính là chân ký hiệu D2 trên board.

Để sử dụng ESP8266 trên Arduino các bạn cần:

  1. Cài đặt thư viện cho ESP8266: Hướng dẫn cài đặt
  2. Cài driver CH340: Windows , Mac, Linux

Đã đủ để tiếp tục thực hiện dự án hiển thị dữ liệu lên led ma trận với esp8266 web server rồi.

2. Led ma trận (32 x 8)

LED MATRIX 8×8 đơn giản chỉ là 64 con LED được sắp xếp với nhau theo dạng ma trận, thành 8 hàng và 8 cột, tức là 16 chân. Vì mỗi loại LED MATRIX có sơ đồ chân riêng nên các bạn hãy tra cứu datasheet của nó để có thể lắp mạch chính xác nhé.

Trong bài viết này mình sử dụng LED matrix “row anode“, có nghĩa là các chân điều khiển hàng của ma trận chính là cực dương của LED. Đây là hình minh họa:

Sơ đồ module led ma trận 8 x 8

Bài viết này mình sử dụng thanh led 32×8, tức là ghép 4 module led 8×8 lại trên 1 board

Module led ma trận 32 x 8

Để có thể điều khiển 64 con led trên 1 module 8×8 hay chính xác hơn ở đây ta dùng loại 4 module 8×8 nên sẽ phải điều khiển tổng cộng 256 con led. Vậy vấn đề đặt ra là làm sao có thể điều khiển đến 256 con led với tốc độ sáng/tắt nhanh để có thể hiển thị được các nội dung như mình mong muốn? Câu trả lời ở đây chính là nhờ vào IC dịch Max7219. Nguyên lý điều khiển của nó như hình dưới:

Nguyên lý dịch của IC Max7219

Và với module gồm 4 led 8×8 chúng ta sẽ cần 4 con IC Max7219 tương ứng để dịch dữ liệu đến các điểm led trên từng module nhỏ, giúp ta có thể điều khiển sáng/tắt 256 led theo ý muốn.

Kết nối các phần cứng với nhau

Sơ đồ kết nối ESP8266 và module led ma trận 32 x 8

  • VCC —> 3v3 ESP8266
  • GND —> GND ESP8266
  • DIN (data in) trên led Matrix  —> GPIO13 / MOSI ESP8266 / D7
  • Clock(CLK) trên led Matrix    —> GPIO14 / SCK ESP8266
  • CS pin trên led Matrix            —> GPIO15 / D8

Như vậy là chúng ta đã tìm hiểu cấu tạo của ESP8266 và Led ma trận, tiếp theo sẽ tiến hành code để chạy dự án thôi nào –> Let go !!!

Tiến hành viết chương trình

Lưu ý trước khi code: Các bạn phải cài đặt đầy đủ thư viện cho ESP8266 và Driver, bên cạnh đó cần cài đặt thêm driver cho module led ma trận nữa nhé: Tải về và tiến hành thêm driver vào thư viện Arduino (chưa biết add thư viện thì lên GG gõ nhé =) ).

SOURCE CODE:

#include <LEDMatrixDriver.hpp>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClient.h>
const char* ssid = "";
const char* password = "";
// TCP server at port 80 will respond to HTTP requests
WiFiServer server(80);


/*
 * ESP8266 pins need wired are below:
 * DIN (data in) on Matrix ---> 13 or MOSI on ESP8266
 * Clock(CLK) on Matrix --> 14 or SCK on ESP8266
 * CS pin on Matrix define below  --->( pick 15 on esp8266)
 */
const uint8_t LEDMATRIX_CS_PIN = D8;

// Define LED Matrix dimensions (0-n) - eg: 32x8 = 31x7
const int LEDMATRIX_WIDTH = 32;  
const int LEDMATRIX_HEIGHT = 8;
const int LEDMATRIX_SEGMENTS = 4;

// The LEDMatrixDriver class instance
LEDMatrixDriver lmd(LEDMATRIX_SEGMENTS, LEDMATRIX_CS_PIN);

// Block font 8x8
byte  font[][8]= {
    { 0,0,0,0,0,0,0,0 }, //space
    { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00},   // U+0021 (!)
    { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0022 (")
    { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00},   // U+0023 (#)
    { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00},   // U+0024 ($)
    { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00},   // U+0025 (%)
    { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00},   // U+0026 (&)
    { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0027 (')
    { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00},   // U+0028 (()
    { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00},   // U+0029 ())
    { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00},   // U+002A (*)
    { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00},   // U+002B (+)
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06},   // U+002C (,)
    { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00},   // U+002D (-)
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00},   // U+002E (.)
    { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00},   // U+002F (/)
    { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00},   // U+0030 (0)
    { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00},   // U+0031 (1)
    { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00},   // U+0032 (2)
    { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00},   // U+0033 (3)
    { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00},   // U+0034 (4)
    { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00},   // U+0035 (5)
    { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00},   // U+0036 (6)
    { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00},   // U+0037 (7)
    { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00},   // U+0038 (8)
    { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00},   // U+0039 (9)
    { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00},   // U+003A (:)
    { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06},   // U+003B (//)
    { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00},   // U+003C (<)
    { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00},   // U+003D (=)
    { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00},   // U+003E (>)
    { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00},   // U+003F (?)
    { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00},   // U+0040 (@)
    { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00},   // U+0041 (A)
    { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00},   // U+0042 (B)
    { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00},   // U+0043 (C)
    { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00},   // U+0044 (D)
    { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00},   // U+0045 (E)
    { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00},   // U+0046 (F)
    { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00},   // U+0047 (G)
    { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00},   // U+0048 (H)
    { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+0049 (I)
    { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00},   // U+004A (J)
    { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00},   // U+004B (K)
    { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00},   // U+004C (L)
    { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00},   // U+004D (M)
    { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00},   // U+004E (N)
    { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00},   // U+004F (O)
    { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00},   // U+0050 (P)
    { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00},   // U+0051 (Q)
    { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00},   // U+0052 (R)
    { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00},   // U+0053 (S)
    { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+0054 (T)
    { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00},   // U+0055 (U)
    { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00},   // U+0056 (V)
    { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00},   // U+0057 (W)
    { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00},   // U+0058 (X)
    { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00},   // U+0059 (Y)
    { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00},   // U+005A (Z)
    { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00},   // U+005B ([)
    { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00},   // U+005C (\)
    { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00},   // U+005D (])
    { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00},   // U+005E (^)
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF},   // U+005F (_)
    { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0060 (`)
    { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00},   // U+0061 (a)
    { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00},   // U+0062 (b)
    { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00},   // U+0063 (c)
    { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00},   // U+0064 (d)
    { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00},   // U+0065 (e)
    { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00},   // U+0066 (f)
    { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F},   // U+0067 (g)
    { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00},   // U+0068 (h)
    { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+0069 (i)
    { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E},   // U+006A (j)
    { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00},   // U+006B (k)
    { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+006C (l)
    { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00},   // U+006D (m)
    { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00},   // U+006E (n)
    { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00},   // U+006F (o)
    { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F},   // U+0070 (p)
    { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78},   // U+0071 (q)
    { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00},   // U+0072 (r)
    { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00},   // U+0073 (s)
    { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00},   // U+0074 (t)
    { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00},   // U+0075 (u)
    { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00},   // U+0076 (v)
    { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00},   // U+0077 (w)
    { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00},   // U+0078 (x)
    { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F},   // U+0079 (y)
    { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00},   // U+007A (z)
    { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00},   // U+007B ({)
    { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00},   // U+007C (|)
    { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00},   // U+007D (})
    { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+007E (~)
    };
int x=LEDMATRIX_WIDTH, y=0;   // start top left

// Marquee text
char text[75] = " Hello ";
int len = strlen(text);
// Marquee speed
const int ANIM_DELAY = 100;
unsigned long myTime=millis();
unsigned long intro=millis();
IPAddress ip ;
  
void setup() {
  Serial.begin(115200);
  //Initialize the display  
    lmd.setEnabled(true);  
    lmd.setIntensity(10);   // 0 = low, 10 = high  
    //sprintf(text,"Connecting to %s",ssid);  
    len=strlen(text);
  // Connect to WiFi network
  pinMode(2,OUTPUT);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      //displayText(text);    
      delay(ANIM_DELAY);
      digitalWrite(2,1);
      delay(100);
      digitalWrite(2,0);
      delay(100);
  }
   // Start TCP (HTTP) server
  server.begin();
  ip = WiFi.localIP();
  String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);
  strcpy(text, ipStr.c_str());
  len=strlen(text);
  //Serial.println(ip);
}



void loop() 
{
 
 
 displayText(text);
  // Check if a client has connected
  
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
 
  // Wait for data from client to become available
  while(client.connected() && !client.available()){
    displayText(text);
    delay(1);
  }
  
  // Read the first line of HTTP request
  String req = client.readStringUntil('\r');
  
  // First line of HTTP request looks like "GET /path HTTP/1.1"
  // Retrieve the "/path" part by finding the spaces
  int addr_start = req.indexOf(' ');
  int addr_end = req.indexOf(' ', addr_start + 1);
  if (addr_start == -1 || addr_end == -1) {
    return;
  }
  req = req.substring(addr_start + 1, addr_end);
  client.flush();
  
  String s;
  String answer;
  int pos;
  if (req.indexOf('?')>0) {

    
     //Change url tags to text
     answer=req.substring(req.indexOf('=')+1);
    answer.replace('+',' ');
    //Conver HTML URL Encode to Text:
    //https://www.w3schools.com/tags/ref_urlencode.asp
    answer.replace("%21","\!");
    answer.replace("%22","\"");
    answer.replace("%23","\#");
    answer.replace("%24","\$");
    answer.replace("%25","%");
    answer.replace("%26","&");
    answer.replace("%27","\'");
    answer.replace("%28","\(");
    answer.replace("%29","\)");
    answer.replace("%2B","\+");
    answer.replace("%2C","\,");
    answer.replace("%2D","\-");
    answer.replace("%2E","\.");
    answer.replace("%2F","\/");
    answer.replace("%3A","\:");
    answer.replace("%3B","\;");
    answer.replace("%3C","\<");
    answer.replace("%3D","\=");
    answer.replace("%3E","\>");
    answer.replace("%3F","\?");
    answer.replace("%40","\@");
    answer.replace("%5B","\[");
    answer.replace("%5C","\\");
    answer.replace("%5D","\]");
    answer.replace("%5E","\^");
    answer.replace("%7B","\{");
    answer.replace("%7C","\|");
    answer.replace("%7D","\}");

    //answer.replace("%30","\0");
    //answer.replace("%31","\1");
     
    strcpy(text, answer.c_str());
    len=strlen(text);
    x=LEDMATRIX_WIDTH;
    lmd.clear();
    
    //Serial.println(req.substring(req.indexOf('=')+1));
    s="HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML><style> #header{ min-height: 20px; background-color: #666699; } #menu{ min-height: 20px; margin-top: 1%; background-color: #999999; } #body{ min-height: 200px; margin-top: 1%; } #footer{ min-height: 20px; margin-top: 1%; background-color: #666699; } #header, #menu, #body, #footer{ margin-left: 10%; margin-right: 10%; box-shadow: 3px 5px 7px #666666; border: 1px solid black; } @viewport{ zoom: 1.0; width: extend-to-zoom; } @-ms-viewport{ width: extend-to-zoom; zoom: 1.0; } </style> <html lang='en'> <head> <meta name='viewport' content='width=device-width, initial-scale=1'> <title>ESP8266 Web Server</title> </head> <body> <div id='header'><center><h1>Welcome to the ESP8266 Web Server</H1></center></div>";
    s+=" <div id='menu'><center><H2>Printing to the 4 - 8x8 Matrix</h2></center></div> ";
    s+="<div id='body'><center><div><div><br/><H3>";
    s+=answer;
    s+="<p><a href='./'>Back</a></p>";
    s+="</H3></div></div> </center> </div> <div id='footer'> </div> </body></html> ";
    //s+=req.substring(req.indexOf('=')+1);
    s+"</body></html>\r\n\r\n";
    client.print(s);
    return;
  }  
  else
  {
    
    s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
    s+="<!doctype html> <style> \#header{ min-height: 20px; background-color: \#666699; } \#menu{ min-height: 20px; margin-top: 1%; background-color: \#999999; } \#body{ min-height: 200px; margin-top: 1%; } \#footer{ min-height: 20px; margin-top: 1%; background-color: \#666699; } \#header, \#menu, \#body, \#footer{ margin-left: 10%; margin-right: 10%; box-shadow: 3px 5px 7px \#666666; border: 1px solid black; } @viewport{ zoom: 1.0; width: extend-to-zoom; } @-ms-viewport{ width: extend-to-zoom; zoom: 1.0; } </style> <html lang='en'> <head> <meta name='viewport' content='width=device-width, initial-scale=1'> <title>ESP8266 Web Server</title> </head> <body> <div id='header'><center><h1>Welcome to the ESP8266 Web Server</H1></center></div> <div id='menu'><center><H2>ENTER TEXT TO LED MATRIX</h2></center></div> <div id='body'><center><div><div><br> <form action='esp8266'> <br>TEXT HERE:<br><input type='text' maxlength='70' name='max' value=''><br><br> <input type='submit' value='SEND'></form> </div></div> </center> </div> <div id='footer'> </div> </body>";
    s += "</html>\r\n\r\n";
    client.print(s);
   return;
  }
     
}

/* This function is called in loop but 
 *  only does stuff when animimation delay
 *  is met. 
 *  
 *  This will allow loop to do other thing instead
 *  of waiting for a delay to happen.
 *  
 *  Delay=bad programming.
 */
void displayText ( char * theText)
{
   if ( myTime + ANIM_DELAY < millis()) 
   {
        myTime=millis();
        // Draw the text to the current position
        drawString(theText, len, x, 0);
        // In case you wonder why we don't have to call lmd.clear() in every loop: The font has a opaque (black) background... 
        // Toggle display of the new framebuffer
        lmd.display();  
        // Advance to next coordinate
        if( --x < len * -8 )
        {
            x = LEDMATRIX_WIDTH;
            lmd.clear();
        }
   }  
}

/**
 * This function draws a string of the given length to the given position.
 */
void drawString(char* text, int len, int x, int y )
{
  
  for( int idx = 0; idx < len; idx ++ )
  {
    int c = text[idx] - 32;

    // stop if char is outside visible area
    if( x + idx * 8  > LEDMATRIX_WIDTH )
      return;

    // only draw if char is visible
    if( 8 + x + idx * 8 > 0 )
      drawSprite( font, x + idx * 8, y, 8, 8 );
  }
}

/**
 * This draws a sprite to the given position using the width and height supplied (usually 8x8)
 */
void drawSprite( byte* sprite, int x, int y, int width, int height )
{
  // The mask is used to get the column bit from the sprite row
  byte mask = B10000000;
  
  for( int iy = 0; iy < height; iy++ )
  {
    for( int ix = 0; ix < width; ix++ )
    {
      //Yes my font is backwards so I swap it around.
      //lmd.setPixel(x + ix, y + iy, (bool)(sprite[iy] & mask ));
        lmd.setPixel(x + (width - ix), y + iy, (bool)(sprite[iy] & mask ));

      // shift the mask by one pixel to the right
      mask = mask >> 1;
    }

    // reset column mask
    mask = B10000000;
  }
}

LƯU Ý: Cần thêm tên wifi và password bạn muốn ESP8266 kết nối nhé!

const char* ssid = ""; 
const char* password = "";

Tiếp theo các bạn tiến hành nạp code và cần chú ý quan sát địa chỉ IP của ESP8266 sau khi kết nối vào mạng (led trên ESP8266 sẽ chớp tắt liên tục nếu chưa thể kết nối wifi -> cần xem lại lúc điền tên và mật khẩu wifi). Sau khi kết nối thành công led trên board ESP8266 sẽ sáng lên và bạn có thể mở Serial Monitor (góc phải trên cùng ARDUINO IDE) để quan sát địa chỉ IP. Hoặc bạn có thể quan sát trên chính thanh led ma trận sẽ chạy địa chỉ IP của ESP8266.

Địa chỉ IP của ESP8266 sau khi kết nối mạng

Tiến hành mở trình duyệt bất kỳ (máy tính / điện thoại phải cùng kết nối vào mạng bạn đã đăng nhập cho ESP8266 ở trên), nhập vào địa chỉ IP bạn có được ở bước trên và truy cập. Giao diện sau khi truy cập vào ESP8266 web server như sau:

Esp8266 web server

Đến đây là bạn đã thành công rồi, giờ chỉ việc gõ các đoạn Text và gửi đến led ma trận để thưởng thức thành quả của mình thôi. Dự án có thể phát triển thêm khá nhiều như điều khiển qua APP, gửi các icon biểu thị cảm xúc,… Hãy là người tiên phong thực hiện nó nhé.

Chúc các bạn thành công!

3 Comments

  1. xin hỏi lỗi này là gì vậy ạ. Arduino: 1.8.13 (Windows 7), Board: “NodeMCU 1.0 (ESP-12E Module), 80 MHz, Flash, Legacy (new can return nullptr), All SSL ciphers (most compatible), 4MB (FS:2MB OTA:~1019KB), 2, v2 Lower Memory, Disabled, None, Only Sketch, 115200”

    C:\Users\Administrator\Downloads\New folder\LED_MA_TR_N\LED_MA_TR_N.ino: In function ‘void drawString(char*, int, int, int)’:

    LED_MA_TR_N:312:46: error: cannot convert ‘byte (*)[8] {aka unsigned char (*)[8]}’ to ‘byte* {aka unsigned char*}’ for argument ‘1’ to ‘void drawSprite(byte*, int, int, int, int)’

    drawSprite( font, x + idx * 8, y, 8, 8 );

    ^

    exit status 1

    cannot convert ‘byte (*)[8] {aka unsigned char (*)[8]}’ to ‘byte* {aka unsigned char*}’ for argument ‘1’ to ‘void drawSprite(byte*, int, int, int, int)’

    This report would have more information with
    “Show verbose output during compilation”
    option enabled in File -> Preferences.

Trả lời

Email của bạn sẽ không được hiển thị công khai.