라즈베리파이에서 보낸 문자열을 아두이노 우노에 연결된 캐릭터 LCD에 보여주는 예제입니다.
아두이노 우노에 연결된 ESP8266을 사용하여 TCP 소켓 통신을 합니다.
진행하기 전에 다음 포스팅을 참고하여 아두이노 우노에 ESP8266 WiFi 모듈을 연결하고 필요한 WeeESP8266 라이브러리를 설치해야 합니다.
1. 아두이노 IDE에 다음 코드를 복사합니다.
다음 포스팅에서 사용한 코드에 LCD에 수신한 문자열을 보여주는 코드를 추가했습니다.
#include "ESP8266.h" #include <SoftwareSerial.h> #include <LiquidCrystal.h>
#define SSID "공유기의 SSID" #define PASSWORD "공유기의 비밀번호" #define HOST_PORT (TCP서버_포트번호) SoftwareSerial mySerial(10, 9); /* RX:D10, TX:D9 */ ESP8266 wifi(mySerial);
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2; LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup(void) { Serial.begin(9600); Serial.print("setup begin\r\n"); Serial.print("FW Version:"); Serial.println(wifi.getVersion().c_str()); if (wifi.setOprToStationSoftAP()) { Serial.print("to station + softap ok\r\n"); } else { Serial.print("to station + softap err\r\n"); } if (wifi.joinAP(SSID, PASSWORD)) { Serial.print("Join AP success\r\n"); Serial.print("IP: "); Serial.println(wifi.getLocalIP().c_str()); } else { Serial.print("Join AP failure\r\n"); } if (wifi.enableMUX()) { Serial.print("multiple ok\r\n"); } else { Serial.print("multiple err\r\n"); } if (wifi.startTCPServer(HOST_PORT)) { Serial.print("start tcp server ok\r\n"); } else { Serial.print("start tcp server err\r\n"); } if (wifi.setTCPServerTimeout(10)) { Serial.print("set tcp server timout 10 seconds\r\n"); } else { Serial.print("set tcp server timout err\r\n"); } Serial.print("setup end\r\n"); pinMode( 13, OUTPUT ); lcd.begin(16, 2); } void loop(void) { uint8_t send_buffer[128] = {0}; uint8_t recv_buffer[128] = {0}; uint8_t mux_id; uint32_t len = wifi.recv(&mux_id, recv_buffer, sizeof(recv_buffer), 100); if (len > 0) { Serial.print("Received:["); lcd.setCursor(0, 0);lcd.clear(); for(uint32_t i = 0; i < len; i++) { Serial.print((char)recv_buffer[i]);
if ( i < len-1 ) lcd.print((char)recv_buffer[i]); } Serial.print("]\r\n");
char command = recv_buffer[0]; int ledStatus = digitalRead(LED_BUILTIN);
switch (command){ case '1': if (ledStatus == LOW){ digitalWrite(LED_BUILTIN, HIGH); sprintf(send_buffer, "LED is on\n"); wifi.send(mux_id,send_buffer, strlen(send_buffer)); } else{ sprintf(send_buffer, "LED is already on\n"); wifi.send(mux_id,send_buffer, strlen(send_buffer)); } break; case '2': if (ledStatus == HIGH){ digitalWrite(LED_BUILTIN, LOW); sprintf(send_buffer, "LED is off.\n"); wifi.send(mux_id,send_buffer, strlen(send_buffer)); } else{ sprintf(send_buffer, "LED is already off.\n"); wifi.send(mux_id,send_buffer, strlen(send_buffer)); } break; case 'S': case 's': if (ledStatus == LOW){ sprintf(send_buffer, "LED status: off\n"); wifi.send(mux_id,send_buffer, strlen(send_buffer)); } else { sprintf(send_buffer, "LED status: on\n"); wifi.send(mux_id,send_buffer, strlen(send_buffer)); } break; default: uint8_t buf[]="Usage\n1 : Turn On LED\n2 : Turn Off LED\nS : LED status\n\n"; wifi.send(mux_id, buf, strlen(buf)); break; } } }
|
상단에 있는 다음 3줄을 환경에 맞게 수정한 후, Arduino Uno에 업로드시켜줍니다.
포스팅에서는 TCP 서버 포트번호로 23번을 사용하여 진행합니다.
#define SSID "공유기의 SSID" #define PASSWORD "공유기의 비밀번호" #define HOST_PORT (23)
|
2. Arduino IDE의 메뉴에서 툴 > 시리얼 모니터를 실행합니다. 서버역활을 하게될 아두이노의 IP를 확인해둡니다.
IP 항목에서 두번째 아이피(붉은색 글씨)를 사용하면 됩니다.
setup begin FW Version:0018000902 to station + softap ok Join AP success IP: 192.168.4.1 192.168.43.239 multiple ok start tcp server ok set tcp server timout 10 seconds setup end
|
3. 라즈베리파이에서 TCP 클라이언트 코드를 컴파일 후, 아두이노의 IP와 포트번호를 사용하여 실행합니다.
$ gcc -o tcpclient tcpclient.c $ ./tcpclient 192.168.43.239 23
|
/* * tcpclient.c - A simple TCP client * usage: tcpclient <host> <port> */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h>
#define BUFSIZE 1024
/* * error - wrapper for perror */ void error(char *msg) { perror(msg); exit(0); }
int main(int argc, char **argv) { int sockfd, portno, n; struct sockaddr_in serveraddr; struct hostent *server; char *hostname; char buf[BUFSIZE];
/* check command line arguments */ if (argc != 3) { fprintf(stderr,"usage: %s <hostname> <port>\n", argv[0]); exit(0); } hostname = argv[1]; portno = atoi(argv[2]);
/* socket: create the socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket");
/* gethostbyname: get the server's DNS entry */ server = gethostbyname(hostname); if (server == NULL) { fprintf(stderr,"ERROR, no such host as %s\n", hostname); exit(0); }
/* build the server's Internet address */ bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; bcopy((char *)server->h_addr, (char *)&serveraddr.sin_addr.s_addr, server->h_length); serveraddr.sin_port = htons(portno);
/* connect: create a connection with the server */ if (connect(sockfd, &serveraddr, sizeof(serveraddr)) < 0) error("ERROR connecting");
while(1){
/* get message line from the user */ printf("Please enter msg: "); bzero(buf, BUFSIZE); fgets(buf, BUFSIZE, stdin);
if ( buf[0] == 'q' ) break;
/* send the message line to the server */ n = write(sockfd, buf, strlen(buf)); if (n < 0) error("ERROR writing to socket");
/* print the server's reply */ bzero(buf, BUFSIZE); n = read(sockfd, buf, BUFSIZE); if (n < 0) error("ERROR reading from socket");
printf("Echo from server: %s", buf);
if (n == 0){ printf("Disconnected\n"); break; } }
close(sockfd);
return 0; } |
4. 기존에 LED 제어하는 명령에 기능이 추가되었습니다. 입력한 문자열을 LCD에 보여줍니다.
라즈베리파이에서 문자열 송신시 약간의 딜레이가 생기면서 오동작하는 현상이 있습니다.
원인을 찾아보니 read 함수에서 0바이트를 수신할때가 문제입니다.
현재는 TCP 클라이언트 프로그램을 종료하도록 하고 있습니다. 기존의 접속을 끊고 서버에 재접속하도록 수정하면 해결될듯합니다.
if (n == 0){ printf("Disconnected\n"); break; } |
시리얼 버퍼의 크기를 늘려주고 해결된 듯합니다. 변경 방법은 다음 포스팅에 포함되어 있습니다.
Arduino UNO에서 ESP8266 WiFi 모듈을 사용하는 방법
http://webnautes.tistory.com/755
마지막 업데이트 2019. 1. 17