手把手教你用wifi控制顯示屏!ESP8266實踐指南(一)

上次帶大家簡單瞭解了esp8266這個超高性價比的物聯網和智能家居神器,今天我們就用它和max7219來控制LED點陣顯示屏吧~ 大家想用他們來顯示點啥呢?時間還是天氣?或者是滾動字幕?

手把手教你用wifi控制顯示屏!ESP8266實踐指南(一)

一、ESP8266和MAX7219是啥?

  • ESP8266簡介:

ESP8266是一個非常適合用於物聯網和家庭智能項目的wifi模塊。它的售價非常低廉,在某寶上一塊ESP8266開發板只要10幾塊錢

手把手教你用wifi控制顯示屏!ESP8266實踐指南(一)


ESP8266的介紹和入門指南可以參見我上次寫的這篇文章:

  • MAX7219簡介:

MAX7219是一種集成化的串行輸入/輸出顯示驅動器,用它可以在LED點陣屏幕方便地顯示你想要的內容。我買到的是4合1的MAX7219點陣模塊,也只需十來塊~ 如圖:

手把手教你用wifi控制顯示屏!ESP8266實踐指南(一)


二、配置開發環境


首先參照我上次寫的ESP8266新手指南,設置好基本環境:

>>> <<<

這裡簡單概括一下:

  • 安裝串口芯片驅動(CH340或者CP2102)
  • 安裝Arduino IDE
  • 安裝用於Arduino IDE的ESP8266插件
  • 設置開發板型號並選擇正確的COM口


根據線路圖,連接好ESP8266 NodeMCU模塊和MAX7219點陣:

手把手教你用wifi控制顯示屏!ESP8266實踐指南(一)

ESP8266與MAX7219接線圖, 原圖來自於etechpath


實際接線效果如下:

手把手教你用wifi控制顯示屏!ESP8266實踐指南(一)

使用的接線就是標準的母對母杜邦線,大家在購買MAX7219點陣屏幕時一般都會附送。


安裝MD_MAX72xx依賴庫:

  • 進入依賴庫庫管理
手把手教你用wifi控制顯示屏!ESP8266實踐指南(一)

  • 搜索MD_MAX72xx並安裝
手把手教你用wifi控制顯示屏!ESP8266實踐指南(一)

三、上傳代碼到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
#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>
/<esp8266wifi.h>/<code>


在這裡修改wifi名稱密碼~

手把手教你用wifi控制顯示屏!ESP8266實踐指南(一)

點擊按鈕,上傳代碼到ESP8266 NodeMCU:

手把手教你用wifi控制顯示屏!ESP8266實踐指南(一)

稍等片刻,上傳完成,屏幕上滾動ESP8266的IP:

手把手教你用wifi控制顯示屏!ESP8266實踐指南(一)

手機拍照,成像不太好,實際的LED點陣屏幕亮度很高,效果非常棒!

四、大功告成!

打開電腦或者手機上的瀏覽器,訪問屏幕上顯示的IP地址:

在網頁上輸入任何你想要的問題,並點擊按鈕提交:

手把手教你用wifi控制顯示屏!ESP8266實踐指南(一)

屏幕上就顯示你想要的文字啦~

手把手教你用wifi控制顯示屏!ESP8266實踐指南(一)


到這裡我們就完成了:

  • 正確使用杜邦線連接了ESP8266 NodeMCU和MAX7219 LED點陣顯示屏模塊
  • 下載並安裝了MD_MAX72xx依賴庫
  • 上傳代碼到ESP8266來控制點陣屏幕
  • 在瀏覽器通過網頁控制點陣屏幕的顯示

大家有沒有覺得並沒有那麼難,而且成就感滿滿的呢~

今天就到這裡吧,下次教大家使用ESP8266和MAX7219製作wifi時鐘~ 或者是wifi小車?


大家有什麼還有什麼想要做的物聯網或者智能家居項目呢?在下面留言告訴我吧~


我是零度橙子,裝機愛好者,科技達人,谷歌認證雲計算架構師,大家可以關注我,瞭解有用有趣的科技知識~


分享到:


相關文章: