工程源碼下載下傳: https://download.csdn.net/download/xiaolong1126626497/15805037
一、硬體環境介紹
1. ESP8266 :采用安信可的模組,型号是ESP12F
2. STM32 : 采用STM32F103C8T6
3. 程式設計軟體 : 采用Keil5
ESP8266程式設計調試過程中用到的相關軟體下載下傳位址:
物聯網網調試終端:
https://download.csdn.net/download/xiaolong1126626497/12624530 TCP調試助手: https://download.csdn.net/download/xiaolong1126626497/12624461 序列槽調試助手: https://download.csdn.net/download/xiaolong1126626497/12624450二、ESP8266通信的調試與運作效果
下面幾張圖是将ESP8266配置成AP+TCP伺服器模式,電腦連接配接ESP8266的熱點之後,實作資料通信。通信的效果是,在電腦點選物聯網控制系統軟體,實作控制開發闆上的LED燈和蜂鳴器,開發闆上将檢測的光敏資料、溫度資料、RC522刷卡資料傳輸到電腦的軟體上進行顯示。----區域網路通信
三、硬體接線與代碼技術部分介紹
硬體連接配接: 下面會貼出核心代碼,在目前開發闆上,ESP8266接在STM32F103C8T6的序列槽3上。
代碼分為以下幾個部分:
(1) STM32程式裡的序列槽接收采用定時器+接收中斷的形式接收資料,使用這種方式可以接收不定長度資料,友善接下來與ESP8266進行通信。
(2). ESP8266驅動代碼:代碼實作了STA+TCP用戶端的一鍵配置函數,AP+TCP伺服器的一鍵配置函數,要配置ESP8266隻需要調用對應的函數傳入參數即可。
四、核心代碼部分
4.1 ESP8266.c代碼
#include "esp8266.h"
u8 ESP8266_IP_ADDR[16]; //255.255.255.255
u8 ESP8266_MAC_ADDR[18]; //硬體位址
/*
函數功能: ESP8266指令發送函數
函數傳回值:0表示成功 1表示失敗
*/
u8 ESP8266_SendCmd(char *cmd)
{
u8 i,j;
for(i=0;i<10;i++) //檢測的次數--發送指令的次數
{
USARTx_StringSend(USART3,cmd);
for(j=0;j<100;j++) //等待的時間
{
delay_ms(50);
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
if(strstr((char*)USART3_RX_BUFFER,"OK"))
{
return 0;
}
}
}
}
return 1;
}
/*
函數功能: ESP8266硬體初始化檢測函數
函數傳回值:0表示成功 1表示失敗
*/
u8 ESP8266_Init(void)
{
//退出透傳模式
USARTx_StringSend(USART3,"+++");
delay_ms(50);
return ESP8266_SendCmd("AT\r\n");
}
/*
函數功能: 一鍵配置WIFI為AP+TCP伺服器模式
函數參數:
char *ssid 建立的熱點名稱
char *pass 建立的熱點密碼 (最少8位)
u16 port 建立的伺服器端口号
函數傳回值: 0表示成功 其他值表示對應錯誤值
*/
u8 ESP8266_AP_TCP_Server_Mode(char *ssid,char *pass,u16 port)
{
char *p;
u8 i;
char ESP8266_SendCMD[100]; //組合發送過程中的指令
/*1. 測試硬體*/
if(ESP8266_SendCmd("AT\r\n"))return 1;
/*2. 關閉回顯*/
if(ESP8266_SendCmd("ATE0\r\n"))return 2;
/*3. 設定WIFI模式*/
if(ESP8266_SendCmd("AT+CWMODE=2\r\n"))return 3;
/*4. 複位*/
ESP8266_SendCmd("AT+RST\r\n");
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
/*5. 關閉回顯*/
if(ESP8266_SendCmd("ATE0\r\n"))return 5;
/*6. 設定WIFI的AP模式參數*/
sprintf(ESP8266_SendCMD,"AT+CWSAP=\"%s\",\"%s\",1,4\r\n",ssid,pass);
if(ESP8266_SendCmd(ESP8266_SendCMD))return 6;
/*7. 開啟多連接配接*/
if(ESP8266_SendCmd("AT+CIPMUX=1\r\n"))return 7;
/*8. 設定伺服器端口号*/
sprintf(ESP8266_SendCMD,"AT+CIPSERVER=1,%d\r\n",port);
if(ESP8266_SendCmd(ESP8266_SendCMD))return 8;
/*9. 查詢本地IP位址*/
if(ESP8266_SendCmd("AT+CIFSR\r\n"))return 9;
//提取IP位址
p=strstr((char*)USART3_RX_BUFFER,"APIP");
if(p)
{
p+=6;
for(i=0;*p!='"';i++)
{
ESP8266_IP_ADDR[i]=*p++;
}
ESP8266_IP_ADDR[i]='\0';
}
//提取MAC位址
p=strstr((char*)USART3_RX_BUFFER,"APMAC");
if(p)
{
p+=7;
for(i=0;*p!='"';i++)
{
ESP8266_MAC_ADDR[i]=*p++;
}
ESP8266_MAC_ADDR[i]='\0';
}
//列印總體資訊
USART1_Printf("目前WIFI模式:AP+TCP伺服器\n");
USART1_Printf("目前WIFI熱點名稱:%s\n",ssid);
USART1_Printf("目前WIFI熱點密碼:%s\n",pass);
USART1_Printf("目前TCP伺服器端口号:%d\n",port);
USART1_Printf("目前TCP伺服器IP位址:%s\n",ESP8266_IP_ADDR);
USART1_Printf("目前TCP伺服器MAC位址:%s\n",ESP8266_MAC_ADDR);
return 0;
}
/*
函數功能: TCP伺服器模式下的發送函數
發送指令:
*/
u8 ESP8266_ServerSendData(u8 id,u8 *data,u16 len)
{
u8 i,j,n;
char ESP8266_SendCMD[100]; //組合發送過程中的指令
for(i=0;i<10;i++)
{
sprintf(ESP8266_SendCMD,"AT+CIPSEND=%d,%d\r\n",id,len);
USARTx_StringSend(USART3,ESP8266_SendCMD);
for(j=0;j<10;j++)
{
delay_ms(50);
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
if(strstr((char*)USART3_RX_BUFFER,">"))
{
//繼續發送資料
USARTx_DataSend(USART3,data,len);
//等待資料發送成功
for(n=0;n<200;n++)
{
delay_ms(50);
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
if(strstr((char*)USART3_RX_BUFFER,"SEND OK"))
{
return 0;
}
}
}
}
}
}
}
return 1;
}
/*
函數功能: 配置WIFI為STA模式+TCP用戶端模式
函數參數:
char *ssid 建立的熱點名稱
char *pass 建立的熱點密碼 (最少8位)
char *p 将要連接配接的伺服器IP位址
u16 port 将要連接配接的伺服器端口号
u8 flag 1表示開啟透傳模式 0表示關閉透傳模式
函數傳回值:0表示成功 其他值表示對應的錯誤
*/
u8 ESP8266_STA_TCP_Client_Mode(char *ssid,char *pass,char *ip,u16 port,u8 flag)
{
char ESP8266_SendCMD[100]; //組合發送過程中的指令
//退出透傳模式
//USARTx_StringSend(USART3,"+++");
//delay_ms(50);
/*1. 測試硬體*/
if(ESP8266_SendCmd("AT\r\n"))return 1;
/*2. 關閉回顯*/
if(ESP8266_SendCmd("ATE0\r\n"))return 2;
/*3. 設定WIFI模式*/
if(ESP8266_SendCmd("AT+CWMODE=1\r\n"))return 3;
/*4. 複位*/
ESP8266_SendCmd("AT+RST\r\n");
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
/*5. 關閉回顯*/
if(ESP8266_SendCmd("ATE0\r\n"))return 5;
/*6. 配置将要連接配接的WIFI熱點資訊*/
sprintf(ESP8266_SendCMD,"AT+CWJAP=\"%s\",\"%s\"\r\n",ssid,pass);
if(ESP8266_SendCmd(ESP8266_SendCMD))return 6;
/*7. 設定單連接配接*/
if(ESP8266_SendCmd("AT+CIPMUX=0\r\n"))return 7;
/*8. 配置要連接配接的TCP伺服器資訊*/
sprintf(ESP8266_SendCMD,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",ip,port);
if(ESP8266_SendCmd(ESP8266_SendCMD))return 8;
/*9. 開啟透傳模式*/
if(flag)
{
if(ESP8266_SendCmd("AT+CIPMODE=1\r\n"))return 9; //開啟
if(ESP8266_SendCmd("AT+CIPSEND\r\n"))return 10; //開始透傳
if(!(strstr((char*)USART3_RX_BUFFER,">")))
{
return 11;
}
//如果想要退出發送: "+++"
}
//列印總體資訊
USART1_Printf("目前WIFI模式:STA+TCP用戶端\n");
USART1_Printf("目前連接配接的WIFI熱點名稱:%s\n",ssid);
USART1_Printf("目前連接配接的WIFI熱點密碼:%s\n",pass);
USART1_Printf("目前連接配接的TCP伺服器端口号:%d\n",port);
USART1_Printf("目前連接配接的TCP伺服器IP位址:%s\n",ip);
return 0;
}
/*
函數功能: TCP用戶端模式下的發送函數
發送指令:
*/
u8 ESP8266_ClientSendData(u8 *data,u16 len)
{
u8 i,j,n;
char ESP8266_SendCMD[100]; //組合發送過程中的指令
for(i=0;i<10;i++)
{
sprintf(ESP8266_SendCMD,"AT+CIPSEND=%d\r\n",len);
USARTx_StringSend(USART3,ESP8266_SendCMD);
for(j=0;j<10;j++)
{
delay_ms(50);
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
if(strstr((char*)USART3_RX_BUFFER,">"))
{
//繼續發送資料
USARTx_DataSend(USART3,data,len);
//等待資料發送成功
for(n=0;n<200;n++)
{
delay_ms(50);
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
if(strstr((char*)USART3_RX_BUFFER,"SEND OK"))
{
return 0;
}
}
}
}
}
}
}
return 1;
}
4.2 ESP8266.h
#ifndef _ESP8266_H
#define _ESP8266_H
#include "stm32f10x.h"
#include "usart.h"
#include "delay.h"
//函數聲明
u8 ESP8266_Init(void);
u8 ESP8266_SendCmd(char *cmd);
u8 ESP8266_AP_TCP_Server_Mode(char *ssid,char *pass,u16 port);
u8 ESP8266_ServerSendData(u8 id,u8 *data,u16 len);
u8 ESP8266_STA_TCP_Client_Mode(char *ssid,char *pass,char *ip,u16 port,u8 flag);
u8 ESP8266_ClientSendData(u8 *data,u16 len);
#endif
4.3 序列槽部分代碼
/*
函數功能: 序列槽1的初始化
硬體連接配接: PA9(TX) 和 PA10(RX)
*/
void USART1_Init(u32 baud)
{
/*1. 開時鐘*/
RCC->APB2ENR|=1<<14; //USART1時鐘
RCC->APB2ENR|=1<<2; //PA
RCC->APB2RSTR|=1<<14; //開啟複位時鐘
RCC->APB2RSTR&=~(1<<14);//停止複位
/*2. 配置GPIO口的模式*/
GPIOA->CRH&=0xFFFFF00F;
GPIOA->CRH|=0x000008B0;
/*3. 配置波特率*/
USART1->BRR=72000000/baud;
/*4. 配置核心寄存器*/
USART1->CR1|=1<<5; //開啟接收中斷
STM32_SetPriority(USART1_IRQn,1,1); //設定中斷優先級
USART1->CR1|=1<<2; //開啟接收
USART1->CR1|=1<<3; //開啟發送
USART1->CR1|=1<<13;//開啟序列槽功能
}
/*
函數功能: 序列槽3的初始化
硬體連接配接: PB10(TX) 和 PB11(RX)
*/
void USART3_Init(u32 baud)
{
/*1. 開時鐘*/
RCC->APB1ENR|=1<<18; //USART3時鐘
RCC->APB2ENR|=1<<3; //PB
RCC->APB1RSTR|=1<<18; //開啟複位時鐘
RCC->APB1RSTR&=~(1<<18);//停止複位
/*2. 配置GPIO口的模式*/
GPIOB->CRH&=0xFFFF00FF;
GPIOB->CRH|=0x00008B00;
/*3. 配置波特率*/
USART3->BRR=36000000/baud;
/*4. 配置核心寄存器*/
USART3->CR1|=1<<5; //開啟接收中斷
STM32_SetPriority(USART3_IRQn,1,1); //設定中斷優先級
USART3->CR1|=1<<2; //開啟接收
USART3->CR1|=1<<3; //開啟發送
USART3->CR1|=1<<13;//開啟序列槽功能
}
u8 USART3_RX_BUFFER[USART3_RX_LENGTH]; //儲存接收資料的緩沖區
u32 USART3_RX_CNT=0; //目前接收到的資料長度
u8 USART3_RX_FLAG=0; //1表示資料接收完畢 0表示沒有接收完畢
//序列槽3的中斷服務函數
void USART3_IRQHandler(void)
{
u8 data;
//接收中斷
if(USART3->SR&1<<5)
{
TIM3->CNT=0; //清除計數器
TIM3->CR1|=1<<0; //開啟定時器3
data=USART3->DR; //讀取序列槽資料
// if(USART3_RX_FLAG==0) //判斷上一次的資料是否已經處理完畢
{
//判斷是否可以繼續接收
if(USART3_RX_CNT<USART3_RX_LENGTH)
{
USART3_RX_BUFFER[USART3_RX_CNT++]=data;
}
else //不能接收,超出存儲範圍,強制表示接收完畢
{
USART3_RX_FLAG=1;
}
}
}
}
/*
函數功能: 字元串發送
*/
void USARTx_StringSend(USART_TypeDef *USARTx,char *str)
{
while(*str!='\0')
{
USARTx->DR=*str++;
while(!(USARTx->SR&1<<7)){}
}
}
/*
函數功能: 資料發送
*/
void USARTx_DataSend(USART_TypeDef *USARTx,u8 *data,u32 len)
{
u32 i;
for(i=0;i<len;i++)
{
USARTx->DR=*data++;
while(!(USARTx->SR&1<<7)){}
}
}
/*
函數功能: 格式化列印函數
*/
char USART1_PRINTF_BUFF[1024];
void USART1_Printf(char *fmt,...)
{
va_list ap;
/*1. 初始化形參清單*/
va_start(ap,fmt);
/*2. 提取可變形參資料*/
vsprintf(USART1_PRINTF_BUFF,fmt,ap);
/*3. 結束,釋放空間*/
va_end(ap);
/*4. 輸出資料到序列槽1*/
USARTx_StringSend(USART1,USART1_PRINTF_BUFF);
//USART1_Printf("%d%s",123,454656);
//int data=va_arg(ap,int);
}
4.4 定時器部分代碼
/*
函數功能: 配置定時器3
函數參數: psc 預分頻器 arr重裝載值
*/
void TIMER3_Init(u16 psc,u16 arr)
{
/*1. 開時鐘*/
RCC->APB1ENR|=1<<1; //開啟定時器3的時鐘
RCC->APB1RSTR|=1<<1;//開啟定時器3複位時鐘
RCC->APB1RSTR&=~(1<<1);//關閉定時器3複位時鐘
/*2. 配置核心寄存器*/
TIM3->PSC=psc-1;
TIM3->ARR=arr;
TIM3->DIER|=1<<0; //開啟更新中斷
STM32_SetPriority(TIM3_IRQn,1,1); //設定中斷優先級
// TIM3->CR1|=1<<0; //開啟定時器3
}
/*
函數功能: 定時器3中斷服務函數
*/
void TIM3_IRQHandler(void)
{
if(TIM3->SR&1<<0)
{
TIM3->SR&=~(1<<0);
USART3_RX_FLAG=1; //表示接收完畢
TIM3->CR1&=~(1<<0); //關閉定時器3
}
}
4.5 主函數調用部分(STA+TCP用戶端)示例
int main()
{
u8 key,cnt=0;
LED_Init();
BEEP_Init();
KEY_Init();
USART1_Init(115200);
USART3_Init(115200);//序列槽-WIFI
TIMER3_Init(72,20000); //逾時時間20ms
USART1_Printf("正在初始化WIFI請稍等.\n");
if(ESP8266_Init())
{
USART1_Printf("ESP8266硬體檢測錯誤.\n");
}
else
{
USART1_Printf("WIFI:%d\n",ESP8266_STA_TCP_Client_Mode("ChinaNet-wbyw","12345678","192.168.101.6",8088,1));
}
while(1)
{
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART1_Printf("%s",USART3_RX_BUFFER);
USART3_RX_CNT=0;
USART3_RX_FLAG=0;
}
key=KEY_Scan(0);
if(key==2)
{
USARTx_StringSend(USART3,"AT+GMR\r\n"); //檢視版本資訊
}
else if(key==3)
{
USARTx_StringSend(USART3,"12345ABCD");
}
else if(key==4) //退出透傳模式
{
USARTx_StringSend(USART3,"+++");
}
else if(key==5) //發送AT
{
USARTx_StringSend(USART3,"AT+CIPSTATUS\r\n"); //檢視狀态資訊
}
}
}