STM32串口WEBSOCKET Server设计(基于ESP8266 WIFI模块AT模式)

STM32串口WEBSOCKET Server设计(基于ESP8266 WIFI模块AT模式)

HTML5标准支持WEBSOCKET Client,因此对于基于HTML5标准的桌面型应用(如Electron APP)以及移动APP(如HBUILDERX APP),可以通过WIFI模块,实现与嵌入式端WEBSOCKET Server的通讯。WIFI模块与嵌入式端的接口有多种包括SPI和TTL串口等,WIFI转TTL串口在物联网领域用得比较多。这里设计基于WIFI转TTL模块ESP8266的STM32 WEBSOCKET Server。STM32与ESP8266之间通过AT指令通讯。

ESP8266是WIFI转串口的模块,有多种型号,主要是3.3V供电的模块,但需注意一些扩展模块如正点原子的模块里加了一些电路,所以要求是5V供电。另外早期模块ESP-01的EN和RST管脚可以用跳线帽短路,利用RST内部上拉的特性使得EN管脚使能,才能只用普通4线(vcc, gnd, tx, rx)连接方式使用。而后来的ESP-01S模块则不需要去处理EN管脚。更低功耗的模块可以选择ESP-01W(和E103-W05A相兼容)。而需要邮票孔或者外接天线等还可以选择ESP8266的其它版本模块。
STM32串口WEBSOCKET Server设计(基于ESP8266 WIFI模块AT模式)_第1张图片

ESP8266基本配置

这里采用标准AT版本固件库的ESP8266。首先通过将ESP8266模块连接到USB转TTL串口模块,进行一些初始配置。这里需要注意,有些USB转TTL串口模块的输出电流不足,通过TTL串口访问时会出现异常,这种情况下就需要通过外部电源供电。连接到PC后,通过PC串口工具(默认115200波特率)发送AT,如果得到AT则通讯正常。

  1. 查询和配置ESP8266启动后的模式
    通过发送如下指令进行查询:
AT+CWMODE_DEF?

如果得到回复:

+CWMODE_DEF:2

则为正确模式,否则发送如下指令设置正确模式。指令里的_DEF表示存储到ESP8266内部FLASH里,(下次)启动后会读取生效。

AT+CWMODE_DEF=2
  1. 设置IP和子网掩码
    发送如下类似指令设置IP和子网掩码:
AT+CIPAP_DEF="192.168.4.1","192.168.4.1","255.255.255.0"

以上部分为将ESP8266模块连接到STM32之前所做的配置。这部分配置相对比较固定,且可断电不失,因此先做配置,从而减少STM32里的处理内容。

STM32CUBEIDE配置

这里基于HAL库采用STM32F401CCU6开发板和STM32CUBEIDE开发环境实现范例。
首先建立工程并配置时钟:
STM32串口WEBSOCKET Server设计(基于ESP8266 WIFI模块AT模式)_第2张图片
配置两个USART串口,USART1连接ESP8266模块,USART6用作调试输出。
STM32串口WEBSOCKET Server设计(基于ESP8266 WIFI模块AT模式)_第3张图片
STM32串口WEBSOCKET Server设计(基于ESP8266 WIFI模块AT模式)_第4张图片
STM32串口WEBSOCKET Server设计(基于ESP8266 WIFI模块AT模式)_第5张图片STM32串口WEBSOCKET Server设计(基于ESP8266 WIFI模块AT模式)_第6张图片

STM32串口WEBSOCKET Server设计(基于ESP8266 WIFI模块AT模式)_第7张图片
STM32串口WEBSOCKET Server设计(基于ESP8266 WIFI模块AT模式)_第8张图片
保存并生成初始工程文件:
STM32串口WEBSOCKET Server设计(基于ESP8266 WIFI模块AT模式)_第9张图片
在工程目录的包含文件目录(\Core\Inc)建立websocket.h文件内容如下:

/*
Note: currently only for single websocket frame communication, can be expanded if necessary.
*/

#include 
#include   

#define WS_MIN_LEN_READ 1088
#define WS_MAX_LEN_WRITE 512

char g_ws_read_buf[WS_MIN_LEN_READ] = {0};
char g_ws_write_buf[WS_MAX_LEN_WRITE] = {0};
char g_ws_write_buf_t[WS_MAX_LEN_WRITE] = {0};

unsigned short int ws_handshake_done = 0; 
unsigned long long payloadLen = 0;  
unsigned long long pack_data_length;

#ifdef __cplusplus
extern "C"{
#endif
	
#define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits)))) 	
const char base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	
typedef struct SHA1Context
{  
	unsigned Message_Digest[5];        
	unsigned Length_Low;               
	unsigned Length_High;              
	unsigned char Message_Block[64];   
	int Message_Block_Index;           
	int Computed;                      
	int Corrupted;                     
}SHA1Context; 

int tolower(int c);
int htoi(const char s[],int start,int len);
	
char fetch_sec_key(void); 
char compute_accept_key(void)	;
char shake_hand(void); 
	
void base64_encode(void);  	
char sha1_hash(void);
void SHA1Reset(SHA1Context * context); 
int SHA1Result(SHA1Context * context);
void SHA1Input(SHA1Context * context,const char * message_array,unsigned length);    
void SHA1ProcessMessageBlock(SHA1Context *); 
void SHA1PadMessage(SHA1Context * context); 

char analy_data(void); 
void pack_data(char * message, unsigned long long dn); 
void pack_data_bin(char * message, 	unsigned long long dn) ;

//if error, return 0, else return 1
char fetch_sec_key(void)  
{   
	const char * flag = "Sec-WebSocket-Key: "; 
	char * keyBegin = NULL; 
	int i = 0;	
 
	memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);    

	keyBegin = strstr(g_ws_read_buf, flag);  
	if(! keyBegin)   //w/o effective request head 
	{  
		return 0;  
	}
	
	//w/ effective request head
	keyBegin += strlen(flag);  

	for(i = 0; i < strlen(g_ws_read_buf); i++)  
	{  
		if((keyBegin[i] == 0x0A) || (keyBegin[i] == 0x0D))  //0x0A: new line; 0x0D: return
		{  
			break;  
		}  
		g_ws_write_buf[i] = keyBegin[i];  
	}  

	return 1;  
}  

//if error, return 0, else return 1
char compute_accept_key(void)  
{  
	const char * GUID="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";  	  
	int i = 0, n = 0;   
	
	//websocket key
	if(! fetch_sec_key())
		return 0;

	strcat(g_ws_write_buf, GUID);  

	if(! sha1_hash())
		return 0;
 
	n = strlen(g_ws_write_buf); 
 
	memset(g_ws_read_buf, '\0', WS_MIN_LEN_READ);  

	for(i = 0; i < n; i += 2)  
	{        
		g_ws_read_buf[i / 2] = htoi(g_ws_write_buf, i, 2);      
	}   

	base64_encode();   

	return 1;  
}  

//if error, return 0, else return 1
char shake_hand(void)  
{  
	memset(g_ws_read_buf, '\0', WS_MIN_LEN_READ);  

	sprintf(g_ws_read_buf, "HTTP/1.1 101 Switching Protocols\r\n");  
	sprintf(g_ws_read_buf, "%sUpgrade: websocket\r\n", g_ws_read_buf);  
	sprintf(g_ws_read_buf, "%sConnection: Upgrade\r\n", g_ws_read_buf);  
	sprintf(g_ws_read_buf, "%sSec-WebSocket-Accept: %s\r\n\r\n", g_ws_read_buf, g_ws_write_buf);  

	return 1;
}


/*base64 function*/
void base64_encode(void)   
{    
	int tmp = 0, i = 0;	
	int prepare = 0;     
	int temp = strlen(g_ws_read_buf) % 3;     
	char * f = NULL;   	   
	char changed[4];   

	memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);   
	f = g_ws_write_buf;
	while (tmp < strlen(g_ws_read_buf))   
	{   
		temp = 0;   
		prepare = 0;   
		memset(changed, '\0', 4);   
		while (temp < 3)   
		{      
			if (tmp >= strlen(g_ws_read_buf))   
			{   
				break;   
			}   
			prepare = ((prepare << 8) | (g_ws_read_buf[tmp] & 0xFF));   
			tmp++;   
			temp++;   
		}   
		prepare = (prepare << ((3 - temp) * 8));      
		for (i = 0; i < 4 ;i++ )   
		{   
			if (temp < i)   
			{   
				changed[i] = 0x40;   
			}   
			else   
			{   
				changed[i] = (prepare >> ((3 - i) * 6)) & 0x3F;   
			}
			*f = base[changed[i]];     
			f++;   
		}   
	}   
	*f = '\0';
} 


/*SHA1 function*/
void SHA1Reset(SHA1Context * context)
{
	context->Length_Low             = 0;  
	context->Length_High            = 0;  
	context->Message_Block_Index    = 0;  

	context->Message_Digest[0]      = 0x67452301;  
	context->Message_Digest[1]      = 0xEFCDAB89;  
	context->Message_Digest[2]      = 0x98BADCFE;  
	context->Message_Digest[3]      = 0x10325476;  
	context->Message_Digest[4]      = 0xC3D2E1F0;  

	context->Computed   = 0;  
	context->Corrupted  = 0;  
}  


int SHA1Result(SHA1Context * context)
{
	if (context->Corrupted)
	{  
		return 0;  
	}  
	if (!context->Computed) 
	{  
		SHA1PadMessage(context);  
		context->Computed = 1;  
	}  
	return 1;  
}  


void SHA1Input(SHA1Context * context,const char * message_array,unsigned length)
{  
	if (!length) 
		return;  

	if (context->Computed || context->Corrupted)
	{  
		context->Corrupted = 1;  
		return;  
	}  

	while(length-- && !context->Corrupted)
	{  
		context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF);  

		context->Length_Low += 8;  

		context->Length_Low &= 0xFFFFFFFF;  
		if (context->Length_Low == 0)
		{  
			context->Length_High++;  
			context->Length_High &= 0xFFFFFFFF;  
			if (context->Length_High == 0) context->Corrupted = 1;  
		}  

		if (context->Message_Block_Index == 64)
		{  
			SHA1ProcessMessageBlock(context);  
		}  
		message_array++;  
	}  
}  

void SHA1ProcessMessageBlock(SHA1Context * context)
{  
	const unsigned K[] = {0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };  
	int         t;                  
	unsigned    temp;               
	unsigned    W[80];              
	unsigned    A, B, C, D, E;      

	for(t = 0; t < 16; t++)
	{  
		W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;  
		W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;  
		W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;  
		W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);  
	}  

	for(t = 16; t < 80; t++)
		W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);  

	A = context->Message_Digest[0];  
	B = context->Message_Digest[1];  
	C = context->Message_Digest[2];  
	D = context->Message_Digest[3];  
	E = context->Message_Digest[4];  

	for(t = 0; t < 20; t++)
	{  
		temp =  SHA1CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];  
		temp &= 0xFFFFFFFF;  
		E = D;  
		D = C;  
		C = SHA1CircularShift(30,B);  
		B = A;  
		A = temp;  
	}  
	for(t = 20; t < 40; t++)
	{  
		temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];  
		temp &= 0xFFFFFFFF;  
		E = D;  
		D = C;  
		C = SHA1CircularShift(30,B);  
		B = A;  
		A = temp;  
	}  
	for(t = 40; t < 60; t++)
	{  
		temp = SHA1CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];  
		temp &= 0xFFFFFFFF;  
		E = D;  
		D = C;  
		C = SHA1CircularShift(30,B);  
		B = A;  
		A = temp;  
	}  
	for(t = 60; t < 80; t++)
	{  
		temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];  
		temp &= 0xFFFFFFFF;  
		E = D;  
		D = C;  
		C = SHA1CircularShift(30,B);  
		B = A;  
		A = temp;  
	}  
	context->Message_Digest[0] = (context->Message_Digest[0] + A) & 0xFFFFFFFF;  
	context->Message_Digest[1] = (context->Message_Digest[1] + B) & 0xFFFFFFFF;  
	context->Message_Digest[2] = (context->Message_Digest[2] + C) & 0xFFFFFFFF;  
	context->Message_Digest[3] = (context->Message_Digest[3] + D) & 0xFFFFFFFF;  
	context->Message_Digest[4] = (context->Message_Digest[4] + E) & 0xFFFFFFFF;  
	context->Message_Block_Index = 0;  
}  

void SHA1PadMessage(SHA1Context *context)
{  
	if (context->Message_Block_Index > 55)
	{  
		context->Message_Block[context->Message_Block_Index++] = 0x80;  
		while(context->Message_Block_Index < 64)  
			context->Message_Block[context->Message_Block_Index++] = 0;  
		SHA1ProcessMessageBlock(context);  
		while(context->Message_Block_Index < 56) 
			context->Message_Block[context->Message_Block_Index++] = 0;  
	} 
	else
	{  
		context->Message_Block[context->Message_Block_Index++] = 0x80;  
		while(context->Message_Block_Index < 56)
			context->Message_Block[context->Message_Block_Index++] = 0;  
	}  
	context->Message_Block[56] = (context->Length_High >> 24 ) & 0xFF;  
	context->Message_Block[57] = (context->Length_High >> 16 ) & 0xFF;  
	context->Message_Block[58] = (context->Length_High >> 8 ) & 0xFF;  
	context->Message_Block[59] = (context->Length_High) & 0xFF;  
	context->Message_Block[60] = (context->Length_Low >> 24 ) & 0xFF;  
	context->Message_Block[61] = (context->Length_Low >> 16 ) & 0xFF;  
	context->Message_Block[62] = (context->Length_Low >> 8 ) & 0xFF;  
	context->Message_Block[63] = (context->Length_Low) & 0xFF;  

	SHA1ProcessMessageBlock(context);  
}  

