이글의 전부 또는 일부, 사진, 소스프로그램 등은 저작자의 동의 없이는 상업적인 사용을 금지합니다. 또한, 비상업적인 목적이라하더라도 출처를 밝히지 않고 게시하는 것은 금지합니다.

이번 글에서는 지난 글 STM32F103으로 ESP8266을 이용한 소켓 통신하기 -제1편

에서 만든 프로젝트에 코드를 입력하겠습니다.

 

먼저 ESP8266.h에 다음과 같은 내용을 입력합니다.

#ifndef INC_ESP8266_H_
#define INC_ESP8266_H_

#define QUEUE_SIZE		1024
#define SSID_PW_LENGTH	16

#define NO_ERROR		0
#define NOT_FOUND		0xFF
#define HANDLE_NOTSET		1
#define QUEUE_EMPTY		10
#define QUEUE_FULL		11
#define DATA_NOTENOUGH	12

typedef union {
	uint8_t val[4];
	uint32_t longvalue;
} IPUNION, *PIPUNION;

typedef struct {
	IPUNION ip;
	IPUNION subnet;
	IPUNION gateway;
} IPSTRUCT, *PIPSTRUCT;

typedef struct {
	uint16_t Head, Tail, Data;
	uint8_t Queue[QUEUE_SIZE];
} QUEUE, *PQUEUE;

typedef class esp8266 {
protected:
	QUEUE Queue;
	uint8_t LastError;
	UART_HandleTypeDef *pHandle;
	uint8_t SSID[SSID_PW_LENGTH];
	uint8_t Password[SSID_PW_LENGTH];
	IPSTRUCT Ip;
public:
	esp8266();
	~esp8266();
	void SetHandle(UART_HandleTypeDef *pUart);
	void SetSSID(uint8_t *pSSID);
	void SetPassword(uint8_t *pPassword);
	bool SetIp(PIPSTRUCT pIp);
	UART_HandleTypeDef *GetHandle(void);
	uint8_t *GetSSID(void);
	uint8_t *GetPassword(void);
	PIPSTRUCT GetIp(void);
	uint8_t GetLastError(void);
	uint8_t GetData(void);
	bool PutData(uint8_t data);
	uint16_t GetDataSoo(void);
	bool CopyQueue(uint8_t *pDest);
	bool FindStringInqueue(uint8_t *pStr);
	bool FindSkipStringInqueue(uint8_t *pConn, uint8_t *pStr);
	void SendString(uint8_t *pStr);
	bool WaitForOK(void);
	bool SetModeStation(void);
	bool Connect(uint8_t *ssid, uint8_t *passwd);
	bool Connect(void);
	bool SetMUX(uint8_t value);
	bool SetServer(uint8_t set, uint16_t port);
	bool CheckConnect(uint8_t *pConn);
	bool CheckClosed(uint8_t *pConn);
	bool Send(uint8_t Conn, uint16_t Length, uint8_t *pSend);
	bool Receive(uint8_t *pConn, uint16_t *pLength, uint8_t *pReceive);
	bool Close(uint8_t Conn);
} ESP8266, *PESP8266;


#endif /* INC_ESP8266_H_ */

 

위의 소스프로그그램에서 선언한 매크로에 관하여 간단히 설명합니다.

 

① QUEUE_SIZE :  QUEUE의 크기 지정. ESP8266 모듈과 STM32F103은 시리얼 통신을 합니다. 이중 STM32F103이 ESP8266으로부터 데이터를 수신할 때에는 인터럽트를 사용할 것입니다. 인터럽트로 받은 데이터는 일단 QUEUE에 넣을 예정입니다. QUEUE의 크기를 지정하는 매크로입니다. 위 프로그램에서는 1024 바이트로 정했습니다. 

 

② SSID_PW_LENGTH : 공유기의 SSID명과 PASSWORD 최대 길이. 위 프로그램에서는 16 바이트로 정했습니다.

 

