1. 개념
https://powerdeng.tistory.com/227
2. 개요
Wi-Fi 공유기에 IoT 보드와 PC( C#으로 UDP 서버 역할)가 연결되면 같은 공유기에 연결된 것들끼리는 UDP 통신이 가능하다. 따라서 이를 이용하여 보드에서 PC로 LED 상태 정보를 보내고, PC에서 보드로는 LED 제어 정보를 보내어 LED를 제어 및 상태를 파악하는 프로젝트를 진행하려고 한다.
<참고 자료>
보드 정보: WeMos D1 R1
https://www.devicemart.co.kr/goods/view?no=1312096
3. 진행 과정
1번. IoT보드가 UDP 통신이 가능한 클라이언트로 만든다.
2번. C#으로 서버 역할을 할 UDP 클라이언트를 만든다.
3번. 1번과 2번이 서로 연결되는지 확인한다.
4. IoT보드가 UDP 통신이 가능한 클라이언트 만들기
1) 개발 환경 설정
아래 링크의 개발 환경 설정과 동일하다.
https://powerdeng.tistory.com/231
2) 코드 작성
여기서 작성한 코드는 아래 경로의 UDP 코드를 기본으로 작성했다.
File -> Examples -> ESP8266WiFi -> Udp
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
// 사물인터넷보드가 와이파이 공유기와 연결하기 위한 ID, PW를 입력해야 한다.
#ifndef STASSID
#define STASSID "미래기술"
#define STAPSK "hynux17830"
#endif
// LED 정의
#define LED1 D8
#define LED2 D7
#define LED3 D6
#define LED4 D5
// IoT보드에서 사용할 포트번호
unsigned int localPort = 60000; // local port to listen on
// 송수신 데이터의 버퍼를 생성한다.
char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1]; // buffer to hold incoming packet,
// UDP 통신을 위한 클래스
WiFiUDP Udp;
unsigned long t = 0;
void setup() {
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
pinMode(LED4, OUTPUT);
// 와이파이 공유기와 접속하기 위한 절차가 진행된다.
Serial.begin(9600);
Serial.print("TEST ");
WiFi.mode(WIFI_STA);
WiFi.begin(STASSID, STAPSK);
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(500);
}
Serial.print("Connected! IP address: ");
Serial.println(WiFi.localIP());
Serial.printf("UDP server on port %d\n", localPort);
// 상단에 지정된 포트를 UDP 통신에 개구멍으로 쓴다.
Udp.begin(localPort);
}
void loop() {
// 수신된 데이터의 길이를 받는다.
int packetSize = Udp.parsePacket();
if (packetSize) {
// UDP 통신으로 데이터를 수신한다.
int n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
packetBuffer[n] = 0;
// 받아온 데이터를 출력한다.
Serial.println(packetBuffer);
// LED 제어 예시
// 10(LED1 OFF), 11(LED1 ON)
// 30(LED3 OFF), 31(LED3 ON)
char led_num = packetBuffer[0];
char led_state = packetBuffer[1];
if(led_num == '1') {
if(led_state == '0') digitalWrite(LED1, LOW);
else if(led_state == '1') digitalWrite(LED1, HIGH);
}else if(led_num == '2') {
if(led_state == '0') digitalWrite(LED2, LOW);
else if(led_state == '1') digitalWrite(LED2, HIGH);
}else if(led_num == '3') {
if(led_state == '0') digitalWrite(LED3, LOW);
else if(led_state == '1') digitalWrite(LED3, HIGH);
}else if(led_num == '4') {
if(led_state == '0') digitalWrite(LED4, LOW);
else if(led_state == '1') digitalWrite(LED4, HIGH);
}
}
// 1초에 한 번마다 UDP 통신으로 C# UDP 클라이언트에 메시지를 전송한다.
if (millis() - t > 1000) {
t = millis();
// UDP 전송데이터의 시작(목적지의 주소가 필요하다)
Udp.beginPacket("192.168.2.197", 60001);
// 반환데이터 규칙
//0000 = >모든 LED가 꺼져있다
//1111 => 모든 LED가 켜져있다!
//1100 => 1,2번 LED는 켜져있고 3,4번 LED는 꺼져있다!
//0011 => 1,2번 LED는 꺼져있고 3,4번 LED는 켜져있다!
bool led1_state = digitalRead(LED1);
bool led2_state = digitalRead(LED2);
bool led3_state = digitalRead(LED3);
bool led4_state = digitalRead(LED4);
if(led1_state == true) Udp.write('1');
else Udp.write('0');
if(led2_state == true) Udp.write('1');
else Udp.write('0');
if(led3_state == true) Udp.write('1');
else Udp.write('0');
if(led4_state == true) Udp.write('1');
else Udp.write('0');
// UDP 전송데이터의 끝
Udp.endPacket();
}
}
/*
test (shell/netcat):
--------------------
nc -u 192.168.esp.address 8888
*/
5. C#으로 서버 역할을 할 UDP 클라이언트 만들기
1) 개발 환경 설정
아래 링크의 개발 환경 설정과 동일하다.
https://powerdeng.tistory.com/231
2) 코드 작성
여기서 작성한 코드는 아래 경로의 예시를 기본으로 작성했다.
https://learn.microsoft.com/ko-kr/dotnet/api/system.net.sockets.udpclient?view=net-5.0
<UI>
<코드>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace UDP_IoT_WinForm
{
public partial class Form1 : Form
{
UdpClient udpClient = new UdpClient(60001);
Thread t;
bool is_udp_run = false;
public Form1()
{
InitializeComponent();
}
void powerdeng_udp()
{
try
{
//udp로 연결될 대상이 있는데 그 대상이 누구든지 그냥 받아 들이겠다.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
while (is_udp_run)
{
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.UTF8.GetString(receiveBytes);
richTextBox1.Text += returnData + "@" + RemoteIpEndPoint.Address.ToString() + ":" + RemoteIpEndPoint.Port.ToString() +"\n";
// 1번 LED 상태
if (returnData[0] == '0')
{
button3.BackColor = Color.White;
button4.BackColor = Color.Red;
}
else if(returnData[0] == '1')
{
button3.BackColor = Color.Green;
button4.BackColor = Color.White;
}
// 2번 LED 상태
if (returnData[1] == '0')
{
button5.BackColor = Color.White;
button6.BackColor = Color.Red;
}
else if (returnData[1] == '1')
{
button5.BackColor = Color.Green;
button6.BackColor = Color.White;
}
// 3번 LED 상태
if (returnData[2] == '0')
{
button7.BackColor = Color.White;
button8.BackColor = Color.Red;
}
else if (returnData[2] == '1')
{
button7.BackColor = Color.Green;
button8.BackColor = Color.White;
}
// 4번 LED 상태
if (returnData[3] == '0')
{
button9.BackColor = Color.White;
button10.BackColor = Color.Red;
}
else if (returnData[3] == '1')
{
button9.BackColor = Color.Green;
button10.BackColor = Color.White;
}
}
//udpClient.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
is_udp_run = true;
t = new Thread(new ThreadStart(powerdeng_udp));
t.Start();
}
private void button2_Click(object sender, EventArgs e)
{
is_udp_run = false;
if(t != null && t.IsAlive) t.Abort();
}
private void button3_Click(object sender, EventArgs e)
{
Byte[] sendBytes = Encoding.UTF8.GetBytes("11");
udpClient.Connect("192.168.2.195", 60000);
udpClient.Send(sendBytes, sendBytes.Length);
}
private void button4_Click(object sender, EventArgs e)
{
Byte[] sendBytes = Encoding.UTF8.GetBytes("10");
udpClient.Connect("192.168.2.195", 60000);
udpClient.Send(sendBytes, sendBytes.Length);
}
private void button5_Click(object sender, EventArgs e)
{
Byte[] sendBytes = Encoding.UTF8.GetBytes("21");
udpClient.Connect("192.168.2.195", 60000);
udpClient.Send(sendBytes, sendBytes.Length);
}
private void button6_Click(object sender, EventArgs e)
{
Byte[] sendBytes = Encoding.UTF8.GetBytes("20");
udpClient.Connect("192.168.2.195", 60000);
udpClient.Send(sendBytes, sendBytes.Length);
}
private void button7_Click(object sender, EventArgs e)
{
Byte[] sendBytes = Encoding.UTF8.GetBytes("31");
udpClient.Connect("192.168.2.195", 60000);
udpClient.Send(sendBytes, sendBytes.Length);
}
private void button8_Click(object sender, EventArgs e)
{
Byte[] sendBytes = Encoding.UTF8.GetBytes("30");
udpClient.Connect("192.168.2.195", 60000);
udpClient.Send(sendBytes, sendBytes.Length);
}
private void button9_Click(object sender, EventArgs e)
{
Byte[] sendBytes = Encoding.UTF8.GetBytes("41");
udpClient.Connect("192.168.2.195", 60000);
udpClient.Send(sendBytes, sendBytes.Length);
}
private void button10_Click(object sender, EventArgs e)
{
Byte[] sendBytes = Encoding.UTF8.GetBytes("40");
udpClient.Connect("192.168.2.195", 60000);
udpClient.Send(sendBytes, sendBytes.Length);
}
}
}
6. IoT 보드와 PC연결 확인 및 최종 테스트
PC에서 버튼을 누르면 IoT보드에 연결된 LED가 제어되며, IoT보드에서는 LED 상태정보를 PC로 보내 버튼의 색깔이 잘 변경되는 것을 확인할 수 있다.
<참고 자료>
https://www.youtube.com/watch?v=mHTFR4CnHxA
'토이 프로젝트' 카테고리의 다른 글
Arduino 보드에서 생성된 값을 Serial 통신을 사용하여 서버로 보내기 (0) | 2024.03.19 |
---|---|
Arduino 보드와 PC(C# 사용)간에 UDP 통신을 사용하여 메시지 주고 받기 (0) | 2024.03.14 |