2022年7月31日日曜日

WebSocketでOV7670-ESP32の画像表示

 ■OV7670

 OV7670 はVGA(640×480画素)サイズのイメージセンサです。内部構造はCMOSイメージセンサと信号処理用 DSPがワンチップになっています。マイコンへの映 像信号出力は、ディジタル8ビット・パラレルです。
製品仕様:
・イメージセンサー:OV7670 CMOS、VGA-640(V)×480(V)
・レンズ焦点距離:3.6mm(F2.5)
・光学サイズ:1/6型、画素セル:3.6um x 3.6um
・フィールド角:25°(対角)
・小さいサイズ:3.5cm x 3.5cm
・低動作電圧:2.5V~3.0VDC
・低動作電流:60mw(15fps VGA YUV format)
・スリープモード<20μA
・保存温度:-30℃~70℃
・動作温度:0℃~50℃
・感度:1.3V/(Lux-sec)
・インターフェース:標準SCCB(Serial Camera Control Bus)インターフェース(I2C互換)
・データ出力フォーマット:Raw RGB、RGB(GRB4:2:2)、RGB(565/555/444)、YUV(4:2:2)、YCbCr(4:2:2)
・データ出力解像度:VGA、CIF、CIF~40x30の任意解像度
・サンプリングタイプ:Vario Pixel
・接続コネクタ:2.54mmピッチ(2列)18ピン、ピンヘッダ
■ESP32接続
 下記ように、OV7670のピンとESP32ピンを接続します。
 ※データ転送スピードを考えると、短いジャンプワイヤーが勧め
 ※SDAとSCLは1KΩの抵抗を使用でも可
OV7670ESP32
D0IO36
D1IO39
D2IO34
D3IO35
D4IO32
D5IO33
D6IO25
D7IO26
MCLKIO15
PCLKIO14
HREFIO23
VSYNCIO13
SDAIO21 (1kΩ Pull Up)
SCLIO22 (1KΩ Pull Up)
RST3.3V
PWDNGND
■Web送信
 Web送信はWebSocketを使いました。
 下記ライブラリが必要です。
■部品一覧:
・ESP-WROOM-32開発ボード
・OV7670
・USBケーブル
・ジャンプワイヤー
・1KΩ抵抗*2
・ブレッドボード
■プログラム:
 単純なESP32、OV7670と接続ため(FIFOなどがない)、インターネットのいろいろなサンプルを試した結果で、
は使えます。
 
 下記箇所をちょっと修正しました。
 ①13行目~14行目までのWiFi接続情報
 ②23行目~33行目までのピン情報
 ③APモードは不要のため、削除
 ④DBABuffer.hはコンパイルエラーあるため、「#include <stdlib.h>」を追加

#include "OV7670.h"

#include <WebSockets.h>
#include <WebSocketsClient.h>
#include <WebSocketsServer.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <WiFiClient.h>
#include "canvas_htm.h"

const char *ssid_AP_1 = "XXXXXX";
const char *pwd_AP_1  = "XXXXXXX";

const int SIOD = 21; //SDA
const int SIOC = 22; //SCL

const int VSYNC = 13;
const int HREF = 23;

const int XCLK = 15;
const int PCLK = 14;

const int D0 = 36;
const int D1 = 39;
const int D2 = 34;
const int D3 = 35;
const int D4 = 32;
const int D5 = 33;
const int D6 = 25;
const int D7 = 26;

const int TFT_DC = 2;
const int TFT_CS = 5;

OV7670 *camera;

WiFiMulti wifiMulti;
WiFiServer server(80);

unsigned char pix = 0;

unsigned char start_flag = 0xAA;
unsigned char end_flag = 0xFF;
unsigned char ip_flag = 0x11;

WebSocketsServer webSocket(81);    // create a websocket server on port 81

void startWebSocket() { // Start a WebSocket server
  webSocket.begin();                          // start the websocket server
  webSocket.onEvent(webSocketEvent);          // if there's an incomming websocket message, go to function 'webSocketEvent'
  Serial.println("WebSocket server started.");
}