③ NO_ERROR, NOT_FOUND, HANDLE_NOTSET, QUEUE_EMPTY, QUEUE_FULL, DATA_NOTENUOGH : 에러 코드. 위 헤더 파일에서 ESP8266을 위한 class ESP8266는 24개의 멤버 함수를 갖습니다. 이이 멤버 함수들이 실행되는 동안 에러 상황을 만나면 멤버 변수 LastError에 넣을 코드들입니다. 의미는 매크로의 이름으로부터 알 수 있습니다.

 

class ESP8266에서 사용하기 위해서 세 개의 데이터 타입을 정의했습니다.

 

① IPUNION : ip, subnetmask, gateway 등은 문자열로 저장하는 것이 일반적입니다. 실제로 ESP8266의 AT 명령에서도 문자열로 다루고 있습니다. 하지만, 본 글에서는 그냥 숫자로 처리하기로 했습니다. 이유는 없습니다. 그냥 그렇게 해보고 싶었습니다. 이 글을 읽으시는 분이 있다면 문자열로 처리할 것을 권장합니다. IPUNION은 4개의 요소를 갖는 바이트 배열(val[4])와 32비트 길이를 가지는 정수(longvalue)로 정의했습니다.

 

IPSTRUCT : 소켓 통신 과정에서 서버로 동작하려면 고정 ip를 가져야합니다. 고정 ip를 가져야 공유기에서 port forwading시킬 수 있습니다. ip, subnetmask, gateway 주소를 저장하기 위한 데이터 타입으로 IPSTRUCT형을 정의했습니다. 이 형은 IPUNION 변수 ip, subnetmask, gateway를 가지고 있습니다. 

 

QUEUE : ESP8266과 시리얼 통신에 사용할 데이터형입니다. 멤버 변수로 Head, Tail, Data, Queue를 가지고 있습니다.

 

class esp8266은 ESP8266형으로 정의했습니다. ESP8266의 멤버 변수 Queue, LastError, pHandle, SSID, Password, Ip 등 6개의 변수를 가지고 있고, 20여개의 멤버 함수를 가지고 있습니다. 멤버 변수들의 역할은 변수명을 보면 짐작할 수 있습니다.

 

다음으로 ESP8266.cpp에 다음과 같이 ESP8266형의 멤버 함수들을 구현합니다.

#include "main.h"
#include "ESP8266.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define WAIT_RESPOND_TIME		500
#define WAIT_REPETE			20

ESP8266::esp8266()
{
	LastError = NO_ERROR;
	pHandle = 0;
	memset(&Queue, 0, sizeof(QUEUE));
}

ESP8266::~esp8266()
{

}
void ESP8266::SetHandle(UART_HandleTypeDef *pUart)
{
	pHandle = pUart;
}

void ESP8266::SetSSID(uint8_t *pSSID)
{
	strcpy((char *)SSID, (char *)pSSID);
}

void ESP8266::SetPassword(uint8_t *pPassword)
{
	strcpy((char *)Password, (char *)pPassword);
}

bool ESP8266::SetIp(PIPSTRUCT pIp)
{
	uint8_t Buffer[128];

	memcpy(&Ip, pIp, sizeof(IPSTRUCT));
	sprintf((char *)Buffer, "AT+CIPSTA_CUR=\"%d.%d.%d.%d\",\"%d.%d.%d.%d\",\"%d.%d.%d.%d\"",
			Ip.ip.val[0], Ip.ip.val[1], Ip.ip.val[2], Ip.ip.val[3],
			Ip.gateway.val[0], Ip.gateway.val[1], Ip.gateway.val[2], Ip.gateway.val[3],
			Ip.subnet.val[0], Ip.subnet.val[1], Ip.subnet.val[2], Ip.subnet.val[3]);
	SendString(Buffer);
	return WaitForOK();
}

UART_HandleTypeDef *ESP8266::GetHandle(void)
{
	return pHandle;
}

uint8_t *ESP8266::GetSSID(void)
{
	return SSID;
}

uint8_t *ESP8266::GetPassword(void)
{
	return Password;
}

PIPSTRUCT ESP8266::GetIp(void)
{
	return &Ip;
}

uint8_t ESP8266::GetLastError(void)
{
	return LastError;
}

