무선와이파이 코딩을 통해 스마트폰이나 무선 공유기가 설치된 PC 의 웹브라우저에서 아두이노 NodeMCU 보드의 센서 계측 결과를 FND 스타일로 비쥬얼하게 결과를 모니터링 해야 할 경우는 코딩에 의해서 FND (Finite Numeric Display)를 그래픽하게 처리해야 할 필요가 있다.
FND 의 각 7 세그먼트는 그림과 같이 8개의 LED 요소로 구성되어 있으며 0,1,2,3,4,5,6,7,8,9,A,b,C,d,E 및 점(.) 에 해당하는 문자를 디스플레이 할 수 있다.
그래픽 출력이기 때문에 아두이노 우노에서 처럼 하드웨어 적인 디지털 핀의 할당 및 배선이 전혀 없는 HTML SVG 그래픽 FND (Finite Numeric Display) 4 디지트 (Digit) 7세그먼트를 구성하도록 하자.
하지만 코딩의 가성비 즉 시간 단축을 위해서 아주 컴팩트한 아래의 7 세그먼트 LED 코딩 사례를 참조하여 가급적이면 수정 작업을 최소로 하여 이용하기로 하자.
스마트폰 키보드에 의한 아두이노 NodeMCU 7세그먼트 LED 제어 프로그램 알고리듬 개량 컴팩트화:IV
http://blog.daum.net/ejleep1/358
웹서버 코딩에 의한 그래픽 방식에서는 아두이노에서 처럼 LED 7 세그먼트를 on OFF 하기 위한 8개의 디지털 데이터 핀 할당은 더 이상 필요하지 않다. 하지만 7 세그먼트 디스플레이를 이해할 수 있도록 예전의 설명을 다시 한 번 요약하기로 하자.
“0” 이라는 숫자를 디스플레이하기 위해서 위 그림에서처럼 7 세그먼트 그림에서 ABCDEF 세그먼트들을 on시켜야 함을 쉽게 알 수 있다. 그 다음에 FND_DATA[] 어레이를 설정하고 디스플레이할 문자들 즉 0,1,2,3,4,5,6,7,8,9,A,b,C,d,E 및 점(.)을 대상으로 16진 데이터를 사전에 설정해 두어야 한다.
그 첫 번째 데이터인 0XC0 예를 살펴보자. 0X는 단지 16진법 또는 Hexa를 뜻한다. 중요한 부분은 C0이다. 16진법에서 C는 십진법으로는 12에 해당하는데 12를 2진법의 비트 단위로 풀어서 표현하면 12 = 1X2^3+1X2^2+0X2^1+0X2^0 이 된다. 앞 계수를 따내어 정리하면 1100이 된다. 아울러 16진법의 0은 2진법에서 0000 이 된다. 즉 16진법의 C0는 2진법으로 1100 0000 이 된다. 이 이진 비트 정보를 7 세그먼트의 각 세그먼트와 대응시켜 보자.
1 1 0 0 0 0 0 0
---------------
H G F E D C B A
즉 ABCDEF 세그먼트를 on으로 그래픽 처리하고 G 와 H 세그먼트를 OFF 그래픽 처리하면 결과는 “0”을 보여주게 된다.
두 번째로 0XD8 예를 살펴보자. 16진 D8의 이진 비트 표현은 다음과 같다.
16진 13 = 10진 1X2^3+1X2^2+0X2^1+1X2^0 =2진 1101
16진 8 = 10진 1X2^3+0X2^2+0X2^1+0X2^0 =2진 1000
1 1 0 1 1 0 0 0
---------------
H G F E D C B A
즉 ABCF 세그먼트를 on으로 그래픽 처리하고 DEGH세그먼트를 OFF 그래픽 처리하면 결과는 “7”을 보여주게 된다.
FND_DATA[] 어레이에는 7 세그먼트 디스플레이 용 글자의 16진 정보를 저장해둔다.
웹서버 키보드에서 키를 눌러 입력하면 체크하여 정수형 변수 d에 저장한다.
d1,d2,d3,d4는 디스플레이 출력할 각 자리수별 글자를 정수 형태로 저장하기로 한다.
스마트폰과 연결할 무선 웹서버 와이파이 연결을 위한 코딩 설명은 생략 한다.
글자 하나가 입력이 완료되면 d 에 저장한다.
3번째 글자 d3을 d4로, d2를 d3, d1을 d2, d를 d1으로 옮겨 저장하며, 이 순서가 바뀌지 않도록 유의 한다.
이 부분이 7 세그먼트 방식 출력의 핵심이다. 이 d1,d2 ,d3,d4를 응용 사례에 맞춰 적절하게 입력해 주면 원하는 4 디지트 출력이 이루어질 것이다.
코딩의 핵심인 HTML SVG 태그의 그래픽 화면 설정에 관해 알아보자. VIEWBOX 정의를 도입한다. 웹서버형 아날로그 시계 코딩에서 사용되었던 기법인데 원형 시계를 100X100 박스로 정의하여 그래픽 처리를 한다. 이 그래픽을 기준으로 실제 SVG 화면의 크기를 정의하는 width와 height를 비례적으로 예를 들면 좀 작은 그래픽을 원하면 50 50 좀 큰 그래픽을 원하면 200 200 방식으로 설정한다.
100X100 사이즈로 VIEWBOX를 설정 하면 좌표 숫자 다루기가 대단히 편한 이점이 있으나 7 세그먼트 그래픽의 특성 상 소숫점 이하가 있는 숫자가 나올 우려가 있어 끝자리가 0 또는 5로 끝날 수 있도록 첫 번째 VIEWBOX를 300X300 으로 설정하였다. 따라서 4쪽으로 구성된 FND 그래픽을 위해서 1200X300 VIEWBOX를 설정한다. 폭과 높이는 비례적으로 100X400으로 설정한다. 보다 큰 폰트 사이즈의 출력을 보려면 7 세그먼트 그래픽 세부 좌표를 전혀 변경함이 없이 이 폭과 높이를 비례적으로 키워주면 된다.
키보드 입력을 하면 글자 하나가 디스플레이 되며 계속함에 따라 입력된 글자는 왼쪽으로 움직이고 방금 입력한 글자가 가장 오른쪽에 위치하게 된다. 4자리 수 가 넘어가게 되면 제일 왼쪽의 글자가 밀려서 사라지게 된다.
미세먼지 센서 또는 온습도계 계측 결과의 FND 디스플레이에서처럼 응용 출력하기 위해서는 이 코드를 기본으로 코드를 각자의 필요에 따라 수정해야 할 것이다. 즉 제일 왼쪽 4번째는 측정 사례에 따라서 if 문을 사용하여 P, C, H를 출력하도록 한다. 3번째에서 1번째까지는 정수형 데이터를 표현하기 위해서 데이터를 십진법이므로 100, 10, 1 자리의 계수를 찾아 d3, d3, d1 값을 지정해 주면 된다.
현재의 코드는 HTML 파트에서 버튼 키 입력을 대상으로 작성된 코드이다. 그러므로 아두이노 NodeMCU 보드에 DHT11 센서나 미세먼지 센서 GP2Y1010AU를 사용할 때는 버튼 키들이 필요 없으므로 HTML 코드 파트에서 삭제하면 될 것이다.
Webserver_NodeMCU_IOT_keybd_7segment_05
#include <ESP8266WiFi.h>
const char* ssid = "android1234";
const char* password = "dddddddddd";
byte FND_DATA[] = {0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XD8,0X80,0X90,0X88,0X83,0XC6,0XA1,0X86,0X8E,0XF7,0X7F};
WiFiServer server(80);
// String c;
int d,d1,d2,d3,d4;
void setup() {
Serial.begin(115200);
delay(10);
// Set WiFi to station mode and disconnect from an AP if it was previously connected
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
Serial.println("Setup done");
// Connect to WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
// Start the server
server.begin();
Serial.println("Server started");
// Print the IP address
Serial.print("Use this URL to connect: ");
Serial.print("http://");
Serial.print(WiFi.localIP());
Serial.println("/");
}
void loop() {
// Check if a client has connected
WiFiClient client = server.available();
if (!client) {
return;
}
// Wait until the client sends some data
Serial.println("new client");
while(!client.available()){
delay(1);
}
// Read the first line of the request
String request = client.readStringUntil('\r');
Serial.println(request);
// favicon.ico request는 중복이므로 건너 뛰도록 프로그램 한다.
if(request.substring(5,16) != "favicon.ico") {
client.flush();
// Match the request
// Key board input processing
if (request.indexOf("/KEY=0") != -1) {
d = 0;
}
if (request.indexOf("/KEY=1") != -1) {
d = 1;
}
if (request.indexOf("/KEY=2") != -1) {
d = 2;
}
if (request.indexOf("/KEY=3") != -1) {
d = 3;
}
if (request.indexOf("/KEY=4") != -1) {
d = 4;
}
if (request.indexOf("/KEY=5") != -1) {
d = 5;
}
if (request.indexOf("/KEY=6") != -1) {
d = 6;
}
if (request.indexOf("/KEY=7") != -1) {
d = 7;
}
if (request.indexOf("/KEY=8") != -1) {
d = 8;
}
if (request.indexOf("/KEY=9") != -1) {
d = 9;
}
if (request.indexOf("/KEY=A") != -1) {
d = 10;
}
if (request.indexOf("/KEY=B") != -1) {
d = 11;
}
if (request.indexOf("/KEY=C") != -1) {
d = 12;
}
if (request.indexOf("/KEY=D") != -1) {
d = 13;
}
if (request.indexOf("/KEY=E") != -1) {
d = 14;
}
if (request.indexOf("/KEY=F") != -1) {
d = 15;
}
if (request.indexOf("/KEY=.") != -1) {
d = 17;
}
// 한칸씩 왼쪽으로 이동
d4 = d3;
d3 = d2;
d2 = d1;
d1 = d;
// Return the response
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println(""); // do not forget this one
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("<head>");
//배경 색 문자 색 사이즈 HTML CSS 설정
client.println("<style>");
client.println("body {");
client.println("background-color: lightblue;");
client.println("}");
client.println("p {");
client.println("color:red;");
client.println("font-size:250%;");
client.println("}");
//버튼 HTML CSS 설정
client.println(".button {");
client.println("background-color: white;");
client.println("border: solid;");
client.println("color: black;");
client.println("padding: 15px 32px;");
client.println("text-align: center;");
client.println("text-decoration: none;");
client.println("display: inline-block;");
client.println("font-size: 50px;");
client.println("margin: 2px 2px;");
client.println("cursor: pointer;");
client.println("}");
client.println("</style>");
client.println("<title>Page Title</title>");
client.println("<h1> Arduino 7 Segment </h1>");
client.println("</head>");
client.println("<body>");
client.println("<p>");
// segment display on smartphone webbrowser
client.println("<svg viewbox=' 0 0 1200 300' height='100' width='400'>");
for(int z=0; z<8; z++) {
if( z == 0 && bitRead(FND_DATA[d4],z) == 0) {client.println("<polygon points='50,50 60,40 190,40 200,50 190,60 60,60' style='fill:red;stroke:black;stroke-width:3' />");} //A
if( z == 1 && bitRead(FND_DATA[d4],z) == 0) {client.println("<polygon points='200,55 210,65 210,135 200,145 190,135 190,65' style='fill:red;stroke:black;stroke-width:3' />");} //B
if( z == 2 && bitRead(FND_DATA[d4],z) == 0) {client.println("<polygon points='200,155 210,165 210,235 200,245 190,235 190,165' style='fill:red;stroke:black;stroke-width:3' />");} //C
if( z == 3 && bitRead(FND_DATA[d4],z) == 0) {client.println("<polygon points='50,250 60,240 190,240 200,250 190,260 60,260' style='fill:red;stroke:black;stroke-width:3' />");} //D
if( z == 4 && bitRead(FND_DATA[d4],z) == 0) {client.println("<polygon points='50,155 60,165 60,235 50,245 40,235 40,165' style='fill:red;stroke:black;stroke-width:3' />");} //E
if( z == 5 && bitRead(FND_DATA[d4],z) == 0) {client.println("<polygon points='50,55 60,65 60,135 50,145 40,135 40,65' style='fill:red;stroke:black;stroke-width:3' />");} //F
if( z == 6 && bitRead(FND_DATA[d4],z) == 0) {client.println("<polygon points='50,150 60,140 190,140 200,150 190,160 60,160' style='fill:red;stroke:black;stroke-width:3' />");} //G
if( z == 7 && bitRead(FND_DATA[d4],z) == 0) {client.println("<polygon points='205,250 215,240 225,240 235,250 225,260 215,260' style='fill:red;stroke:black;stroke-width:3' />");} //H
if( z == 0 && bitRead(FND_DATA[d3],z) == 0) {client.println("<polygon points='350,50 360,40 490,40 500,50 490,60 360,60' style='fill:red;stroke:black;stroke-width:3' />");} //A
if( z == 1 && bitRead(FND_DATA[d3],z) == 0) {client.println("<polygon points='500,55 510,65 510,135 500,145 490,135 490,65' style='fill:red;stroke:black;stroke-width:3' />");} //B
if( z == 2 && bitRead(FND_DATA[d3],z) == 0) {client.println("<polygon points='500,155 510,165 510,235 500,245 490,235 490,165' style='fill:red;stroke:black;stroke-width:3' />");} //C
if( z == 3 && bitRead(FND_DATA[d3],z) == 0) {client.println("<polygon points='350,250 360,240 490,240 500,250 490,260 360,260' style='fill:red;stroke:black;stroke-width:3' />");} //D
if( z == 4 && bitRead(FND_DATA[d3],z) == 0) {client.println("<polygon points='350,155 360,165 360,235 350,245 340,235 340,165' style='fill:red;stroke:black;stroke-width:3' />");} //E
if( z == 5 && bitRead(FND_DATA[d3],z) == 0) {client.println("<polygon points='350,55 360,65 360,135 350,145 340,135 340,65' style='fill:red;stroke:black;stroke-width:3' />");} //F
if( z == 6 && bitRead(FND_DATA[d3],z) == 0) {client.println("<polygon points='350,150 360,140 490,140 500,150 490,160 360,160' style='fill:red;stroke:black;stroke-width:3' />");} //G
if( z == 7 && bitRead(FND_DATA[d3],z) == 0) {client.println("<polygon points='505,250 515,240 525,240 535,250 525,260 515,260' style='fill:red;stroke:black;stroke-width:3' />");} //H
if( z == 0 && bitRead(FND_DATA[d2],z) == 0) {client.println("<polygon points='650,50 660,40 790,40 800,50 790,60 660,60' style='fill:red;stroke:black;stroke-width:3' />");} //A
if( z == 1 && bitRead(FND_DATA[d2],z) == 0) {client.println("<polygon points='800,55 810,65 810,135 800,145 790,135 790,65' style='fill:red;stroke:black;stroke-width:3' />");} //B
if( z == 2 && bitRead(FND_DATA[d2],z) == 0) {client.println("<polygon points='800,155 810,165 810,235 800,245 790,235 790,165' style='fill:red;stroke:black;stroke-width:3' />");} //C
if( z == 3 && bitRead(FND_DATA[d2],z) == 0) {client.println("<polygon points='650,250 660,240 790,240 800,250 790,260 660,260' style='fill:red;stroke:black;stroke-width:3' />");} //D
if( z == 4 && bitRead(FND_DATA[d2],z) == 0) {client.println("<polygon points='650,155 660,165 660,235 650,245 640,235 640,165' style='fill:red;stroke:black;stroke-width:3' />");} //E
if( z == 5 && bitRead(FND_DATA[d2],z) == 0) {client.println("<polygon points='650,55 660,65 660,135 650,145 640,135 640,65' style='fill:red;stroke:black;stroke-width:3' />");} //F
if( z == 6 && bitRead(FND_DATA[d2],z) == 0) {client.println("<polygon points='650,150 660,140 790,140 800,150 790,160 660,160' style='fill:red;stroke:black;stroke-width:3' />");} //G
if( z == 7 && bitRead(FND_DATA[d2],z) == 0) {client.println("<polygon points='805,250 815,240 825,240 835,250 825,260 815,260' style='fill:red;stroke:black;stroke-width:3' />");} //H
if( z == 0 && bitRead(FND_DATA[d1],z) == 0) {client.println("<polygon points='950,50 960,40 1090,40 1100,50 1090,60 960,60' style='fill:red;stroke:black;stroke-width:3' />");} //A
if( z == 1 && bitRead(FND_DATA[d1],z) == 0) {client.println("<polygon points='1100,55 1110,65 1110,135 1100,145 1090,135 1090,65' style='fill:red;stroke:black;stroke-width:3' />");} //B
if( z == 2 && bitRead(FND_DATA[d1],z) == 0) {client.println("<polygon points='1100,155 1110,165 1110,235 1100,245 1090,235 1090,165' style='fill:red;stroke:black;stroke-width:3' />");} //C
if( z == 3 && bitRead(FND_DATA[d1],z) == 0) {client.println("<polygon points='950,250 960,240 1090,240 1100,250 1090,260 960,260' style='fill:red;stroke:black;stroke-width:3' />");} //D
if( z == 4 && bitRead(FND_DATA[d1],z) == 0) {client.println("<polygon points='950,155 960,165 960,235 950,245 940,235 940,165' style='fill:red;stroke:black;stroke-width:3' />");} //E
if( z == 5 && bitRead(FND_DATA[d1],z) == 0) {client.println("<polygon points='950,55 960,65 960,135 950,145 940,135 940,65' style='fill:red;stroke:black;stroke-width:3' />");} //F
if( z == 6 && bitRead(FND_DATA[d1],z) == 0) {client.println("<polygon points='950,150 960,140 1090,140 1100,150 1090,160 960,160' style='fill:red;stroke:black;stroke-width:3' />");} //G
if( z == 7 && bitRead(FND_DATA[d1],z) == 0) {client.println("<polygon points='1105,250 1115,240 1125,240 1135,250 1125,260 1115,260' style='fill:red;stroke:black;stroke-width:3' />");} //H
}//for loop 끝
client.println("</svg>");
// Key board input
client.println("<br><br>");
client.println("<a href=\"/KEY=1\"\" class='button'> 1 </button></a>");
client.println("<a href=\"/KEY=2\"\" class='button'> 2 </button></a>");
client.println("<a href=\"/KEY=3\"\" class='button'> 3 </button></a>");
client.println("<a href=\"/KEY=A\"\" class='button'> A </button></a>");
client.println("<br>");
client.println("<a href=\"/KEY=4\"\" class='button'> 4 </button></a>");
client.println("<a href=\"/KEY=5\"\" class='button'> 5 </button></a>");
client.println("<a href=\"/KEY=6\"\" class='button'> 6 </button></a>");
client.println("<a href=\"/KEY=B\"\" class='button'> B </button></a>");
client.println("<br>");
client.println("<a href=\"/KEY=7\"\" class='button'> 7 </button></a>");
client.println("<a href=\"/KEY=8\"\" class='button'> 8 </button></a>");
client.println("<a href=\"/KEY=9\"\" class='button'> 9 </button></a>");
client.println("<a href=\"/KEY=C\"\" class='button'> C </button></a>");
client.println("<br>");
client.println("<a href=\"/KEY=F\"\" class='button'> F </button></a>");
client.println("<a href=\"/KEY=0\"\" class='button'> 0 </button></a>");
client.println("<a href=\"/KEY=D\"\" class='button'> D </button></a>");
client.println("<a href=\"/KEY=E\"\" class='button'> E </button></a>");
client.println("<br>");
client.println("<a href=\"/KEY=.\"\" class='button'> . </button></a>");
//
client.println("</p>");
client.println("</body>");
client.println("</html>");
delay(1);
Serial.println("Client disonnected");
Serial.println("");
}// if(request.substring(5,16) 문 괄호 닫기
}//프로그램 끝
'아두이노프로세싱 프로그래밍' 카테고리의 다른 글
아두이노 ESP8266 NodeMCU IOT(사물인터넷) Java Script 그래픽 와이파이 코딩 (0) | 2017.05.21 |
---|---|
아두이노 NodeMCU 의 그래픽 7 세그먼트에 의한 DHT11 온습도 디스플레이 (0) | 2017.05.20 |
아두이노 온습도, 미세먼지 측정 및 ESP8266 NodeMCU WiFi 코딩 요약 (0) | 2017.05.16 |
초보자를 위한 라즈베리 파이3 파이선 LED ON OFF 코딩 (0) | 2017.05.13 |
초보자를 위한 “아두이노 NodeMCU ESP8266WiFi 라이브러리 사용법 요약” (0) | 2017.05.09 |