//if error, return 0, else return 1
char sha1_hash(void)
{ 
	SHA1Context sha = {0};
	SHA1Reset(&sha);  
	SHA1Input(&sha, g_ws_write_buf, strlen(g_ws_write_buf));  

	if (! SHA1Result(&sha))
	{  
		printf("%s-%d:Could not compute message digest.\n", __func__, __LINE__);  
		return 0;  
	}
	else
	{  
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);  
		sprintf(g_ws_write_buf, "%08X%08X%08X%08X%08X", sha.Message_Digest[0],sha.Message_Digest[1],  
				sha.Message_Digest[2],sha.Message_Digest[3],sha.Message_Digest[4]);  

		return 1;  
	}  
}


/*convertion function*/
int tolower(int c)   
{   
	if (c >= 'A' && c <= 'Z')   
	{   
		return c + 'a' - 'A';   
	}   
	else   
	{   
		return c;   
	}   
}   

int htoi(const char s[],int start,int len)   
{   
	int i,j;   
	int n = 0;
	if (s[0] == '0' && (s[1]=='x' || s[1]=='X'))
	{   
		i = 2;   
	}   
	else   
	{   
		i = 0;   
	}   
	i+=start;  
	j=0;  
	for (; (s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'f') || (s[i] >='A' && s[i] <= 'F');++i)   
	{     
		if(j>=len)  
		{  
			break;  
		}  
		if (tolower(s[i]) > '9')   
		{   
			n = 16 * n + (10 + tolower(s[i]) - 'a');   
		}   
		else   
		{   
			n = 16 * n + (tolower(s[i]) - '0');   
		}   
		j++;  
	}   
	return n;   
}   	

/*
Frame format:  
      0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 ......
     +-+-+-+-+-------+-+-------------+-------------------------------+
     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
     | |1|2|3|       |K|             |                               |
     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
     |     Extended payload length continued, if payload len == 127  |
     + - - - - - - - - - - - - - - - +-------------------------------+
     |                               |Masking-key, if MASK set to 1  |
     +-------------------------------+-------------------------------+
     | Masking-key (continued)       |          Payload Data         |
     +-------------------------------- - - - - - - - - - - - - - - - +
     :                     Payload Data continued ...                :
     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
     |                     Payload Data continued ...                |
     +---------------------------------------------------------------+
*/
char analy_data(void)  
{   
	char fin = 0;
	char maskFlag = 0;
	char masks[4] = {0};  
	char temp[8]; 
	unsigned long long i = 0;


  payloadLen = 0;
	if (strlen(g_ws_read_buf) < 2)   
	{  
    //data len error.
		return 0;  
	}  

	fin = (g_ws_read_buf[0] & 0x80) == 0x80; 
	if (!fin)  
	{  
    //fin error.
		return 0;
	}  

	maskFlag = (g_ws_read_buf[1] & 0x80) == 0x80;   
	if (!maskFlag)  
	{  
    //mask flag error.
		return 0;
	}  

	payloadLen = g_ws_read_buf[1] & 0x7F;  
	if (payloadLen == 126)  
	{        
		memcpy(masks, g_ws_read_buf + 4, 4);        
		payloadLen = (((unsigned short)g_ws_read_buf[2] ) << 8) | ((unsigned short)g_ws_read_buf[3]);      
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);  
		memcpy(g_ws_write_buf, g_ws_read_buf + 8, payloadLen);  
	}  
	else if (payloadLen == 127)  
	{  
		memcpy(masks, g_ws_read_buf + 10, 4);    
		for ( i = 0; i < 8; i++)  
		{  
			temp[i] = g_ws_read_buf[2 + i];  
		}   

		memcpy(&payloadLen,temp,8);      
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);   
		memcpy(g_ws_write_buf, g_ws_read_buf + 14, payloadLen);//toggle error(core dumped) if data is too long.  
     
	}  
	else  
	{     
		memcpy(masks, g_ws_read_buf + 2, 4);       
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);  
		memcpy(g_ws_write_buf, g_ws_read_buf + 6, payloadLen);   
	}  

	memset(g_ws_write_buf_t, '\0', WS_MAX_LEN_WRITE); 
	for (i = 0; i < payloadLen; i++)  
	{  
		g_ws_write_buf_t[i] = (char)(g_ws_write_buf[i] ^ masks[i % 4]);
	}  
	
  //get data: g_ws_write_buf_t w/ data length: payloadLen  
	
	return 1; 
}  

void pack_data(char * message, 	unsigned long long dn)  // message: input; dn: input; len: output
{   
  if (dn<=0) pack_data_length = 0;  
	else if ((dn > 0)&&(dn < 126))  
	{   
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);      
		g_ws_write_buf[0] = 0x81;  
		g_ws_write_buf[1] = dn;  
		memcpy(g_ws_write_buf + 2, message, dn);  
		pack_data_length = dn + 2;  
	}  
	else if ((dn >= 126)&&(dn <= 0xFFFF)) 
	{    
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);
		g_ws_write_buf[0] = 0x81;  
		g_ws_write_buf[1] = 126;  
		g_ws_write_buf[2] = ((dn >> 8) & 0xFF);  
		g_ws_write_buf[3] = (dn & 0xFF);  
		memcpy(g_ws_write_buf + 4, message, dn);      
		pack_data_length = dn + 4;  
	}  
	else  
	{  
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);
		g_ws_write_buf[0] = 0x81;  
		g_ws_write_buf[1] = 127;  
		g_ws_write_buf[2] = ((dn >> 56) & 0xFF);
		g_ws_write_buf[3] = ((dn >> 48) & 0xFF);
		g_ws_write_buf[4] = ((dn >> 40) & 0xFF);
		g_ws_write_buf[5] = ((dn >> 32) & 0xFF);
		g_ws_write_buf[6] = ((dn >> 24) & 0xFF);
		g_ws_write_buf[7] = ((dn >> 16) & 0xFF);
		g_ws_write_buf[8] = ((dn >> 8) & 0xFF);
		g_ws_write_buf[9] = ((dn >> 0) & 0xFF);
		
 
		memcpy(g_ws_write_buf + 10, message, dn);      
		pack_data_length = dn + 10;  
	} 
	

	
	//get data: g_ws_write_buf w/ length: *len
	//*len is essential for byte communication beyond character communication
}  

void pack_data_bin(char * message, 	unsigned long long dn)  // message: input; dn: input; len: output
{
  if (dn<=0) pack_data_length = 0;
	else if ((dn > 0)&&(dn < 126))
	{
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);
		g_ws_write_buf[0] = 0x82;
		g_ws_write_buf[1] = dn;
		memcpy(g_ws_write_buf + 2, message, dn);
		pack_data_length = dn + 2;
	}
	else if ((dn >= 126)&&(dn <= 0xFFFF))
	{
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);
		g_ws_write_buf[0] = 0x82;
		g_ws_write_buf[1] = 126;
		g_ws_write_buf[2] = ((dn >> 8) & 0xFF);
		g_ws_write_buf[3] = (dn & 0xFF);
		memcpy(g_ws_write_buf + 4, message, dn);
		pack_data_length = dn + 4;
	}
	else
	{
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);
		g_ws_write_buf[0] = 0x82;
		g_ws_write_buf[1] = 127;
		g_ws_write_buf[2] = ((dn >> 56) & 0xFF);
		g_ws_write_buf[3] = ((dn >> 48) & 0xFF);
		g_ws_write_buf[4] = ((dn >> 40) & 0xFF);
		g_ws_write_buf[5] = ((dn >> 32) & 0xFF);
		g_ws_write_buf[6] = ((dn >> 24) & 0xFF);
		g_ws_write_buf[7] = ((dn >> 16) & 0xFF);
		g_ws_write_buf[8] = ((dn >> 8) & 0xFF);
		g_ws_write_buf[9] = ((dn >> 0) & 0xFF);


		memcpy(g_ws_write_buf + 10, message, dn);
		pack_data_length = dn + 10;
	}



	//get data: g_ws_write_buf w/ length: *len
	//*len is essential for byte communication beyond character communication
}

#ifdef __cplusplus
}
#endif

STM32主代码

因为ESP8266上电时向串口输出上电信息,因此STM32在打开USART1串口接收中断前,应该延时一段时间,以规避处理这部分上电信息。然后STM32控制ESP8266进入无回显状态(ATE0指令),开启多连接(AT+CIPMUX=1指令),设置端口号(AT+CIPSERVER=1,8080指令,这里8080为端口号),以及准备发送(AT+CIPSENDEX=0,1460指令,实际发送过程中,会通过特定的结束符指示进行发送)。
STM32主代码实现接受WEBSOCKET连接,范例功能设计为在接收到两个字节时,返回这两个字节, 在接收到其他数据时,返回"F" (fault)。
为简化例程设计,一些向ESP8266发送的指令的回复,会接收但不做识别处理。
代码里用到延时函数原理参考 STM32 HAL us delay(微秒延时)的指令延时实现方式及优化 。

