Created
August 4, 2016 08:48
-
-
Save BBBSnowball/dd97339d58b94b547604be0a83e40f50 to your computer and use it in GitHub Desktop.
ESP8266 plus 7segment display with MAX7219
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2015, Majenko Technologies | |
* Copyright (c) 2016, Benjamin Koch | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without modification, | |
* are permitted provided that the following conditions are met: | |
* | |
* * Redistributions of source code must retain the above copyright notice, this | |
* list of conditions and the following disclaimer. | |
* | |
* * Redistributions in binary form must reproduce the above copyright notice, this | |
* list of conditions and the following disclaimer in the documentation and/or | |
* other materials provided with the distribution. | |
* | |
* * Neither the name of Majenko Technologies nor the names of its | |
* contributors may be used to endorse or promote products derived from | |
* this software without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
// This also uses ideas (and similar code in some places) from | |
// https://github.com/tzapu/WiFiManager | |
// MIT license, (c) 2015 tzapu | |
#include <ESP8266WiFi.h> | |
#include <ESP8266WebServer.h> | |
#include <ESP8266mDNS.h> | |
#include <DNSServer.h> | |
#include "LedControl.h" | |
const char ssid[] = "wifidisplay"; | |
#define password NULL | |
const bool captivePortal = true; | |
//const char defaultText[] = "Herzlichen Glueckwunsch."; | |
const char defaultText[] = "HERZLICHEN GLUECKWUNSCH."; | |
#define IP(a,b,c,d) (IPAddress((uint32_t)((a) | ((b)<<8) | ((c)<<16) | ((d)<<24)))) | |
IPAddress myIp = IP(192, 168, 1, 1); | |
ESP8266WebServer server(80); | |
DNSServer dnsServer; | |
// data on pin 14, clk on 13, cs on 12, one device | |
LedControl sevenseg = LedControl(14,13,12,1); | |
const int led = 0; | |
void handleRoot(); | |
void handleNotFound(); | |
void changeText(); | |
void scrollText(); | |
void setText(const char* text); | |
void setup() { | |
pinMode(led, OUTPUT); | |
digitalWrite(led, 0); | |
Serial.begin(115200); | |
Serial.print(F("Clear 7seg display...\t")); | |
sevenseg.shutdown(0,false); | |
sevenseg.setIntensity(0,8); | |
sevenseg.clearDisplay(0); | |
Serial.println("done"); | |
Serial.print(F("Open AP with SSID '")); | |
Serial.print(ssid); | |
if (password) { | |
Serial.print(F("' and password '")); | |
Serial.print(password); | |
} | |
Serial.print(F("'...\t")); | |
WiFi.softAPConfig(myIp, | |
captivePortal ? myIp : IP(0, 0, 0, 0), | |
IP(255, 255, 255, 0)); | |
WiFi.softAP(ssid, password); | |
Serial.println("done"); | |
static WiFiEventHandler connected = WiFi.onSoftAPModeStationConnected( | |
[](const WiFiEventSoftAPModeStationConnected&) { | |
Serial.println(F("client connected")); | |
} | |
); | |
static WiFiEventHandler disconnected = WiFi.onSoftAPModeStationDisconnected( | |
[](const WiFiEventSoftAPModeStationDisconnected&) { | |
Serial.println(F("client disconnected")); | |
} | |
); | |
Serial.print(F("Starting mDNS responder...\t")); | |
if (MDNS.begin("display", myIp)) { | |
Serial.println(F("done")); | |
} else { | |
Serial.println(F("failed")); | |
} | |
if (captivePortal) { | |
Serial.print(F("Starting DNS server...\t")); | |
dnsServer.setErrorReplyCode(DNSReplyCode::NoError); | |
dnsServer.start(53, "*", WiFi.softAPIP()); | |
Serial.println(F("done")); | |
} | |
Serial.print(F("Starting HTTP server...\t")); | |
server.on("/", handleRoot); | |
server.on("/t", changeText); | |
server.onNotFound ( handleNotFound ); | |
server.begin(); | |
Serial.println(F("done")); | |
if (defaultText) | |
setText(defaultText); | |
} | |
void loop() { | |
dnsServer.processNextRequest(); | |
server.handleClient(); | |
scrollText(); | |
} | |
const char mainPage[] = | |
"<html>" | |
"<head><title>WiFi display</title></head>" | |
"<body>" | |
"<h1>WiFi display</h1>" | |
"<form action=\"/t\" method=\"POST\">" | |
"<p>" | |
"<label for=\"t\">Text: </label>" | |
"<input type=\"text\" name=\"t\" id=\"t\"/>" | |
"</p>" | |
"<p>" | |
"<input type=\"submit\" value=\"Display text\"/>" | |
"</p>" | |
"</form>" | |
"</body>" | |
"</html>"; | |
void handleRoot() { | |
Serial.println("handleRoot"); | |
digitalWrite(led, 1); | |
server.send (200, "text/html", mainPage); | |
digitalWrite(led, 0); | |
} | |
void handleNotFound() { | |
Serial.print("handleNotFound: "); | |
Serial.println(server.uri()); | |
if (captivePortal && server.uri() != String("/favicon.ico")) { | |
// redirect everything to root page because we are a captive portal | |
// (Chrome/Android will try /generate_204, Windows will try /fwlink) | |
server.sendHeader("Location", "http://192.168.1.1/", true); | |
server.send(302, "text/plain", ""); | |
// stop() is needed because we send no content length | |
server.client().stop(); | |
} else { | |
server.send(404, "text/plain", "not found"); | |
} | |
} | |
static uint8_t sevensegBuffer[64]; | |
static uint8_t sevensegLength = 0; | |
static uint8_t sevensegPos = 0; | |
static unsigned long long sevensegNextScrollTime = 0; | |
#define SEVENSEG_SCROLL_DELAY 500 | |
#define INV 0x01 | |
static const uint8_t sevensegAsciiToPattern[] PROGMEM = { | |
// space, special chars (32-47) | |
0x00, 0xb0, 0x22, INV, INV, INV, INV, 0x20, INV, INV, INV, INV, 0x04, 0x01, 0x80, INV, | |
// numbers (48-57) | |
0x7e, 0x30, 0x6d, 0x79, 0x33, 0x5b, 0x5f, 0x70, 0x7f, 0x7b, | |
// more special chars (58-63) | |
0x80, 0x90, INV, INV, INV, 0xe1, INV, | |
// upper-case letters (64-90) | |
0x77, 0x7f, 0x4e, 0x7e, 0x4f, 0x47, 0x5e, 0x37, 0x30, 0x3c, 0x07, 0x0e, 0, 0x15, 0x7e, // A-O | |
0x67, 0x73, 0x05, 0x5b, 0x0f, 0x3e, 0x1c, 0, 0x37, 0x73, 0x6d, | |
// special chars (91-96) | |
INV, INV, INV, 0x40, 0x08, 0x20, | |
// lower-case letters (97-122) | |
0x77, 0x1f, 0x0d, 0x3d, 0x4f, 0x47, 0x7b, 0x17, 0x10, 0x3c, 0x07, 0x0e, 0, 0x15, 0x1d, // A-O | |
0x67, 0x73, 0x05, 0x5b, 0x0f, 0x3e, 0x1c, 0, 0x37, 0x7b, 0x6d, | |
}; | |
void sevensegShow() { | |
for (int i=0; i<8; i++) { | |
uint8_t x; | |
if ((sevensegPos+i)%256 >= sevensegLength) | |
x = 0; | |
else | |
x = sevensegBuffer[(sevensegPos+i)%256]; | |
sevenseg.setRow(0, 7-i, x); | |
} | |
} | |
void setText(const char* text) { | |
sevensegPos = 0; | |
sevensegLength = 0; | |
for (; *text && sevensegLength < sizeof(sevensegBuffer)/sizeof(*sevensegBuffer); text++) { | |
char x = *text; | |
if (x < 32 || x > 127) | |
x = 32; | |
if ((x == '.') && sevensegLength > 0) { | |
sevensegBuffer[sevensegLength-1] |= 0x80; | |
} else if (sevensegLength+1<sizeof(sevensegBuffer)/sizeof(*sevensegBuffer) | |
&& (x == 'M' || x == 'm' || x == 'W' || x == 'w')) { | |
switch (x) { | |
case 'M': | |
sevensegBuffer[sevensegLength++] = 0x66; | |
sevensegBuffer[sevensegLength++] = 0x72; | |
break; | |
case 'm': | |
sevensegBuffer[sevensegLength++] = 0x15; | |
sevensegBuffer[sevensegLength++] = 0x15; | |
break; | |
case 'W': | |
sevensegBuffer[sevensegLength++] = 0x1e; | |
sevensegBuffer[sevensegLength++] = 0x3c; | |
break; | |
case 'w': | |
sevensegBuffer[sevensegLength++] = 0x1c; | |
sevensegBuffer[sevensegLength++] = 0x1c; | |
break; | |
} | |
} else { | |
sevensegBuffer[sevensegLength++] = pgm_read_byte_near(&sevensegAsciiToPattern[x-32]); | |
} | |
} | |
sevensegShow(); | |
sevensegNextScrollTime = millis() + SEVENSEG_SCROLL_DELAY; | |
} | |
void changeText() { | |
if (server.hasArg("t")) { | |
String text = server.arg("t"); | |
Serial.print("text: "); | |
Serial.println(text); | |
setText(text.c_str()); | |
} | |
handleRoot(); | |
} | |
void scrollText() { | |
if (sevensegLength <= 8) | |
return; | |
unsigned long long m = millis(); | |
if (sevensegNextScrollTime - m >= 0 && sevensegNextScrollTime - m < 0x80000000) | |
return; | |
sevensegPos++; | |
if (sevensegPos >= sevensegLength && sevensegPos<249) | |
sevensegPos = 249; | |
sevensegShow(); | |
sevensegNextScrollTime = m + SEVENSEG_SCROLL_DELAY; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment