上次帶大家簡單瞭解了esp8266這個超高性價比的物聯網和智能家居神器,今天我們就用它和max7219來控制LED點陣顯示屏吧~ 大家想用他們來顯示點啥呢?時間還是天氣?或者是滾動字幕?
一、ESP8266和MAX7219是啥?
- ESP8266簡介:
ESP8266是一個非常適合用於物聯網和家庭智能項目的wifi模塊。它的售價非常低廉,在某寶上一塊ESP8266開發板只要10幾塊錢!
ESP8266的介紹和入門指南可以參見我上次寫的這篇文章:
- MAX7219簡介:
MAX7219是一種集成化的串行輸入/輸出顯示驅動器,用它可以在LED點陣屏幕方便地顯示你想要的內容。我買到的是4合1的MAX7219點陣模塊,也只需十來塊~ 如圖:
二、配置開發環境
首先參照我上次寫的ESP8266新手指南,設置好基本環境:
>>> <<<
這裡簡單概括一下:
- 安裝串口芯片驅動(CH340或者CP2102)
- 安裝Arduino IDE
- 安裝用於Arduino IDE的ESP8266插件
- 設置開發板型號並選擇正確的COM口
根據線路圖,連接好ESP8266 NodeMCU模塊和MAX7219點陣:
實際接線效果如下:
使用的接線就是標準的母對母杜邦線,大家在購買MAX7219點陣屏幕時一般都會附送。
安裝MD_MAX72xx依賴庫:
- 進入依賴庫庫管理
- 搜索MD_MAX72xx並安裝
三、上傳代碼到ESP8266
將以下代碼貼入Arduino IDE,並修改wifi名稱和密碼:
<code>
// IP address for the ESP8266 is displayed on the scrolling display
// after startup initialisation and connected to the WiFi network.
//
// 在填寫了正確的wifi信息,並且連接電源後,ESP8266的IP會顯示在屏幕上。
// 用同一wifi下的手機或者電腦平板等訪問這個ip,就可以設置屏幕的顯示文字了。
// copyright 2020@零度橙子
// source code modified & translated from etechpath.com
//
// Connections for ESP8266 hardware SPI are:
// Vcc 3v3 LED matrices seem to work at 3.3V
// GND GND GND
// DIN D7 HSPID or HMOSI
// CS or LD D8 HSPICS or HCS
// CLK D5 CLK or HCLK
//
#include <esp8266wifi.h>
#include/<esp8266wifi.h>/<code>
#include <spi.h>
#define\tPRINT_CALLBACK\t0
#define DEBUG 0
#define LED_HEARTBEAT 0
#if DEBUG
#define\tPRINT(s, v)\t{ Serial.print(F(s)); Serial.print(v); }
#define PRINTS(s) { Serial.print(F(s)); }
#else
#define\tPRINT(s, v)
#define PRINTS(s)
#endif
#if LED_HEARTBEAT
#define HB_LED D2
#define HB_LED_TIME 500 // in milliseconds
#endif
// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define\tMAX_DEVICES\t4
#define\tCLK_PIN\t\tD5 // or SCK
#define\tDATA_PIN\tD7 // or MOSI
#define\tCS_PIN\t\tD8 // or SS
// SPI hardware interface
//MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW //edit this as per your LED matrix hardware type
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Arbitrary pins
//MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
// WiFi login parameters - network name and password
const char* ssid = "PDCN"; // 輸入你的wifi名(注意ESP8266只支持2.4Gwifi!)
const char* password = "chencheng"; // 輸入你的wifi密碼
// WiFi Server object and parameters
WiFiServer server(80);
// Global message buffers shared by Wifi and Scrolling functions
const uint8_t MESG_SIZE = 255;
const uint8_t CHAR_SPACING = 1;
const uint8_t SCROLL_DELAY = 75;
char curMessage[MESG_SIZE];
char newMessage[MESG_SIZE];
bool newMessageAvailable = false;
char WebResponse[] = "HTTP/1.1 200 OK\\nContent-Type: text/html\\n\\n";
char WebPage[] =
"" \\
"" \\
"" \\
"<title>WiFi Dispaly by OrangeZero/<title>" \\
""\\
"" \\
"" \\
"" \\
""\\" \\
"WiFi LED Display by OrangeZero
" \\
"" \\
"
" \\
"" \\
"Follow me at
" \\
" " \\
"
"" \\
"";
char *err2Str(wl_status_t code)
{
switch (code)
{
case WL_IDLE_STATUS: return("IDLE"); break; // WiFi is in process of changing between statuses
case WL_NO_SSID_AVAIL: return("NO_SSID_AVAIL"); break; // case configured SSID cannot be reached
case WL_CONNECTED: return("CONNECTED"); break; // successful connection is established
case WL_CONNECT_FAILED: return("CONNECT_FAILED"); break; // password is incorrect
case WL_DISCONNECTED: return("CONNECT_FAILED"); break; // module is not configured in station mode
default: return("??");
}
}
uint8_t htoi(char c)
{
c = toupper(c);
if ((c >= '0') && (c <= '9')) return(c - '0');
if ((c >= 'A') && (c <= 'F')) return(c - 'A' + 0xa);
return(0);
}
boolean getText(char *szMesg, char *psz, uint8_t len)
{
boolean isValid = false; // text received flag
char *pStart, *pEnd; // pointer to start and end of text
// get pointer to the beginning of the text
pStart = strstr(szMesg, "/&MSG=");
if (pStart != NULL)
{
pStart += 6; // skip to start of data
pEnd = strstr(pStart, "/&");
if (pEnd != NULL)
{
while (pStart != pEnd)
{
if ((*pStart == '%') && isdigit(*(pStart+1)))
{
// replace %xx hex code with the ASCII character
char c = 0;
pStart++;
c += (htoi(*pStart++) << 4);
c += htoi(*pStart++);
*psz++ = c;
}
else
*psz++ = *pStart++;
}
*psz = '\\0'; // terminate the string
isValid = true;
}
}
return(isValid);
}
void handleWiFi(void)
{
static enum { S_IDLE, S_WAIT_CONN, S_READ, S_EXTRACT, S_RESPONSE, S_DISCONN } state = S_IDLE;
static char szBuf[1024];
static uint16_t idxBuf = 0;
static WiFiClient client;
static uint32_t timeStart;
switch (state)
{
case S_IDLE: // initialise
PRINTS("\\nS_IDLE");
idxBuf = 0;
state = S_WAIT_CONN;
break;
case S_WAIT_CONN: // waiting for connection
{
client = server.available();
if (!client) break;
if (!client.connected()) break;
#if DEBUG
char szTxt[20];
sprintf(szTxt, "%03d:%03d:%03d:%03d", client.remoteIP()[0], client.remoteIP()[1], client.remoteIP()[2], client.remoteIP()[3]);
PRINT("\\nNew client @ ", szTxt);
#endif
timeStart = millis();
state = S_READ;
}
break;
case S_READ: // get the first line of data
PRINTS("\\nS_READ");
while (client.available())
{
char c = client.read();
if ((c == '\\r') || (c == '\\n'))
{
szBuf[idxBuf] = '\\0';
client.flush();
PRINT("\\nRecv: ", szBuf);
state = S_EXTRACT;
}
else
szBuf[idxBuf++] = (char)c;
}
if (millis() - timeStart > 1000)
{
PRINTS("\\nWait timeout");
state = S_DISCONN;
}
break;
case S_EXTRACT: // extract data
PRINTS("\\nS_EXTRACT");
// Extract the string from the message if there is one
newMessageAvailable = getText(szBuf, newMessage, MESG_SIZE);
PRINT("\\nNew Msg: ", newMessage);
state = S_RESPONSE;
break;
case S_RESPONSE: // send the response to the client
PRINTS("\\nS_RESPONSE");
// Return the response to the client (web page)
client.print(WebResponse);
client.print(WebPage);
state = S_DISCONN;
break;
case S_DISCONN: // disconnect client
PRINTS("\\nS_DISCONN");
client.flush();
client.stop();
state = S_IDLE;
break;
default: state = S_IDLE;
}
}
void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col)
// Callback function for data that is being scrolled off the display
{
#if PRINT_CALLBACK
Serial.print("\\n cb ");
Serial.print(dev);
Serial.print(' ');
Serial.print(t);
Serial.print(' ');
Serial.println(col);
#endif
}
uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t)
// Callback function for data that is required for scrolling into the display
{
static enum { S_IDLE, S_NEXT_CHAR, S_SHOW_CHAR, S_SHOW_SPACE } state = S_IDLE;
static char\t\t*p;
static uint16_t\tcurLen, showLen;
static uint8_t\tcBuf[8];
uint8_t colData = 0;
// finite state machine to control what we do on the callback
switch (state)
{
case S_IDLE: // reset the message pointer and check for new message to load
PRINTS("\\nS_IDLE");
p = curMessage; // reset the pointer to start of message
if (newMessageAvailable) // there is a new message waiting
{
strcpy(curMessage, newMessage); // copy it in
newMessageAvailable = false;
}
state = S_NEXT_CHAR;
break;
case S_NEXT_CHAR: // Load the next character from the font table
PRINTS("\\nS_NEXT_CHAR");
if (*p == '\\0')
state = S_IDLE;
else
{
showLen = mx.getChar(*p++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf);
curLen = 0;
state = S_SHOW_CHAR;
}
break;
case S_SHOW_CHAR:\t// display the next part of the character
PRINTS("\\nS_SHOW_CHAR");
colData = cBuf[curLen++];
if (curLen < showLen)
break;
// set up the inter character spacing
showLen = (*p != '\\0' ? CHAR_SPACING : (MAX_DEVICES*COL_SIZE)/2);
curLen = 0;
state = S_SHOW_SPACE;
// fall through
case S_SHOW_SPACE:\t// display inter-character spacing (blank column)
PRINT("\\nS_ICSPACE: ", curLen);
PRINT("/", showLen);
curLen++;
if (curLen == showLen)
state = S_NEXT_CHAR;
break;
default:
state = S_IDLE;
}
return(colData);
}
void scrollText(void)
{
static uint32_t\tprevTime = 0;
// Is it time to scroll the text?
if (millis() - prevTime >= SCROLL_DELAY)
{
mx.transform(MD_MAX72XX::TSL);\t// scroll along - the callback will load all the data
prevTime = millis();\t\t\t// starting point for next time
}
}
void setup()
{
#if DEBUG
Serial.begin(115200);
PRINTS("\\n[MD_MAX72XX WiFi Message Display]\\nType a message for the scrolling display from your internet browser");
#endif
#if LED_HEARTBEAT
pinMode(HB_LED, OUTPUT);
digitalWrite(HB_LED, LOW);
#endif
// Display initialisation
mx.begin();
mx.setShiftDataInCallback(scrollDataSource);
mx.setShiftDataOutCallback(scrollDataSink);
curMessage[0] = newMessage[0] = '\\0';
// Connect to and initialise WiFi network
PRINT("\\nConnecting to ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
PRINT("\\n", err2Str(WiFi.status()));
delay(500);
}
PRINTS("\\nWiFi connected");
// Start the server
server.begin();
PRINTS("\\nServer started");
// Set up first message as the IP address
sprintf(curMessage, "%03d:%03d:%03d:%03d", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3]);
PRINT("\\nAssigned IP ", curMessage);
}
void loop()
{
#if LED_HEARTBEAT
static uint32_t timeLast = 0;
if (millis() - timeLast >= HB_LED_TIME)
{
digitalWrite(HB_LED, digitalRead(HB_LED) == LOW ? HIGH : LOW);
timeLast = millis();
}
#endif
handleWiFi();
scrollText();
}
/<spi.h>
在這裡修改wifi名稱密碼~
點擊按鈕,上傳代碼到ESP8266 NodeMCU:
稍等片刻,上傳完成,屏幕上滾動ESP8266的IP:
四、大功告成!
打開電腦或者手機上的瀏覽器,訪問屏幕上顯示的IP地址:
在網頁上輸入任何你想要的問題,並點擊按鈕提交:
屏幕上就顯示你想要的文字啦~
到這裡我們就完成了:
- 正確使用杜邦線連接了ESP8266 NodeMCU和MAX7219 LED點陣顯示屏模塊
- 下載並安裝了MD_MAX72xx依賴庫
- 上傳代碼到ESP8266來控制點陣屏幕
- 在瀏覽器通過網頁控制點陣屏幕的顯示
大家有沒有覺得並沒有那麼難,而且成就感滿滿的呢~
今天就到這裡吧,下次教大家使用ESP8266和MAX7219製作wifi時鐘~ 或者是wifi小車?
大家有什麼還有什麼想要做的物聯網或者智能家居項目呢?在下面留言告訴我吧~
我是零度橙子,裝機愛好者,科技達人,谷歌認證雲計算架構師,大家可以關注我,瞭解有用有趣的科技知識~
閱讀更多 零度橙子 的文章