uint8_t ESP8266::GetData(void)
{
	if(Queue.Data == 0) {
		LastError = QUEUE_EMPTY;
		return FALSE;
	}
	uint8_t Ret = Queue.Queue[Queue.Tail++];
	Queue.Tail %= QUEUE_SIZE;
	Queue.Data--;
	LastError = NO_ERROR;
	return Ret;
}

bool ESP8266::PutData(uint8_t data)
{
	if(Queue.Data == QUEUE_SIZE) {
		LastError = QUEUE_FULL;
		return FALSE;
	}
	Queue.Queue[Queue.Head++] = data;
	Queue.Head %= QUEUE_SIZE;
	Queue.Data++;
	LastError = NO_ERROR;
	return TRUE;
}

uint16_t ESP8266::GetDataSoo(void)
{
	return Queue.Data;
}

bool ESP8266::CopyQueue(uint8_t *pDest)
{
	if(Queue.Data == 0) {
		LastError = QUEUE_EMPTY;
		return FAIL;
	}
	for(uint16_t i = 0;i < Queue.Data;i++) {
		*(pDest + i ) = Queue.Queue[(Queue.Tail + i) % QUEUE_SIZE];
	}
	LastError = NO_ERROR;
	return TRUE;
}

bool ESP8266::FindStringInqueue(uint8_t *pStr)
{
	uint8_t Buffer[QUEUE_SIZE] = {0,};
	uint8_t *p;

	CopyQueue(Buffer);
	if(LastError == QUEUE_EMPTY) return FALSE;
	p = (uint8_t *)strstr((char *)Buffer, (char *)pStr);
	if(p == 0) {
		LastError = NOT_FOUND;
		return FALSE;
	}
	LastError = NO_ERROR;
	return TRUE;
}

bool ESP8266::FindSkipStringInqueue(uint8_t *pConn, uint8_t *pStr)
{
	uint8_t Buffer[QUEUE_SIZE] = {0,};
	uint8_t *p;
	uint16_t Length;

	*pConn = 0;
	CopyQueue(Buffer);
	if(LastError == QUEUE_EMPTY) return FALSE;
	p = (uint8_t *)strstr((char *)Buffer, (char *)pStr);
	if(p == NULL) {
		LastError = NOT_FOUND;
		return FALSE;
	}
	*pConn = *(p - 2);
	Length = (int16_t)((int32_t)p - (int32_t)Buffer + strlen((char *)pStr));
	if(Queue.Data < Length) {
		LastError = DATA_NOTENOUGH;
		return FALSE;
	}
	Queue.Data -= Length;
	Queue.Tail += Length;
	Queue.Tail %= QUEUE_SIZE;
	LastError = NO_ERROR;
	return TRUE;
}

void ESP8266::SendString(uint8_t *pStr)
{
	if(pHandle == NULL) {
		LastError = HANDLE_NOTSET;
		return;
	}
	HAL_UART_Transmit(pHandle, pStr, strlen((char *)pStr), 10);
	HAL_UART_Transmit(pHandle, (uint8_t *)"\x0D\x0A", 2, 10);
	LastError = NO_ERROR;
}

bool ESP8266::WaitForOK(void)
{
	uint8_t r, j;
	uint16_t i;

	for(i = 0; i < WAIT_REPETE;i++) {
		HAL_Delay(WAIT_RESPOND_TIME);
		r = FindSkipStringInqueue(&j, (uint8_t *)"OK\x0D\x0A");
		if(r == TRUE) {
			LastError = NO_ERROR;
			return TRUE;
		}
	}
	LastError = NOT_FOUND;
	return FALSE;
}

bool ESP8266::SetModeStation(void)
{
	SendString((uint8_t *)"AT+CWMODE_CUR=1");
	return WaitForOK();
}

bool ESP8266::Connect(uint8_t *ssid, uint8_t *passwd)
{
	SetSSID(ssid);
	SetPassword(passwd);
	return Connect();
}

bool ESP8266::Connect(void)
{
	uint8_t Buffer[64];

	sprintf((char *)Buffer, "AT+CWJAP_CUR=\"%s\",\"%s\"", SSID, Password);
	SendString(Buffer);
	return WaitForOK();
}

