買正點原子的開發板時送了一塊ESP8266wifi模塊,一直沒使用,最近幾天剛好有時間就拿出來玩了一下,現在實現過程分享出來。
用到的模塊:
1.STM32F103C8T6最小系統板
2.正點原子ESP8266wifi模塊
3.USB轉串口模塊
整體連接圖
ESP8266模塊與單片機引腳連接關係 :
STM32F103C8T6最小系統 | ESP8266 模塊 |
5V | VCC |
GND | GND |
PB11(USART3_RX) | TXD |
PB10(USATR3_TX) | RXD |
ESP8266模塊的RST引腳和ID_0引腳懸空,可以不用管。
串口模塊與單片機引腳連接關係 :
STM32F103C8T6最小系統 | USB轉串口TTL模塊 |
PA9(USART1_TX) | RXD |
PA10(USART1_RX) | TXD |
GND | GND |
USB轉串口模塊連接到單片機的串口1上,單片機串口1用來作爲調試端口,監控程序的執行過程。ESP8266模塊連接到單片機串口3上,串口3用來實現與wifi模塊的通信。
具體實現的功能是:單片機通過wifi模塊連接上原子雲,並實時向雲端發送數據。通過雲端可以向單片機發送 “led on”、“led off”、“led toggle”指令,實現開發板上LED燈的點亮、熄滅、翻轉。
串口1監控數據結果
原子雲上監控數據
通過原子雲上位機測試軟件監控
通過手機上原子雲客戶端監控:
通過網頁、上位機軟件、手機客戶端可以向單片機發送 “led on”、“led off”、“led toggle”指令,實現開發板上LED燈的點亮、熄滅、翻轉。基本實現的功能就這些,下面說一下實現思想。
ESP8266模塊的驅動代碼是在野火【WiFi_ESP8266】模塊資料上修改的,具體下載地址:https://ebf-products.readthedocs.io/zh_CN/latest/module/wifi/esp8266.html
正點原子ESP8266wifi模塊相關資料下載地址:http://www.openedv.com/thread-308397-1-1.html
通過單片機控制ESP8266模塊連接原子雲的過程和直接通過串口調試ESP8266模塊的過程差不多,實現流程如下:
1.向模塊發送測試指令
向模塊發生指令: AT
模塊回覆指令: OK
2.設置模塊模式爲STA模式
向模塊發生指令: AT+CWMODE=1
模塊回覆指令: OK
3.設置要連接熱點的 ID 和密碼
向模塊發生指令: AT+CWJAP=“enbiens”,”EB88858804”
模塊回覆指令: OK
4.連接原子雲 發送設備編號和密碼
向模塊發生指令: AT+ATKCLDSTA="61212332528032817648","12345678"
模塊回覆指令: CLOUD CONNECTED
只需要4步就可以連接到原子雲上,ESP8266模塊要連接原子雲必須要刷原子雲的固件,否則最後一步連接原子雲的命令是識別不了的。
首先發送測試命令,判斷模塊與單片機的連接狀態是否正常,模塊連接正常後就可以發送設置命令了。第二步設置模塊爲station模式,也就是設置模塊爲從機。第三步連接路由器,發送wifi名稱和密碼,連接上wifi後,模塊就可以通過路由器連接到互聯網上了。最後連接原子雲,直接發送原子雲上的設備編號和密碼接可以了。這個原子雲的設備編號是在原子雲網站https://cloud.alientek.com/註冊的時候會默認分配一個設備編號,密碼自己在原子雲上可以設置。
要用單片機控制ESP8266模塊的關鍵就是要用代碼實現向ESP8266模塊發送指令,在野火提供的例子中已經實現了這個函數的封裝。
/*
* 函數名:ESP8266_Cmd
* 描述 :對WF-ESP8266模塊發送AT指令
* 輸入 :cmd,待發送的指令
* reply1,reply2,期待的響應,爲NULL表不需響應,兩者爲或邏輯關係
* waittime,等待響應的時間
* 返回 : 1,指令發送成功
* 0,指令發送失敗
* 調用 :被外部調用
*/
bool ESP8266_Cmd ( char * cmd, char * reply1, char * reply2, u32 waittime )
{
strEsp8266_Fram_Record .InfBit .FramLength = 0; //接收緩衝區數據長度清0
macESP8266_Usart ( "%s\r\n", cmd ); //向模塊發送命令
if ( ( reply1 == 0 ) && ( reply2 == 0 ) ) //不需要接收數據
return true;
Delay_ms ( waittime ); //延時 等待接收模塊返回的指令
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0'; //接收到的字符串末尾加入 結束符
macPC_Usart ( "%s", strEsp8266_Fram_Record .Data_RX_BUF ); //調試口打印接收到模塊的指令
if ( ( reply1 != 0 ) && ( reply2 != 0 ) )
return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) ||
( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) );
else if ( reply1 != 0 )
return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) );
else
return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) );
}
這個函數主要實現了向ESP82676模塊發送指令,並判斷模塊返回的指令是否正確。第一個參數cmd中存放要發送的指令,第二個參數存放模塊需要返回的字符串,第三個參數也存放模塊需要返回的字符串,最後一個參數用來設置向模塊發送完指令後需要等待的時間。因爲向模塊發送指令到模塊返回指令還有一段時間的延時。向模塊發送完指令後需要等待一段時間,再去判斷串口3接收到的數據是否正確。
首先將要發送的命令 通過macESP8266_Usart()函數發送出去。
macESP8266_Usart ( "%s\r\n", cmd );
這個函數其實就是通過串口3將字符串發送出去。通過串口3向ESP8266模塊發送指令後,延時一段時間等待串口接收數據。
Delay_ms ( waittime );
這行代碼實現延時,因爲要等待ESP8266模塊返回指令,所以代碼不能跳出去,必須在這裏死等。
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0'; //接收到的字符串末尾加入 結束符
macPC_Usart ( "%s", strEsp8266_Fram_Record .Data_RX_BUF ); //調試口打印接收到模塊的指令
延時一段時間後,就會在串口3的中斷函數中接收到ESP8266模塊返回的數據。在接收到的數據最後一位添加上字符串結束標誌,然後通過調試端口串口1將模塊返回的數據打印出來。
最後判斷模塊返回的字符串是否和參數中提供字符串一樣,如果一樣說明模塊設置正確,否則說明模塊設置失敗。
要設置不同的命令時,直接調用這個命令設置函數就行,比如第一步向模塊發送測試指令
void ESP8266_AT_Test ( void )
{
char count = 0;
Delay_ms ( 1000 );
while ( count < 10 )
{
if( ESP8266_Cmd ( "AT", "OK", NULL, 500 ) ) return; //如果接收到模塊返回的OK指令,就直接返回
ESP8266_Rst(); //否則復位模塊,重新發送AT測試指令
++ count;
}
}
向模塊發送“AT”字符串,如果模塊返回“OK”則退出,否則循環發送10次。
第二步設置模塊爲station模式
ESP8266_Net_Mode_Choose ( STA );
/*
* 函數名:ESP8266_Net_Mode_Choose
* 描述 :選擇WF-ESP8266模塊的工作模式
* 輸入 :enumMode,工作模式
* 返回 : 1,選擇成功
* 0,選擇失敗
* 調用 :被外部調用
*/
bool ESP8266_Net_Mode_Choose ( ENUM_Net_ModeTypeDef enumMode )
{
switch ( enumMode )
{
case STA:
return ESP8266_Cmd ( "AT+CWMODE=1", "OK", "no change", 2500 );
case AP:
return ESP8266_Cmd ( "AT+CWMODE=2", "OK", "no change", 2500 );
case STA_AP:
return ESP8266_Cmd ( "AT+CWMODE=3", "OK", "no change", 2500 );
default:
return false;
}
}
第三步連接路由器
ESP8266_JoinAP ( macUser_ESP8266_ApSsid, macUser_ESP8266_ApPwd );
/*
* 函數名:ESP8266_JoinAP
* 描述 :WF-ESP8266模塊連接外部WiFi
* 輸入 :pSSID,WiFi名稱字符串
* :pPassWord,WiFi密碼字符串
* 返回 : 1,連接成功
* 0,連接失敗
* 調用 :被外部調用
*/
bool ESP8266_JoinAP ( char * pSSID, char * pPassWord )
{
char cCmd [120];
sprintf ( cCmd, "AT+CWJAP=\"%s\",\"%s\"", pSSID, pPassWord );
return ESP8266_Cmd ( cCmd, "OK", NULL, 5000 );
}
第四步連接原子雲
ESP8266_ConnectYuanziyun ( yuanziyun_DeviceID, yuanziyun_DevicePassWord );
/*
* ESP8266_ConnectYuanziyun
* 描述 :WF-ESP8266模塊連接原子雲
* 輸入 :pSSID,原子雲上設備ID
* :pPassWord,原子雲上設備密碼
* 返回 : 1,連接成功
* 0,連接失敗
* 調用 :被外部調用
*/
bool ESP8266_ConnectYuanziyun ( char * pSSID, char * pPassWord )
{
char cCmd [120];
sprintf ( cCmd, "AT+ATKCLDSTA=\"%s\",\"%s\"", pSSID, pPassWord );
return ESP8266_Cmd ( cCmd, "OK", "CONNECTED", 5000 );
}
這樣通過不同的函數,將不同的命令通過命令發送函數發送到串口3上,也就是發送到ESP8266模塊上,從而實現ESP8266模塊連接到原子雲上。
當模塊連接到原子雲上之後,就可以通過單片機向雲端發送數據了。
void ESP8266_Station_Mode_yuanziyun_Test ( void )
{
uint8_t value1 = 0, value2 = 0;
uint8_t ucStatus;
char cStr [ 100 ] = { 0 };
uint8_t ucId;
char cStr1 [ 100 ] = { 0 };
char * pCh;
printf ( "\r\n正在配置 ESP8266 ......\r\n" );
//1、向模塊發送測試指令 AT
ESP8266_AT_Test ();
//2、設置模塊模式爲STA模式 AT+CWMODE=1
ESP8266_Net_Mode_Choose ( STA );
//3、設置要連接路由器的 ID 和密碼 AT+CWJAP=“enbiens”,”EB88858804”
while ( ! ESP8266_JoinAP ( macUser_ESP8266_ApSsid, macUser_ESP8266_ApPwd ) );
//4、連接原子雲 發送設備編號和密碼 AT+ATKCLDSTA="61212332528032817648","12345678"
while ( ! ESP8266_ConnectYuanziyun ( yuanziyun_DeviceID, yuanziyun_DevicePassWord ) );
printf ( "\r\n配置 ESP8266 完畢\r\n" );
while ( 1 )
{
value1++;
value2++;
sprintf ( cStr, "\r\nThe humidity: %d RH ,The temperature: %d C \r\n", value1, value2 );
printf ( "%s", cStr ); //打印數據
ESP8266_SendString ( ENABLE, cStr, 0, Single_ID_0 ); //通過透傳模式 發送信息到原子雲
Delay_ms ( 1500 );
if ( strEsp8266_Fram_Record .InfBit .FramFinishFlag )
{
USART_ITConfig ( macESP8266_USARTx, USART_IT_RXNE, DISABLE ); //禁用串口接收中斷
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0'; //接收到的數據末尾添加結束符
printf ( "\r\n%s\r\n", strEsp8266_Fram_Record .Data_RX_BUF ); //調試口打印接收到的數據
//strstr是C語言中的函數,作用是返回字符串中首次出現子串的地址。
// 若接收到的字符串中包含字符串 "led on" 就點亮LED燈
if ( ( pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "led on" ) ) != 0 )
{
LED1_ON;
}
// 若接收到的字符串中包含字符串 "led off" 就熄滅LED燈
else if ( ( pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "led off" ) ) != 0 )
{
LED1_OFF;
}
// 若接收到的字符串中包含字符串 "led toggle" 就反轉LED燈
else if ( ( pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "led toggle" ) ) != 0 )
{
LED1_TOGGLE;
}
strEsp8266_Fram_Record .InfBit .FramLength = 0;
strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0;
USART_ITConfig ( macESP8266_USARTx, USART_IT_RXNE, ENABLE ); //使能串口接收中斷
}
}
}
通過兩個變量value1和value2模擬單片機採集到的溫度和溼度值,向雲端發送數據。每發送一次數據後這兩個變量加1.當串口3中接收到雲端發送的數據後,通過調試口串口1將接收到的內容打印出來。並判斷雲端接收到數據的內容,如果是"led on"就點亮 LED燈,如果是"led off"就熄滅LED燈,如果是"led toggle"就翻轉LED的狀態。最後清除串口接收標誌。
通過上面的步驟就能實現單片機和手機客戶端的通信了,也可以通過手機直接控制單片機。如果將單片機連接上家電後,也可以通過手機直接控制家電。
完整工程連接下載地址: