stm32實現簡單wifi通信

最近需要做wifi通信實驗,實驗中的坑比較多,本文章用於記錄實驗中遇到的問題。

實驗內容

瞭解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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章