bool ESP8266::SetMUX(uint8_t value)
{
	uint8_t Buffer[64];

	sprintf((char *)Buffer, "AT+CIPMUX=%d", value);
	SendString(Buffer);
	return WaitForOK();
}

bool ESP8266::SetServer(uint8_t set, uint16_t port)
{
	uint8_t Buffer[64];

	sprintf((char *)Buffer, "AT+CIPSERVER=%d,%d", set, port);
	SendString(Buffer);
	return WaitForOK();
}

bool ESP8266::CheckConnect(uint8_t *pConn)		// 0,CONNECT\x0D\x0A return connect number '0'
{
	return FindSkipStringInqueue(pConn, (uint8_t *)"CONNECT\x0D\x0A");
}

bool ESP8266::CheckClosed(uint8_t *pConn)		// 0,CLOSED\x0D\x0A return connect number '0'
{
	return FindSkipStringInqueue(pConn, (uint8_t *)"CLOSED\x0D\x0A");
}

bool ESP8266::Send(uint8_t Conn, uint16_t Length, uint8_t *pSend)
{
	uint8_t Buffer[64];
	uint16_t i;

	sprintf((char *)Buffer, "AT+CIPSEND=%c,%d", Conn, Length);
	SendString(Buffer);
	HAL_Delay(10);
	for(i = 0;i < Length;i++)
		HAL_UART_Transmit(pHandle, pSend + i, 1, 10);
	return WaitForOK();
}

bool ESP8266::Receive(uint8_t *pConn, uint16_t *pLength, uint8_t *pReceive)
{
	uint8_t *p;
	uint16_t i;					// +IPD,0,n:xxxx

	*pConn = *pLength = 0;
	if(FindSkipStringInqueue(pConn, (uint8_t *)"+IPD,") == FALSE)
		return FALSE;
	HAL_Delay(500);
	*pConn = GetData();
	GetData();		// ','
	p = pReceive;
	while(1) {
		*p = GetData();
		if(*p == ':') break;
		p++;
	}
	*p = 0;
	*pLength = atoi((char *)pReceive);
	if(Queue.Data < *pLength) {
		LastError = DATA_NOTENOUGH;
		return FALSE;
	}
	for(i = 0;i < *pLength;i++)
		*(pReceive + i) = GetData();
	LastError = NO_ERROR;
	return TRUE;
}

bool ESP8266::Close(uint8_t Conn)
{
	uint8_t Buffer[64];

	sprintf((char *)Buffer, "AT+CIPCLOSE=%d", Conn);
	SendString(Buffer);
	return WaitForOK();
}

 

ESP8266 멤버 함수들 중 생성자 ESP8266::esp8266()과 소멸자 ~ESP8266::esp8266(), void형 함수인 ESP8266::SetHandle(), ESP8266::SetSSID(), ESP8266::SetPassword(), ESP8266::SendString() 등은 리턴값이 없습니다.

 

다른 함수들 중 특별한 값을 리턴해야 하는 함수들은 함수명이 Get으로 시작하도록 했습니다. 이 함수들의 기능은 함수명에 그대로 나타납니다. 예를 들어 ESP8266::GetHandle() 함수는 USART handle을, ESP8266::GetSSID() 함수는 SSID의 포인터를 리턴합니다. ESP8266::GetPassword(), ESP8266::GetIp(), ESP8266::LastError(), ESP8266::GetData(), ESP8266:: ESP8266::GetDataSoo() 등도 멤버 함수명에에 나타난 값을 리턴합니다.

 

리턴값이 bool형인 함수들은 기능을 성공적으로 마치면 TRUE 값을, 성공하지 못하면 FALSE의 값을 리턴합니다. 이러한 함수들을 호출한 경우에 FALSE의 값이 돌아온 경우는 ESP8266:GetLastError() 함수를 호출해서 실패한 원인을 찾아 볼 수 있습니다. 본 프로그램의 경우 소켓 통신 상에서 나타난 에러(예를 들면 소켓 연결이 중단된 경우)는 처리하지 않고 있습니다. TRUE와 FALSE는 매크로 상수로 main.h에 정의해 놓았습니다.

 

