esp8266 TCP Client STA模式
因為嵌入式課程做的東西想用esp8266 將開發板上使用攝像頭獲取的影象傳送到電腦。所以參考正點原子上的示例學習做了一下。雖然有原始碼可以參考,不過在根據自己的需要修改的過程中還是遇到不少問題的。
esp8266的初始化過程為:
1. 首先需要初始化串列埠的波特率。在初次嘗試傳輸影象的時候,由於傳輸的速度太慢(1s僅能傳送2000位元組),我以為是串列埠設定的波特率問題,所以用了一個USB轉TTL 使用 AT+UART指令修改串列埠的波特率為921600(程式碼中以及串列埠除錯助手都要調整為對應的值)。不過再次嘗試並沒有顯著的提高傳輸速度(這是因為程式碼中其他地方的原因,下面會解釋)。
2. 接著用一個迴圈傳送AT 指令,是否可以連線模組。在測試傳送資料的時候,由於我是移值的UCOSIII 系統,OV7670 將圖象資料儲存在SRAM 中,此時傳送資料的任務等待,所以連續傳送兩次資料之間有時間間隔。在這個間隔中有時候會出現模組連線不上的情況(就是傳送AT 指令無法連線到模組)。之前我以為重新把連線的過程執行一遍就沒有問題了,但是依然沒有解決這個問題。後來改為如果連線中斷不重新連線,而是直接退出當前傳送。一般情況下,在中斷10s後會重新識別到模組的。
3. 測試之後,傳送ATE0 關閉回顯。該步驟感覺可選,不過沒有測試。
4. 使用AT+CWMODE=1 設定模式為STA。
5. 在設定模式之後使用AT+RST 重啟模組,延時4s等待重啟完成
6. 使用AT+CWJAP 連線WIFI ,需要用到WIFI 的SSID 與密碼,在該步驟後,開發板將會獲得一個IP 地址
7. 使用AT+CIPMUX =0指令設定為單連線,=1 為多連線
8. 使用AT+CIPSTART 指令啟動TCP 連線,引數為TCP 、目標主機的IP 、目標主機的埠
9. 使用AT+CIPMODE=1 退出透傳模式。如果要傳送指令,需要退出透傳模式,在傳送資料的時候,需要開啟透傳
10.之後就可以使用AT+CIPSEND 指令傳輸資料了
在以上步驟中,需要經常使用atk_8266_at_response(1) 檢查接收到的資料。該函式是例程中封裝好的函式,如果直接操作到暫存器的話,可以參考如下的步驟:
if(USART3_RX_STA&0X8000) //接收到一次資料了
{
USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//新增結束符
printf("%s",USART3_RX_BUF); //傳送到串列埠
if(mode)USART3_RX_STA=0;
}
在傳輸的過程中,可以使用如下的步驟檢查模組的連線狀態:
u8 atk_8266_consta_check(void)
{
u8 *p;
u8 res;
if(atk_8266_quit_trans())return 0; //退出透傳
atk_8266_send_cmd("AT+CIPSTATUS",":",50); //傳送AT+CIPSTATUS指令,查詢連線狀態
p=atk_8266_check_cmd("+CIPSTATUS:");
res=*p; //得到連線狀態
return res;
}
下面是傳送資料任務部分的程式碼,傳送資料的部分,每次傳送512個位元組(因為傳送的緩衝限制為不超過600個位元組)。傳送位元組數大約為10KB,大約用時1-2s。相比較於之前的程式碼,主要是修改的傳送資料的迴圈。之前在迴圈中,每一次傳送都使用quit_trans 於AT+CIPSEND 指令。在將這兩步刪除之後,傳送速度提高很快。具體速度最快可以達到多少還沒有測試。
檔案 send_msg.c
#include "send_img_task.h"
#include <stdio.h>
#include "camera_main.h"
#include "usart.h"
/*******************
用於向電腦傳送資料
*********************/
void send_img()
{
uart_init(921600); //串列埠初始化為 921600
printf("wifi 任務\r\n");
while(!hasimg)//等待srma 中有影象,同時也用於在camera_main 中的初始化函式完成之後再執行當前接下來的任務
{
printf("in wifi task hasimg=%d hassend = %d\r\n",hasimg,hassend);
}
printf("傳送影象幀的任務開始\r\n");
printf("準備與電腦建立連線..........\r\n");
connect_to_computer(); //首先建立連線
while(1)
{
if(!hasimg)
{
printf("等待SRAM 中的資料\r\n");
delay_ms(30);
if(atk_8266_consta_check() == '+')
printf("連線正常....\r\n");
else
printf("連線中斷......\r\n");
atk_8266_at_response(1);
continue;
}
printf("準備傳送一幀影象\r\n");
//wifi_send_data("DA",2);
wifi_send_data((char *)imgarray,4800*2); //76800 為總的畫素點數,每個16位,傳送80*60
printf("一幀影象傳送完畢\r\n");
if(atk_8266_consta_check() == '+')
printf("連線正常\r\n");
else
printf("連線中斷\r\n");
atk_8266_at_response(1);
delay_ms(30);
hassend=1;
hasimg=0;
}
}
檔案 wifi_conn.c
#include "wifi_conn.h"
#include "usart.h"
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include <string.h>
#include "os.h"
/***********************
連線電腦的方法
**************************/
void connect_to_computer()
{
char *p =NULL;
printf("開始初始化WIFI 模組\r\n");
while(atk_8266_send_cmd("AT","OK",20)) //檢查WIFI 模組是否線上
{
atk_8266_quit_trans(); //退出透傳
atk_8266_send_cmd("AT+CIPMODE=0","OK",200); //關閉透傳模式
printf("嘗試連線到模組\r\n");
delay_ms(800);
}
printf("模組連線成功\r\n");
while(atk_8266_send_cmd("ATE0","OK",20)); //關閉回顯
printf("開始設定WIFI STA 模式\r\n");
delay_ms(10);
atk_8266_at_response(1); //檢查模組傳送的資料
atk_8266_send_cmd("AT+CWMODE=1","OK",50); //設定WIFI STA 模式
atk_8266_send_cmd("AT+RST","OK",20);
delay_ms(4000);
p = (char *)malloc(sizeof(char)*128);
sprintf(p,"AT+CWJAP=\"%s\",\"%s\"",wifista_ssid,wifista_password);
atk_8266_at_response(1);
while(atk_8266_send_cmd((u8*)p,"WIFI GOT IP",300)); //連線目標路由
atk_8266_at_response(1);
printf("連線到電腦wifi \r\n");
delay_ms(100);
atk_8266_send_cmd("AT+CIPMUX=0","OK",40); //單連線
printf("設定連線的IP 地址\r\n");
sprintf(p,"AT+CIPSTART=\"TCP\",\"192.168.137.1\",8086");
while(atk_8266_send_cmd((u8*)p,"OK",200))
{
printf("TCP 連線失敗!\r\n");
}
printf("TCP 連線成功!\r\n");
atk_8266_send_cmd("AT+CIPMODE=1","OK",200);
//atk_8266_at_response(1);
USART3_RX_STA=0;
free(p);
}
/****************************
使用WIFI 傳送資料
由於影象畫素每個畫素點是16位的資料,所以每次傳送一個16位的資料
len : 以位元組為單位計算的長度
使用8266傳送緩衝的大小為600個位元組,在該函式中採用每次傳送512個位元組
*****************************/
void wifi_send_data(char *data,int len)
{
char *p = data;
p = (char*)malloc(sizeof(char)*128);
if(atk_8266_consta_check() == '+')
{
printf("連線正常\r\n");
}
else
{
printf("連線中斷\r\n");
return;
}
atk_8266_at_response(1);
delay_ms(10);
free(p);
p=data;
//首先發送起始資訊
atk_8266_quit_trans();
atk_8266_send_cmd("AT+CIPSEND","OK",20);
u3_printf("start of msg");
atk_8266_at_response(1);
delay_ms(30);
while(len > 0)
{
if(len >= 512)
{
len -= 512;
u3_printf("%512.512s",p);
p+=512;
}
else
{
u3_printf("%s",p);
len=0;
}
atk_8266_at_response(1);
delay_ms(10);
}
//傳送標識一幀影象結束的訊息
atk_8266_quit_trans();
atk_8266_send_cmd("AT+CIPSEND","OK",20);
u3_printf("end of msg");
atk_8266_at_response(1);
delay_ms(10);
atk_8266_at_response(1);
printf("傳送結束==========================================\r\n");
// char *p = data;
// char *send_content = (char*)malloc(sizeof(char)*2);
// while(len > 0)
// {
// atk_8266_quit_trans();
// atk_8266_send_cmd("AT+CIPSEND","OK",20);
// sprintf(send_content,"%02x%02x",*p,*(p+1));
// u3_printf(send_content); //傳送資料
// p +=2;
// len -= 2;
// atk_8266_at_response(1);
// }
// free(send_content);
}