stm32实现简单wifi通信

最近需要做wifi通信实验,实验中的坑比较多,本文章用于记录实验中遇到的问题。
----------更新:本文章只实现了简单的wifi连接功能,最近封装了较完整的wifi协议,能够实现wifi连接、服务器连接、封装发送数据、解析接收数据、服务器创建等功能,文章链接:https://blog.csdn.net/qq_26024785/article/details/107352408

实验内容

了解ESP8266的基本工作原理,使程序能够自行连接给定的WIFI热点和服务器并实现双向通信。
工程文件网盘地址:https://pan.baidu.com/s/11HxmfvIRzxYGAoqXzZa0Uw 提取码:hbv2

整体思路

通过直接控制wifi模块可以发现整个连接过程有几个指令是不可缺少的:

  1. AT测试、
  2. AT+CWMODE=1设置工作模式、
  3. AT+CWJAP=“热点名称”,“热点密码”
  4. AT+CIPSTART=“TCP”,“服务器地址”,端口号

另外为了方便测试还有ATE1打开回显。
根据以上命令编写wifi_init()函数,先向wifi模块发送“AT”,接收到OK后发送“AT+CWMODE=1”,接收到OK后一次发送3、4两条命令同时检测是否接收到OK。
在上述任意环节超出超时时间后还没有检测到OK则认为连接失败,进行下一次连接,连续连接失败3次后返回错误信息。

代码解析

wifi模块参数配置:

#define WIFI_NAME "hello_world"			//需要连接的热点名
#define WIFI_PWD "87654321"					//热点密码
#define SERVER_ADDR "192.168.43.73"		//服务器IP地址
#define SERVER_PORT "5656"						//端口号

此代码段在my_func.h中4-7行,将其中的参数改成自己的热点及服务器信息。

wifi初始化程序:

int wifi_init()
{
	uint8_t ret=0;
	
	ret = Send_AT_commend("AT", "OK", 100);
	if(!ret)
		return -1;
	#ifdef DEBUG
		Send_AT_commend("ATE1", "", 100);
	#else
		Send_AT_commend("ATE0", "", 100);
	#endif
	ret = Send_AT_commend("AT+CWMODE=1", "OK", 100);
	if(!ret)
		return -2;
	wifi_str();
	ret = Send_AT_commend(temp, "OK", 9000); 			//AT+CWJAP="pxc002","?????"
	if(!ret)
		return -3;
	server_str();
	ret = Send_AT_commend(temp, "OK", 3000);			//AT+CIPSTART="TCP","192.168.31.32",3456
	if(!ret)
		return -4;
	return 1;
}

#ifdef到#endif之间的代码为开关AT指令回显,去掉后对程序功能无影响。

发送AT指令函数:

uint8_t Send_AT_commend(char *at_commend, char *re_commend, uint16_t time_out)
{
	uint8_t i=0;
	for(i=0;i<3;i++)
	{
		clear_buf();											//清空接收数组
		HAL_UART_Transmit(&huart1, (uint8_t *)at_commend, strlen(at_commend), 0xFFFF);
		HAL_UART_Transmit(&huart1, (uint8_t *)"\r\n", 2, 0xFFFF);				//发送回车换行
		HAL_Delay(time_out);
		if(find_str(re_commend))
			return 1;
		i++;
	}
	return 0;
}

此函数接收三个参数,分别为需要发送的AT指令、期待的返回数据、超时时间。
发送AT指令前先将my_re_buf1清空,防止对之前的数据误判,然后发送AT指令并发送回车换行,延时time_out,通过find_str()函数查找开发板是否接收到了wifi模块发来的OK,检测到则返回1,否则i++再发送一次,三次都没有检测到的话就返回0。

定时器中断回调程序:

while(send_buf[i])send_buf[i++]=0x00;			//清空send_buf数组
while(pt_r2<pt_w2 )
{
	//HAL_UART_Transmit(&huart1,&my_re_buf2[pt_r2++],1,1000);				
	while(pt_r2<pt_w2)
		send_buf[len++]=my_re_buf2[pt_r2++];
	wifi_send(send_buf,len);
}

将demo中的程序注释掉,改成自己的以便实现PC通过板子向服务器发送数据。当pt_r2<pt_w2时,将my_re_buf2中新接收到的数据拷贝到send_buf数组中,再调用wifi_send()函数发送数据。

发送数据函数:

void wifi_send(uint8_t *buf, int len)
{
	char len_str[]="",temp1[256]="";
	itoa(len, len_str);
	strcat(temp1,"AT+CIPSEND=");
	strcat(temp1,len_str);
	HAL_UART_Transmit(&huart2, (uint8_t *)"发送数据\r\n", 10, 0xFFFF);
	if(Send_AT_commend(temp1, ">", 300))
		if(Send_AT_commend((char *)buf, "SEND OK", 300))
			HAL_UART_Transmit(&huart2, (uint8_t *)"发送成功!!!\r\n", 16, 0xFFFF);
}

此函数接收两个参数,分别为需要发送的字符串数组、发送字节数。
通过tioa()函数将整数len转换为字符串,并通过strcat将temp1拼接成AT+CIPSEND=len。Send_AT_commend()发送字符串temp1,在接收到“>”后发送字符串buf,接收到“SEND OK”则发送成功。

踩到的坑

strstr()函数:

strstr(s1,s2)函数接收两个字符串参数,具体功能是检测s2是否是s1的子集,是的话返回s2首次出现的地址,否则返回NULL。但是这个函数里面有个硬性bug,如果s1[]={0x00, ‘a’, ‘b’, ‘c’} s1[]={‘a’},strstr(s1,s2)执行后返回NULL,也就是说strstr函数执行的结束标志是s1数组的0x00。这个bug坑了我两个多小时!!!

指针传值问题:

在C语言程序中需要计算字符串数组s的长度通常会用到sizeof或者strlen函数,但是如果char *p=s的话sizeof§和strlen§得到的数据都不是s的长度,具体解释是p虽然指向s数组的首地址,但是p不含有s数组后面的数据,因为以上两个函数无法通过指针p获取s的长度。

总结

C语言基础知识掌握的扎实真的很重要,否则会像我这样遇到许多很智障的bug。由于写此工程时利用的是零碎的空闲时间且比较仓促,没有做充足的实验验证,因此工程还有一些隐藏和没有解决的bug,比如发送数据时总是会丢失第一个字节(但是发送数据前加一个空格能够完美解决,至于为什么我也不知道,懒得解决了就这样吧) (此bug已解决)。所以工程仅供学习交流,切勿用于生产。

原文地址: https://www.jhxblog.cn/article/?articleid=1

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页