중요한 멤버 함수들의 기능들을 설명하겠습니다.

 

① ESP8266::GetData(void) : Queue로부터 1바이트 가져옵니다.

 

ESP8266::PutData(uint8_t data) : Queue에 1바이트를 넣습니다. ESP8266 모듈로부터 데잍가 도착하면 이 함수를 호출하여 Queue에 1바이트를 넣을 것입니다.

 

ESP8266::GetDataSoo(void) : 현재 Queue 안에 있는 데이터 수를 리턴합니다.

 

ESP8266::CopyQueue(uint8_t *pDest) : 현재 Queue에 있는 내용을 pDest로 시작하는 메모리로 복사합니다. ESP8266형에서 사용하고 있는 Queue는 ring형이기 때문에 문자열을 찾을 때에 문제가 발생할 수 있습니다. 예를 들어 CONNECT라는 문자열을 찾을 때에 C가 Queue의 맨 마지막 메모리에 있으면 그 다음 문자인 O는 Queue의 맨 첫 메모리에 있게 되어 strstr() 함수로는 찾을 수 없게됩니다. 이 함수를 이용해서 Queue의 내용을 선형 메모리에 복사해 놓고 검색하면 이런 문제를 해결할 수 있습니다.

 

ESP8266::FindStringInqueue(uint8_t *pStr) : Queue에 pStr 문자열이 있는지 확인합니다. 문자열이 있으면 TRUE를, 없으면 FASLE를 리턴합니다.

 

ESP8266::FindSkipStringInqueue(uint8_t *pConn, uint8_t *pStr) : ESP8266 모듈이 소켓 연결에 성공하거나, 소켓 연결이 끊어진 경우에 다음과 같은 형태의 메시지가 들어 옵니다.

"0,CONNECTED"

"0,CLOSED"

맨 앞의 0은 연결 채널입니다. 이 함수를 호출하면 pStr의 내용이 있는지 검사합니다. pStr이 있으면 pStr보다 두 바이트 앞에 있는 값(위 예의 경우 '0')을 *pConn에 넣고, 최초의 데이터로부터 pStr까지의 내용을 다 처리한 것으로 간주하여 Queue에 있는 데이터를 없애고 TRUE를 리턴합니다. pStr이 없으면 *pConn에 0을 넣고 FALSE를 리턴합니다.

 

ESP8266::SendString(uint8_t *pStr) : 문자열 pStr에 Carage Return(CR:0x0D)과 Line Feed(LF:0x0A)를 추가하여  ESP8266 모듈로 전송합니다. STM32F103에서 ESP8266 모듈로 명령을 전달하는 용도로 사용합니다.

 

ESP8266::WaitForOK(void) : ESP8266 모듈이 명령을 잘 인식하면 "OK" + CR + LF를 보내옵니다. 이 함수는 매크로 상수 WAIT_RESPONSE_TIME만큼 대기했다가 FindStringInqueue() 함수를 호출하여 "OK" 신호를 검색합니다. "OK" 신호를 찾으면 TRUE를 리턴합니다. 매크로 상수 WAIT_REPEATE만큼 반복해도 "OK" 신호를 찾지 못하면 FALSE를 리턴합니다.

 

⑨ ESP8266::SetIp(IPSTRUCT ip) : 매개 변수 ip에 저장된 ip, networkmask, gateway 값에 따라 ESP8266 모듈의 ip를 지정합니다.

 

uint8_t ESP8266::Connect(uint8_t *ssid, uint8_t *passwd), uint8_t ESP8266::Connect(void) : ESP8266을 공유기에 연결합니다. ESP8266::SetSSID() 함수와 ESP8266::SetPassword() 함수로 SSID와 Password를 전달한 경우에는 매개 변수 없는 함수를 사용하고, 그렇지 않은 경우에는 SSID와 Password를 매개 변수로 전달하는 함수를 사용합니다.

 

⑪ ESP8266::SetModeStation(uint8_t mode), ESP8266::SetMUX(uint8_t value),  ESP8266::SetServer(uint8_t set, uint16_t port), ESP8266::Close(uint8_t Conn) : ESP8266 모듈을 설정합니다.

