iT邦幫忙

2024 iThome 鐵人賽

DAY 28
1

LED 64x32 HUB75 燈板

LED 64x32 HUB75 介面燈板是一種常見的顯示模組,主要用於顯示圖片、文字和動畫等。

主要規格

  • 顯示解析度:

    • 尺寸:64x32 像素,即每個顯示面有 64 行和 32 列的 LED 燈點。
  • 顯示技術:

    • 顯示顏色:通常為全彩 RGB LED,每個像素由紅色、綠色和藍色 LED 組成,通過調整這三種顏色的亮度來顯示不同顏色。
    • 亮度:一般會有調整亮度的功能,亮度可以根據需求調整以適應不同的顯示環境。
  • 連接介面:

    • HUB75 介面:這是一種標準的 LED 顯示模組接口,廣泛用於各種 LED 燈板。HUB75 介面包括數據線路、時鐘線線路、選擇列線路等,用於控制 LED 燈板的顯示內容。
  • 控制方式:

    • 驅動芯片:通常內建驅動芯片(如 ICN2038、LPD8806 等),負責解析從控制器傳來的數據並驅動 LED 燈光。
    • 控制器:可以與 Arduino、Raspberry Pi、ESP32 等控制器連接,通過這些控制器來實現顯示內容的控制。
  • 電源需求:

    • 電壓:常見的工作電壓為 5V DC,但也有不同的版本需要不同的電壓。確保提供穩定的電源以保持顯示器正常工作。
    • 電流:根據燈板的亮度和顯示內容,電流要求可能有所不同,要選擇適合的電源供應器。
  • 應用範圍:

    • 廣告顯示、電子標牌、舞台背景、信息顯示板等,適用於各種需要顯示文字、圖像或動畫的場合。
  • 其他特點:

    • 防水防塵:部分燈板具有防水防塵設計,適合戶外使用。
    • 模組化設計:可以通過多個模組拼接組合,實現更大尺寸的顯示屏。

DDLab P5A LED 燈板

DDLab P5A LED 燈板是古豆哥科技教育推出的 LED 燈板控制程式開發版。您可以透過 Arduino IDE 的開發介面,進行各式的 LED 燈光程式開發。透過豐富的範例程式,學校教師可0已經過適度的修改範例程式碼,協助學生進行燈板程式實習與廣告跑馬燈應用等實驗。

主要的範例程式有:

  1. Aurora Demo 炫麗燈光展⽰程式
  2. Web Draw 無線即時繪圖範例程式
  3. Network Clock 網路時鐘程式
  4. Tetris 俄羅斯⽅塊遊戲範例程式
  5. Basic Text & Icons 基本⽂字與圖像控制程式
  6. Chinese Characters 中⽂字型顯⽰範例程式
  7. Bitmap Icon 32x32 Scroll Example 圖像捲動範例程式

執行 Arduino IDE 編譯程式碼:

  1. 選擇開發版

  1. 編譯程式

  1. 燒錄程式

遠端控制畫圖

今日,我們使用第二個 Web Draw 無線即時繪圖範例程式來進行教學。針對範例程式做了一些修改:

  1. DDLab P5A 燈板,執行燈板驅動程式與取得網路IP(192.168.1.107)。
  2. 原本執行網頁程式需要一台電腦,我們改用玩學機來當網頁伺服器(192.168.1.106)。
  3. 將原本 WebDraw 使用 Jquery 函式庫改寫成只使用 JavaScript 標準寫法的程式。

程式執行的步驟

  1. wifi.pywebDraw.htmlwebDrawDemo.py 程式碼,上傳到玩學機的 Flash。
  2. 玩學機執行 webDrawDemo.py,等命令列出現取得IP,例如 192.168.1.106,即可開啟瀏覽器執行 http://192.168.1.106,開啟 webDrawDemo.html 網頁。

  1. 點選 Connect,連線到 DDLab P5A 燈板。一開始請選擇 清除圖像,讓畫面清空。
  2. 選擇您要用的顏色,即可在這個畫布上任意畫圖。
  3. 網頁上繪製的圖形,也會即時同步到 DDLab P5A 燈板上。

程式碼

webDrawDemo.py

# 簡單WebServer 程式
import socket
from machine import Pin, PWM
import wifi
from time import sleep
import os
import network
# 設定 WiFi 連線參數
SSID = 'DoraHome300M'
PASSWORD = '0975393503@'
# 其他主程式邏輯
# 例如:啟動網頁伺服器或其他應用
# 讀取 index.html 檔案的內容
def read_html_file():
    try:
        with open('webDraw.html', 'r') as file:
            return file.read()
    except Exception as e:
        print("無法讀取 index.html 檔案:", e)
        return "<h1>500 Internal Server Error</h1>"
    
# 建立套接字
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]

s = socket.socket()
s.bind(addr)
s.listen(1)

print('伺服器啟動,等待連接...')
station = wifi.connect(SSID, PASSWORD)
while True:
    cl, addr = s.accept()
    print('客戶端連接來自', addr)
    
    # 接收 HTTP 請求
    request = cl.recv(1024)
    print('請求內容:', request)
    
    # 讀取並發送 index.html 檔案的內容
    response = read_html_file()
    
    cl.send('HTTP/1.1 200 OK\r\n')
    cl.send('Content-Type: text/html\r\n')
    cl.send('Connection: close\r\n\r\n')
    cl.sendall(response)
    
    # 關閉連接
    cl.close()