void startWebServer()
{
   server.begin();
   Serial.println("Http web server started.");
}
void serve() {
  WiFiClient client = server.available();
  if (client) 
  {
    //Serial.println("New Client.");
    String currentLine = "";
    while (client.connected()) 
    {
      if (client.available()) 
      {
        char c = client.read();
        //Serial.write(c);
        if (c == '\n') 
        {
          if (currentLine.length() == 0) 
          {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();
            client.print(canvas_htm);
            client.println();
            break;
          } 
          else 
          {
            currentLine = "";
          }
        } 
        else if (c != '\r') 
        {
          currentLine += c;
        }
        
      }
    }
    // close the connection:
    client.stop();

  }  
}

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t payloadlength) { // When a WebSocket message is received
 
  int blk_count = 0;

  char canvas_VGA[] = "canvas-VGA";
  char canvas_Q_VGA[] = "canvas-Q-VGA";
  char canvas_QQ_VGA[] = "canvas-QQ-VGA";
  char canvas_QQQ_VGA[] = "canvas-QQQ-VGA";
  char ipaddr[26] ;
  IPAddress localip;
  
  switch (type) {
    case WStype_DISCONNECTED:             // if the websocket is disconnected
      Serial.printf("[%u] Disconnected!\n", num);
      break;
    case WStype_CONNECTED: {              // if a new websocket connection is established
        IPAddress ip = webSocket.remoteIP(num);
        Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
           webSocket.sendBIN(0, &ip_flag, 1);
           localip = WiFi.localIP();
           sprintf(ipaddr, "%d.%d.%d.%d", localip[0], localip[1], localip[2], localip[3]);
           webSocket.sendTXT(0, (const char *)ipaddr);
           
      }
      break;
    case WStype_TEXT:                     // if new text data is received
      if (payloadlength == sizeof(canvas_QQQ_VGA)-1) {
        if (memcmp(canvas_QQQ_VGA, payload, payloadlength) == 0) {
              Serial.printf("canvas_QQQ_VGA");
              webSocket.sendBIN(0, &end_flag, 1);
              camera = new OV7670(OV7670::Mode::QQQVGA_RGB565, SIOD, SIOC, VSYNC, HREF, XCLK, PCLK, D0, D1, D2, D3, D4, D5, D6, D7);
        }
      } else if (payloadlength == sizeof(canvas_QQ_VGA)-1) {
        if (memcmp(canvas_QQ_VGA, payload, payloadlength) == 0) {
              Serial.printf("canvas_QQ_VGA");
              webSocket.sendBIN(0, &end_flag, 1);
              camera = new OV7670(OV7670::Mode::QQVGA_RGB565, SIOD, SIOC, VSYNC, HREF, XCLK, PCLK, D0, D1, D2, D3, D4, D5, D6, D7);
        }
      } else if (payloadlength == sizeof(canvas_Q_VGA)-1) {
        if (memcmp(canvas_Q_VGA, payload, payloadlength) == 0) {
              Serial.printf("canvas_Q_VGA");
              webSocket.sendBIN(0, &end_flag, 1);
              camera = new OV7670(OV7670::Mode::QVGA_RGB565, SIOD, SIOC, VSYNC, HREF, XCLK, PCLK, D0, D1, D2, D3, D4, D5, D6, D7);
        }
      } else if (payloadlength == sizeof(canvas_VGA)-1) {
        if (memcmp(canvas_VGA, payload, payloadlength) == 0) {
              Serial.printf("canvas_VGA");
              webSocket.sendBIN(0, &end_flag, 1);
              camera = new OV7670(OV7670::Mode::VGA_RGB565, SIOD, SIOC, VSYNC, HREF, XCLK, PCLK, D0, D1, D2, D3, D4, D5, D6, D7);
        }
      } 

      
      blk_count = camera->yres/I2SCamera::blockSlice;//30, 60, 120
      for (int i=0; i<blk_count; i++) {

          if (i == 0) {
              camera->startBlock = 1;
              camera->endBlock = I2SCamera::blockSlice;
              webSocket.sendBIN(0, &start_flag, 1);
          }

          if (i == blk_count-1) {
              webSocket.sendBIN(0, &end_flag, 1);
          }
        
          camera->oneFrame();
          webSocket.sendBIN(0, camera->frame, camera->xres * I2SCamera::blockSlice * 2);
          camera->startBlock += I2SCamera::blockSlice;
          camera->endBlock   += I2SCamera::blockSlice;
      }
      
      break;
    case WStype_ERROR:                     // if new text data is received
      Serial.printf("Error \n");
    default:
      Serial.printf("WStype %x not handled \n", type);

  }
}

void initWifiMulti()
{

    wifiMulti.addAP(ssid_AP_1, pwd_AP_1);

    Serial.println("Connecting Wifi...");
    while(wifiMulti.run() != WL_CONNECTED) {
       delay(5000);        
       Serial.print(".");
    }
    
    Serial.print("\n");
    Serial.print("WiFi connected : ");
    Serial.print("IP address : ");
    Serial.println(WiFi.localIP());
}

void setup() {
  Serial.begin(115200);
  initWifiMulti();
  startWebSocket();
  startWebServer();
}

void loop()
{
  webSocket.loop();
  serve();
}
■結果
ブラウザーを開いて、URLを入力し
配線イメージ
写真工場 :)

0 件のコメント:

コメントを投稿

シンプルロボットカーセットの使い方

■ マイコン :ESP3266-CH340  シンプルの案として、マイコンは安いESP8266-CH340開発ボードを選びました。該当マイコンもWIFI機能があります。  ドライバーダウンロード場所:    https://sparks.gogo.co.nz/ch340.html...