SetModeStation은 ESP8266 모듈의 ap 기능을 비활성화하고 station으로 동작하도록 지정합니다.

ESP8266::SetMUX() 함수는 ESP8266 모듈이 서버로 동작할 때에 Multiple 접속 허용 여부를 지정합니다.

ESP8266::SetServer() 함수는 서버로 설정 여부(set)를 설정하고, 서버로 설정할 경우 사용할 포트(port)를 지정합니다.

ESP8266::Close() 함수는 매개 변수로 전달 받은 채널 Conn의 연결을 종료합니다.

 

ESP8266::CheckConnect(uint8_t *pConn) : 클라이언트로부터 접속 요청이 들어와서 새로이 성공한 접속이 있는지 여부를 확인합니다. 새로운 접속이 있으면 *pConn에 연결 채널 정보를 넣고 TRUE를 리턴합니다. 새로이 성공한 접속이 없으면 FALSE를 리턴합니다.

 

ESP8266::CheckClosed(uint8_t *pConn) : 클라이언트와의 끊어진 접속이 있는지 여부를 확인합니다. 끊어진 접속이 있으면 *pConn에 연결 채널 정보를 넣고 TRUE를 리턴합니다. 끊어진 접속이 없으면 FALSE를 리턴합니다.

 

ESP8266::Send(uint8_t Conn, uint16_t Length, uint8_t *pSend) : 연결된 채널 Conn에 pSend가 가리키는 메모리로부터 Length만큼의 데이터를 전송합니다. 당연한 이야기이지만 채널 Conn은 위 ESP8266::CheckConnect(uint8_t *pConn)에서 연결된 채널이어야 합니다.

 

⑮ ESP8266::Receive(uint8_t *pConn, uint16_t *pLength, uint8_t *pReceive) : 클라이언트로부터 데이터가 들어왔는지 확인합니다. 데이터가 들어온 경우, *pConn에는 클라이언트가 연결된 채널 정보가 들어 있고 데이터는 pReceive로부터 *pLength 바이트만큼입니다.

 

class ESP8266과 관련된 내용이 상당히 길었습니다. 아래는 이 클래스를 이용해서 ESP8266 모듈이 서버로 동작하게 설정하는 내용을 구현해 보겠습니다.

 

먼저 main.h를 열고 다음의 코드를 입력합니다. 입력하는 위치에 관한 정보를 제시하기 위해서 주석문을 같이 적습니다. 이하의 코드에서도 주석문을 보고 입력 위치를 판단하시기 바랍니다.

/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
#define FAIL			0
#define SUCCESS			1
#define FALSE			0
#define	TRUE			1
/* USER CODE END EM */

 

ESP8266 모듈로부터 들어오는 데이터를 받기 위해서 USART3의 인터럽트 처리 루틴을 입력합니다. [Core] 폴더 아래의 [Src] 폴더에 있는 소스프로그램 [stm32f1xx_it.cpp]를 열고 다음의 내용을 각각의 주석문이 제시하는 적절한 위치에 입력합니다. 

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ESP8266.h"
/* USER CODE END Includes */

<중략>

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
extern ESP8266 Wifi;
/* USER CODE END PV */

<중략>

void USART3_IRQHandler(void)
{
  /* USER CODE BEGIN USART3_IRQn 0 */
  if ((__HAL_UART_GET_FLAG(Wifi.GetHandle(), UART_FLAG_RXNE) != RESET)) {
		Wifi.PutData((uint8_t) (Wifi.GetHandle()->Instance->DR & (uint8_t) 0x00FF));
  }
  __HAL_UART_CLEAR_PEFLAG(Wifi.GetHandle()); /* clear event flag */
  return;

  /* USER CODE END USART3_IRQn 0 */
  HAL_UART_IRQHandler(&huart3);
  /* USER CODE BEGIN USART3_IRQn 1 */

  /* USER CODE END USART3_IRQn 1 */
}

ESP8266 모듈로부터 데이터가 들어오면 ESP8266형 전역 변수 Wifi의 PutData() 함수를 사용해서 Wifi.Queue에 넣고 있습니다.

 