webDraw.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>玩學機網頁控制燈板畫圖程式 Web Drawing LED Panel</title>
    <style type="text/css">
        .divTable { display: table; }
        .divTableRow { display: table-row; }
        .divTableCell { border: 1px solid #444444; display: table-cell; height: 10px; width: 10px; }
        .unselectable {
            -moz-user-select: -moz-none;
            -khtml-user-select: none;
            -webkit-user-select: none;
            -o-user-select: none;
            user-select: none;
        }
    </style>
</head>
<body>
    <h1>玩學機網頁控制 DDLab P5A 燈板即時繪圖程式</h1>
    <hr />
    <b>選擇顏色:</b>
    <hr />
    <input id="colorPicker" type="color" value="#ffffff">
    <button id="clearButton">清除圖像 Clear</button>
    <b>&nbsp;&nbsp;連線到 DDLab P5A 燈板 IP 位址:</b>
    <input type="text" id="IP" value="192.168.1.107">
    <button id="connectButton">Connect</button>

    <div class="divTable" style="border: 1px solid #000;">
        <div class="divTableBody" id="divTableBody"></div>
    </div>
    
    <script type="text/javascript">
        var exampleSocket;
        var displayWidth = 64;
        var displayHeight = 32;

        function createGrid(columns, rows) {
            var divTableBody = document.getElementById('divTableBody');
            for (var rowIndex = 0; rowIndex < rows; rowIndex++) {
                var row = document.createElement('div');
                row.className = 'divTableRow';
                row.setAttribute('data-ycord', rowIndex);
                divTableBody.appendChild(row);
                for (var columnIndex = 0; columnIndex < columns; columnIndex++) {
                    var cell = document.createElement('div');
                    cell.className = 'divTableCell unselectable';
                    cell.setAttribute('id', 'cell' + (rowIndex * columns + columnIndex));
                    cell.setAttribute('data-xcord', columnIndex);
                    cell.style.backgroundColor = 'rgb(0, 0, 0)';
                    cell.addEventListener('mousedown', handleMouseDown);
                    cell.addEventListener('mouseenter', handleMouseEnter);
                    row.appendChild(cell);
                }
            }
        }

        function handleMouseDown(e) {
            if (e.buttons == 1) {
                handleCellChange(this, document.getElementById('colorPicker').value);
            } else if (e.buttons == 2) {
                handleCellChange(this, "#000000");
            }
        }

        function handleMouseEnter(e) {
            if (e.buttons == 1) {
                handleCellChange(this, document.getElementById('colorPicker').value);
            } else if (e.buttons == 2) {
                handleCellChange(this, "#000000");
            }
        }

        function handleCellChange(element, colorVal) {
            element.style.backgroundColor = colorVal;
            sendWebsocketMessage(element, colorVal);
        }

        function sendWebsocketMessage(element, colorVal) {
            var xCord = element.getAttribute('data-xcord');
            var yCord = element.parentElement.getAttribute('data-ycord');
            var convertedColour = convertColourToRGB565(colorVal);
            var message = '0:' + xCord + ',' + yCord + ',0x' + convertedColour;
            if (exampleSocket && exampleSocket.readyState === WebSocket.OPEN) {
                exampleSocket.send(message);
            } else {
                console.error("WebSocket is not open.");
            }
        }

        function convertColourToRGB565(colour) {
            var r = parseInt(colour.slice(1, 3), 16);
            var g = parseInt(colour.slice(3, 5), 16);
            var b = parseInt(colour.slice(5, 7), 16);
            var colourInt = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
            return colourInt.toString(16).padStart(4, '0').toUpperCase();
        }

        document.getElementById("clearButton").addEventListener("click", function() {
            if (exampleSocket && exampleSocket.readyState === WebSocket.OPEN) {
                exampleSocket.send("CLEAR");
            }
            var cells = document.getElementsByClassName('divTableCell');
            for (var i = 0; i < cells.length; i++) {
                cells[i].style.backgroundColor = "rgb(0, 0, 0)";
            }
        });

        document.getElementById("connectButton").addEventListener("click", function() {
            var ipAddress = document.getElementById("IP").value;
            exampleSocket = new WebSocket("ws://" + ipAddress + ":81");
            exampleSocket.onopen = function () {
                console.log("Connected to " + ipAddress);
            };
            exampleSocket.onclose = function () {
                console.log("Disconnected from " + ipAddress);
            };
            exampleSocket.onerror = function (error) {
                console.error("WebSocket Error: ", error);
            };
        });

        document.addEventListener('DOMContentLoaded', function() {
            document.addEventListener('contextmenu', function(e) {
                e.preventDefault();
            }, false);
            createGrid(displayWidth, displayHeight);
        });
        function rgbToHex(rgb) {
            var result = rgb.match(/\d+/g);
            var r = parseInt(result[0]).toString(16).padStart(2, '0');
            var g = parseInt(result[1]).toString(16).padStart(2, '0');
            var b = parseInt(result[2]).toString(16).padStart(2, '0');
            return '#' + r + g + b;
        }
    </script>
</body>
</html>

參考資料

  1. ESP8266-Led-Matrix-Web-Draw
  2. P5A_LED_MATRIX

上一篇
27. 透過網頁來控制玩學機
下一篇
29. 自製天氣小時鐘
系列文
使用 WiFiBoy Python 玩學機來學物聯網應用 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言