본문 바로가기

토이 프로젝트

Arduino 보드와 PC(C# 사용)간에 UDP 통신을 사용하여 LED 제어하기

1. 개념

https://powerdeng.tistory.com/227

 

TCP와 UDP

TCP와 UDP의 차이 TCP는 접속을 하고 서로 통신하지만 UDP는 접속하지 않고 통신한다. 사물 인터넷(IoT)에서 TCP와 UDP의 차이 1. TCP 사물 인터넷(IoT)에서는 기본적으로 사물(보드)이 많다는 가정이 있다

powerdeng.tistory.com

 

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

 

아두이노 우노 IoT 보드 WeMos D1 R1 [SZH-EK080]

WeMos D1 R1 보드는 와이파이(ESP-8266EX)가 내장된 Arduino Uno 호환 보드입니다.

www.devicemart.co.kr

 

3. 진행 과정

1번. IoT보드가 UDP 통신이 가능한 클라이언트로 만든다.

2번. C#으로 서버 역할을 할 UDP 클라이언트를 만든다.

3번. 1번과 2번이 서로 연결되는지 확인한다.

 

4. IoT보드가 UDP 통신이 가능한 클라이언트 만들기

1) 개발 환경 설정

아래 링크의 개발 환경 설정과 동일하다.

https://powerdeng.tistory.com/231

 

Arduino 보드와 PC(C# 사용)간에 UDP 통신을 사용하여 메시지 주고 받기

1. 개념 https://powerdeng.tistory.com/227 TCP와 UDP TCP와 UDP의 차이 TCP는 접속을 하고 서로 통신하지만 UDP는 접속하지 않고 통신한다. 사물 인터넷(IoT)에서 TCP와 UDP의 차이 1. TCP 사물 인터넷(IoT)에서는 기

powerdeng.tistory.com

 

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

 

Arduino 보드와 PC(C# 사용)간에 UDP 통신을 사용하여 메시지 주고 받기

1. 개념 https://powerdeng.tistory.com/227 TCP와 UDP TCP와 UDP의 차이 TCP는 접속을 하고 서로 통신하지만 UDP는 접속하지 않고 통신한다. 사물 인터넷(IoT)에서 TCP와 UDP의 차이 1. TCP 사물 인터넷(IoT)에서는 기

powerdeng.tistory.com

 

2) 코드 작성

여기서 작성한 코드는 아래 경로의 예시를 기본으로 작성했다.

https://learn.microsoft.com/ko-kr/dotnet/api/system.net.sockets.udpclient?view=net-5.0

 

UdpClient 클래스 (System.Net.Sockets)

UDP(User Datagram Protocol) 네트워크 서비스를 제공합니다.

learn.microsoft.com

 

<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