main.cpp 소스 프로그램을 열고 다음음의 내용들을 입력합니다.

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
#include "ESP8266.h"
/* USER CODE END Includes */

<중략>

/* USER CODE BEGIN PV */
ESP8266 Wifi;
/* USER CODE END PV */

<중략>

/* USER CODE BEGIN PFP */
void ReplyWifi(uint8_t Conn, uint16_t Length, uint8_t *pBuffer);
/* USER CODE END PFP */

<중략>

int main(void)
{
  /* USER CODE BEGIN 1 */
	IPSTRUCT Ip;
	uint16_t Length, Port = 15598;
	uint8_t Ret, Conn, FlagConn = 0;
	uint8_t Buffer[QUEUE_SIZE];

	uint8_t SSID[SSID_PW_LENGTH]   = "ssid_name";
	uint8_t PASSWD[SSID_PW_LENGTH] = "ssid_password";
	Ip.ip.longvalue      = 172 +  30 * 256 + (uint32_t)  1 * 256 * 256 + (uint32_t) 99 * 256 * 256 * 256;
	Ip.subnet.longvalue  = 255 + 255 * 256 + (uint32_t)255 * 256 * 256 + (uint32_t)  0 * 256 * 256 * 256;
	Ip.gateway.longvalue = 172 +  30 * 256 + (uint32_t)  1 * 256 * 256 + (uint32_t)254 * 256 * 256 * 256;

  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART3_UART_Init();
  /* USER CODE BEGIN 2 */
	HAL_UART_Receive_IT(&huart3, &Ret, 1);			// activate interrupt USART3
	Wifi.SetHandle(&huart3);					// set Wifi's USART handle
	if(Wifi.SetModeStation() != TRUE) Error_Handler();		// set ESP8266 as station only
	if(Wifi.SetIp(&Ip) != TRUE) Error_Handler();		// set ESP8266's IP
	if(Wifi.Connect(SSID, PASSWD) != TRUE) Error_Handler();	// connect to SSID
	if(Wifi.SetMUX(1) != TRUE) Error_Handler();			// enable multi connect
	if(Wifi.SetServer(1, Port) != TRUE) Error_Handler();	// set server and port
  /* USER CODE END 2 */
 
 

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    if(Wifi.CheckConnect(&Conn) == TRUE)				// if client succeed to connect
		FlagConn |= (1 << (Conn - '0'));
	if(FlagConn && Wifi.CheckClosed(&Conn) == TRUE)		// if connection was lost
		FlagConn &= ~(1 << (Conn - '0'));
	if(FlagConn && Wifi.Receive(&Conn, &Length, Buffer) == TRUE) {	// if data received
		ReplyWifi(Conn, Length, Buffer);				// reply
	}
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

<중략>

/* USER CODE BEGIN 4 */
void ReplyWifi(uint8_t Conn, uint16_t Length, uint8_t *pBuffer)
{
	uint8_t imsiBuff[1024];

	*(pBuffer + Length) = 0;
	sprintf((char *)imsiBuff, "From Server: %s", pBuffer);
	Wifi.Send(Conn, strlen((char *)imsiBuff), imsiBuff);
}

/* USER CODE END 4 */

 

전역 변수로 ESP8266형 Wifi를 선언하고, main() 함수 내내에도 필요한 변수들을 선언하고 정의합니다.

Port = 15598에서 서버가 사용할 포트를 15598로 정했고, SSID와 Password를 정했으며, ip는 172.30.1.99, subnetmask는 255.255.255.0, gateway는 172.30.1.254로 지정하고 있습니다.

 

기타 내용은 주석을 참고하기 바랍니다. ESP8266 모듈로부터 접속이 이루어지고 데이터를 받으면, ReplyWifi() 함수를 호출하여 응답을 보냅니다. 보내는 응답의 내용은 "From Server : " 뒤에 클라이언트로부터 받은 내용을 추가하여 보냅니다.

 

소스프로그램 파일을 zip 파일로 첨부합니다.

STM32F103ESP8266.zip
0.60MB

 

 

블로그 이미지

엠쿠스

Microprocessor(STM32, AVR)로 무엇인가를 만들어 보고자 학습 중입니다.

,