스마트 폰에서 키보드를 작성하고 키보드입력을 와이파이로 아두이노 NodeMCu에 전송하여 7 segment LED를 직접 구동함과 동시에 스마트폰에서도 그래픽 기능을 사용하여 7세그먼트 를 출력하는 프로그램이 이미 제시되었다.
블로그 참조: 스마트폰 키보드에 의한 아두이노 NodeMCU 7세그먼트 LED 제어:III
키보드에서 4 또는 6 또는 8을 누르면 스마트폰 화면에 해당하는 7세그먼트 LED가 그래픽 출력이 되고 아울러 NodeMCU 보드에서 LED가 켜지는 것을 볼 수 있다.
단지 4,6,8만 되는 점은 앞에서 얘기 했듯이 나머지 각 글자별로 HTML SVG 프로그램을 보충해야 한다는 점을 지적하였다.
이런 방식으로 0,1,2,⚫⚫⚫,9,A,B,C,D,E,F,_ 및 “⚫“을 출력하기 위해서는 총 15개의 글자별 프로그램 블록이 추가되어야 하는데 프로그램 기법 상 대단히 낙후된 방법으로 보인다.
결국 7 세그먼트는 8개의 정보로 구성되며 각 세그먼트가 on 또는 OFF 상태인지를 지정해 주어야 글자가 출력 될 수 있다.
따라서 직접 7 세그먼트를 구동하는 프로그램 알고리듬을 검토하여 HTML SVG 그래픽 파트에서도 유사하게 컴팩트한 형태의 프로그램이 가능한지 살펴보기로 하자.
우선 7세그먼트 직접 구동을 위한 프로그램 구조에서 아두이노 NodeMCU에서 사용되었던 디지털 출력 핀 설정과 7세그먼트 문자별 16진법 정의는 아래와 같다.
byte FND[8] = {2,3,4,5,0,12,14,15};
byte FND_DATA[] = {0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XD8,0X80,0X90,0X88,0X83,0XC6,0XA1,0X86,0X8E,0XF7,0X7F};
예를 들어 “4”를 스마트폰 키보드에서 키로 입력했다고 하자. 그러면 FND_DATA[4]에 해당하는 즉 0X99를 FND_display 루틴에 1 바이트 데이터 즉 2진법 표현으로 1001 1001을 넘겨주게 된다.
// FND Display Routine
void FND_display(byte data) {
byte z;
for(z=0; z<8; z++) {
digitalWrite(FND[z],bitRead(data,z));
}
}
다시 말하자면 위 루틴이 다음과 같이 실행됨을 의미하는데
void FND_display(byte FND_DATA[4] ) {⚫⚫⚫
이는 더 구체적으로 표현해, 다음과 같이 이해하면 될 것이다.
void FND_display(byte 1001 1001) {⚫⚫⚫
FND_display 루틴 내부에서 그 다음과정은 z=0에서 7까지 도합 8번에 걸쳐 for 루프문이 실행된다. 여기에서 digital.Write() 명령 실행에 대해서 알아보자. FND_display 호출에 따라 1 바이트 2진법 데이터는 bitRead(bitdata,z) 명령 실행에 사용된다.
digitalWrite(FND[z],bitRead(1001 1001,z));
for 루프 인덱스 z가 0에서 7까지 변하면서 몇 번째 비트 데이터가 1인지 시험 후 해당 비트 데이터가 1인 경우에는 디지털 데이터 핀 번호 FND(z) 에 “1” 또는 HIGH를 출력한다. 이로서 하드웨어 적으로 해당 핀이 HIGH 또는 LOW 상태가 된다.
이 알고리듬은 거의 유사하게 스마트폰 웹 브라우저에서 HTML SVG 그래픽 세그먼트를 출력 시키는데 사용할 수 있다.
7세그먼트 하드웨어 직접 구동 프로그램과의 차이는 결국 digital.Write() 명령이 없음으로 인해 이를 대신하기 위해서 if문을 사용하는 것이다. for 루프 변수 z가 0에서 7까지 변함에 따라 bitRead(FND_DATA[d],z)가 “0” 인 것이 사실이면 동시에 해당하는 z 값이 일치한다면 해당 세그먼트를 출력하는 것이다.
아울러 지난번에 올렸던 프로그램에서는 키보드에서 입력된 데이터를 문자 정보 c에 저장하여 HTML SVG 그래픽 파트에서 if문을 사용하여 해당 문자를 확인하고 필요한 세그먼트들을 취하는 방법으로 프로그램 하였다.
하지만 이번 프로그램에서는 7세그먼트 직접 구동에서처럼 키보드 입력 정보를 문자가 아닌 정수데이터로 처리한다. 단 이 정수 데이터는 프로그램 내부에서 특히 if 문 배부에서 사용됨으로 인해 반드시 전역 변수로 프로그램 서두에 정의 되어야 한다.
아래에 첨부된 프로그램이 이상 없이 작동하므로 구태여 시리얼 모니터에서 문자 c의 값을 출력할 필요가 없어 삭제하였음에 유의하자.
결국 이 7세그먼트 프로그램의 알고리듬 개선을 통해 프로그램을 컴팩트하게 줄일 수 있었으며 이는 곧 4쪽짜리 FND 4 디지트 7 세그먼트 구동 프로그램 작성의 출발점이 될 수 있을 것으로 보인다.
Webserver_NodeMCU_IOT_keybd_7segment_02
#include <ESP8266WiFi.h>
const char* ssid = "AndroidHotspot1234";// 자신 스마트폰 핫스팟 ID 입력
const char* password = "00000000";// 자신 스마트폰 핫스팟 비밀번호 입력
byte FND[8] = {2,3,4,5,0,12,14,15};
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;
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("/");
// 7semnent OUTPUT mode
byte z;
for(z=0; z<8; z++) {
pinMode(FND[z],OUTPUT);
}//7 segment setting
}
// FND Display Routine
void FND_display( byte data) {
byte z;
for(z=0; z<8; z++) {
digitalWrite(FND[z],bitRead(data,z));
}
}
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;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=1") != -1) {
d = 1;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=2") != -1) {
d = 2;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=3") != -1) {
d = 3;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=4") != -1) {
d = 4;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=5") != -1) {
d = 5;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=6") != -1) {
d = 6;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=7") != -1) {
d = 7;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=8") != -1) {
d = 8;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=9") != -1) {
d = 9;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=A") != -1) {
d = 10;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=B") != -1) {
d = 11;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=C") != -1) {
d = 12;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=D") != -1) {
d = 13;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=E") != -1) {
d = 14;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=F") != -1) {
d = 15;
FND_display(FND_DATA[d]);}
if (request.indexOf("/KEY=.") != -1) {
d = 17;
FND_display(FND_DATA[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 height='300' width='300'>");
for(int z=0; z<8; z++) {
if( z == 0 && bitRead(FND_DATA[d],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[d],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[d],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[d],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[d],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[d],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[d],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[d],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
}//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) 문 괄호 닫기
}//프로그램 끝
'아두이노프로세싱 프로그래밍' 카테고리의 다른 글
아두이노 초보자를 위한 “아두이노 코딩에 의한 LED ON OFF” (0) | 2017.03.13 |
---|---|
본 블로그에 게재된 아두이노 및 아두이노 NodeMCU 응용 프로그램 전체의 오픈소스화 방침을 밝힙니다. (0) | 2017.03.12 |
아두이노 NodeMCU HTML+Javascript AI(인공지능) 계산기 프로그램 공학계신 기능 추가 (0) | 2017.03.10 |
아두이노 NodeMCU HTML+Javascript 계산기 프로그램 (0) | 2017.03.08 |
아두이노 NodeMCU와 GPS센서 VK16E로 만들어 보는 TinyGPS 네비게이션 시스템 (0) | 2017.03.05 |