完整的main.c文件代码如下:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include 
#include 

#include "websocket.h"
/*
 To config ESP8266 module in advance for the following command:
 AT+CWSAP_DEF="ESP_Pegasus","12345678",1,4   //Set AP&PSW
 AT+CIPAP_DEF="192.168.4.1","192.168.4.1","255.255.255.0" //Set IP
 */
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define WRXMAX 1460
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart6;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART6_UART_Init(void);
/* USER CODE BEGIN PFP */
float usDelayBase;
void PY_usDelayTest(void)
{
  uint32_t firstms, secondms;
  uint32_t counter = 0;

  firstms = HAL_GetTick()+1;
  secondms = firstms+1;

  while(uwTick!=firstms) ;

  while(uwTick!=secondms) counter++;

  usDelayBase = ((float)counter)/1000;
}

void PY_Delay_us_t(uint32_t Delay)
{
  uint32_t delayReg;
  uint32_t usNum = (uint32_t)(Delay*usDelayBase);

  delayReg = 0;
  while(delayReg!=usNum) delayReg++;
}
void PY_usDelayOptimize(void)
{
  uint32_t firstms, secondms;
  float coe = 1.0;

  firstms = HAL_GetTick();
  PY_Delay_us_t(1000000) ;
  secondms = HAL_GetTick();

  coe = ((float)1000)/(secondms-firstms);
  usDelayBase = coe*usDelayBase;
}
void PY_Delay_us(uint32_t Delay)
{
  uint32_t delayReg;

  uint32_t msNum = Delay/1000;
  uint32_t usNum = (uint32_t)((Delay%1000)*usDelayBase);

  if(msNum>0) HAL_Delay(msNum);

  delayReg = 0;
  while(delayReg!=usNum) delayReg++;
}

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t Uart1_RxBuff[WRXMAX+1]={0}; //for max length of one package of Ethernet
uint8_t uart1_rx_status = 0x80;
uint8_t uart1_rx_rxloc = 0;
char * uart1_tx_cmd = "AT+CIPSENDEX=0,1460\r\n";

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* 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_USART1_UART_Init();
  MX_USART6_UART_Init();
  /* USER CODE BEGIN 2 */
  uart1_rx_status=0x80;

  PY_usDelayTest();
  PY_usDelayOptimize();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      //start of ESP8266 config
	  if(uart1_rx_status==0x80)
	  {

		    PY_Delay_us_t(2000000); //to escape ESP8266 power up information

			memset(Uart1_RxBuff, '\0', WRXMAX);
			uart1_rx_status=0x81;
			HAL_UART_Receive_IT(&huart1, Uart1_RxBuff, 1);

			uart1_tx_cmd = "ATE0\r\n";
			HAL_UART_Transmit(&huart1, uart1_tx_cmd,8,2000);
	  }

	  if(uart1_rx_status==0x82)
	  {
		    HAL_UART_Receive(&huart1, (uint8_t *)&Uart1_RxBuff[1], WS_MIN_LEN_READ-1, 100);
		    HAL_UART_Transmit(&huart6, Uart1_RxBuff, strlen(Uart1_RxBuff), 2720);

			memset(Uart1_RxBuff, '\0', WRXMAX);
			uart1_rx_status=0x83;
			HAL_UART_Receive_IT(&huart1, Uart1_RxBuff, 1);

			uart1_tx_cmd = "AT+CIPMUX=1\r\n";
			HAL_UART_Transmit(&huart1, uart1_tx_cmd,15,2000);
	  }

	  if(uart1_rx_status==0x84)
	  {
		    HAL_UART_Receive(&huart1, (uint8_t *)&Uart1_RxBuff[1], WS_MIN_LEN_READ-1, 100);
		    HAL_UART_Transmit(&huart6, Uart1_RxBuff, strlen(Uart1_RxBuff), 2720);

			memset(Uart1_RxBuff, '\0', WRXMAX);
			uart1_rx_status=0x85;
			HAL_UART_Receive_IT(&huart1, Uart1_RxBuff, 1);

			uart1_tx_cmd = "AT+CIPSERVER=1,8080\r\n";
		    HAL_UART_Transmit(&huart1, uart1_tx_cmd,23,2000);

	  }

	  if(uart1_rx_status==0x86)
	  {
		    HAL_UART_Receive(&huart1, (uint8_t *)&Uart1_RxBuff[1], WS_MIN_LEN_READ-1, 100);
		    HAL_UART_Transmit(&huart6, Uart1_RxBuff, strlen(Uart1_RxBuff), 2720);

		    memset(Uart1_RxBuff, '\0', WRXMAX);
			uart1_rx_status=0x00;
			HAL_UART_Receive_IT(&huart1, Uart1_RxBuff, 1);

			uart1_tx_cmd = "AT+CIPSENDEX=0,1460\r\n";
	  }
	  //end of ESP8266 config

	  //start of websocket connection
	  if(uart1_rx_status==1)
	  {
		  HAL_UART_Receive(&huart1, (uint8_t *)&Uart1_RxBuff[1], WS_MIN_LEN_READ-1, 100);
		  uart1_rx_rxloc=0;
		  for(uint8_t j=0;j<30;j++)
		  {
			  if(Uart1_RxBuff[j]==0x3A) //searching ":"
			  {
				  uart1_rx_rxloc=j+1;
				  break;
			  }
		  }

		  memcpy(g_ws_read_buf, &Uart1_RxBuff[uart1_rx_rxloc], WS_MIN_LEN_READ); //Receving data ends with "0x0A" and "0x0D" for recognition

		  if (compute_accept_key()==0)
		  {
			  uart1_rx_status = 0;
		  }
		  else
		  {
			  HAL_UART_Transmit(&huart1, uart1_tx_cmd,23, 2000);
			  uart1_rx_status=0xf1;
			  HAL_UART_Receive_IT(&huart1, Uart1_RxBuff, 1);
			  while(uart1_rx_status==0xf1) PY_Delay_us(10);
			  HAL_UART_Receive(&huart1, (uint8_t *)&Uart1_RxBuff[1], WS_MIN_LEN_READ-1, 100);

			  shake_hand() ;
			  HAL_UART_Transmit(&huart1, g_ws_read_buf, strlen(g_ws_read_buf), 2000);

				  Uart1_RxBuff[0]=0x5c;
				  Uart1_RxBuff[1]=0x30;
				  HAL_UART_Transmit(&huart1, Uart1_RxBuff,2, 2000);

				  uart1_rx_status=0xf1;
				  HAL_UART_Receive_IT(&huart1, Uart1_RxBuff, 1);
				  while(uart1_rx_status==0xf1) PY_Delay_us(10);
				  HAL_UART_Receive(&huart1, (uint8_t *)&Uart1_RxBuff[1], WS_MIN_LEN_READ-1, 100);

				  uart1_rx_status = 2;

				  HAL_UART_Transmit(&huart6, "Websocket connected!", 23, 2720);
		  }
		      memset(Uart1_RxBuff, '\0', WRXMAX);  //Set "end character" for recognition
			  HAL_UART_Receive_IT(&huart1, (uint8_t *)&Uart1_RxBuff[0], 1);
	  }
	  //end of websocket connection

      //start of data receiving and processing
	  if(uart1_rx_status==3)
	  {
	      HAL_UART_Receive(&huart1, (uint8_t *)&Uart1_RxBuff[1], WS_MIN_LEN_READ-1, 2000);

		  uart1_rx_rxloc=0;
		  for(uint8_t j=0;j<30;j++)
		  {
			  if(Uart1_RxBuff[j]==0x3A) //searching ":"
			  {
				  uart1_rx_rxloc=j+1;
				  break;
			  }
		  }
		  memcpy(g_ws_read_buf, &Uart1_RxBuff[uart1_rx_rxloc], WS_MIN_LEN_READ);

		  analy_data() ;

	      if(payloadLen!=2)
	      {
			  HAL_UART_Transmit(&huart1, uart1_tx_cmd,23, 2000);
			  uart1_rx_status=0xf1;
			  HAL_UART_Receive_IT(&huart1, Uart1_RxBuff, 1);
			  while(uart1_rx_status==0xf1) PY_Delay_us(10);
			  HAL_UART_Receive(&huart1, (uint8_t *)&Uart1_RxBuff[1], WS_MIN_LEN_READ-1, 100);

			  g_ws_write_buf_t[0]='F';  //Failure for data receiving length
			  pack_data(g_ws_write_buf_t, 1) ;
			  HAL_UART_Transmit(&huart1, g_ws_write_buf, pack_data_length, 2000);

			  Uart1_RxBuff[0]=0x5c;
			  Uart1_RxBuff[1]=0x30;
			  HAL_UART_Transmit(&huart1, Uart1_RxBuff,2, 2000); //flag of start sending

			  uart1_rx_status=0xf1;
			  HAL_UART_Receive_IT(&huart1, Uart1_RxBuff, 1);
			  while(uart1_rx_status==0xf1) PY_Delay_us(10);
			  HAL_UART_Receive(&huart1, (uint8_t *)&Uart1_RxBuff[1], WS_MIN_LEN_READ-1, 100);

			  memset(Uart1_RxBuff, '\0', WRXMAX);  //Set "end character" for recognition
		      uart1_rx_status=2;
		      HAL_UART_Receive_IT(&huart1, (uint8_t *)&Uart1_RxBuff[0], 1);
	      }
	      else
	      {
			  HAL_UART_Transmit(&huart1, uart1_tx_cmd,23, 2000);
			  uart1_rx_status=0xf1;
			  HAL_UART_Receive_IT(&huart1, Uart1_RxBuff, 1);
			  while(uart1_rx_status==0xf1) PY_Delay_us(10);
			  HAL_UART_Receive(&huart1, (uint8_t *)&Uart1_RxBuff[1], WS_MIN_LEN_READ-1, 100);

			  pack_data(g_ws_write_buf_t, 2) ;
			  HAL_UART_Transmit(&huart1, g_ws_write_buf, pack_data_length, 2000);

			  Uart1_RxBuff[0]=0x5c;
			  Uart1_RxBuff[1]=0x30;
			  HAL_UART_Transmit(&huart1, Uart1_RxBuff,2, 2000); //flag of start sending

			  uart1_rx_status=0xf1;
			  HAL_UART_Receive_IT(&huart1, Uart1_RxBuff, 1);
			  while(uart1_rx_status==0xf1) PY_Delay_us(10);
			  HAL_UART_Receive(&huart1, (uint8_t *)&Uart1_RxBuff[1], WS_MIN_LEN_READ-1, 100);

			  memset(Uart1_RxBuff, '\0', WRXMAX);  //Set "end character" for recognition
		      uart1_rx_status=2;
		      HAL_UART_Receive_IT(&huart1, (uint8_t *)&Uart1_RxBuff[0], 1);
	      }
	  }
	  //end of data receiving and processing

    /* USER CODE END WHILE */

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

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * @brief USART6 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART6_UART_Init(void)
{

  /* USER CODE BEGIN USART6_Init 0 */

  /* USER CODE END USART6_Init 0 */

  /* USER CODE BEGIN USART6_Init 1 */

  /* USER CODE END USART6_Init 1 */
  huart6.Instance = USART6;
  huart6.Init.BaudRate = 115200;
  huart6.Init.WordLength = UART_WORDLENGTH_8B;
  huart6.Init.StopBits = UART_STOPBITS_1;
  huart6.Init.Parity = UART_PARITY_NONE;
  huart6.Init.Mode = UART_MODE_TX_RX;
  huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart6.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart6) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART6_Init 2 */

  /* USER CODE END USART6_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();

}

/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
	if(UartHandle==&huart1) //for WiFi
	{
		if(uart1_rx_status==0)
		{
			uart1_rx_status=1;
		}

		if(uart1_rx_status==2)
		{
			uart1_rx_status=3;

		}

		if(uart1_rx_status==0x81)
		{
		    uart1_rx_status=0x82;
		}
		if(uart1_rx_status==0x83)
		{
		    uart1_rx_status=0x84;
		}
		if(uart1_rx_status==0x85)
		{
		    uart1_rx_status=0x86;
		}

		if(uart1_rx_status==0xf1)
		{
		    uart1_rx_status=0xf0;
		}


	}


}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */


测试过程

  1. 嵌入式端上电后,打开PC或手机WIFI,查找对应的热点如ESP_PEGASUS,然后输入密码如12345678连接。如果有出现当前WIFI热点不能上网的提示时,选择保持此连接;
  2. 用Chrome浏览器打开下面代码的websocket_test.html文件;
  3. 点击”Run WebSocket“链接,触发websocket连接及发送两个字符"OK";
  4. 从开发者工具的控制台查看过程及接收信息。


   
   
   Websocket Demo
    
      
        
   
   
   
      
      
   

STM32串口WEBSOCKET Server设计(基于ESP8266 WIFI模块AT模式)_第10张图片

WEBSOCKET协议应用特征

这里的WEBSOCKET协议应用特征如下:

  1. 只接受客户端发来的单帧数据,即FIN为0时认为错误不做处理。因此如果要发来的数据很长时,要在客户端自行先做分段,再将分段按单帧进行发送;
  2. 只接受客户端发来的加密数据,未加密时认为错误不做处理;
  3. 客户端发来的opcode对服务器端没有价值,嵌入式服务器端当作字节数据处理即可;
  4. 服务器端向客户端发送数据时不做数据加密;
  5. 服务器端向客户端发送的opcode有意义,浏览器客户端的处理方式会不同。

–End–

你可能感兴趣的:(STM32,websocket,stm32,WIFI,AT,串口websocket,server)