// ESP32_akizuki_Camera // Board: ESP32 Dev Module(Compatible) // TFT Module: Aitendo M018C7735S(ST7735) // Camera Module: akizukidenshi ST-HL-08-V1(OV7670 w/o FIFO) // // Based on the original program on the web-site, bitluni's lab // http://bitluni.net/esp32-i2s-camera-ov7670/ // Modified and partially programmed by vabenecosi // http://vabenecosi.blog.fc2.com/(brog) // 2018/09/24 // // Programming Environment // Arduino IDE 1.8.5 // Board: ESP32 Dev Module // Partition Scheme: Initial // Flash Size: 4MB // Flash Frequency: 80MHz // Upload Speed: 115200 // // 'setAddrWindow()' functions well with following libraries. // (versions are very important) // Adafruit_GFX_Library version1.2.2 // Adafruit_ST7735_and_7739_Library verion1.1.0 // // Process executing time in the loop (measured value) // Capturing one frame by the camera: 60ms // Checking if server client exists: almost 0ms // Displaying one frame on the TFT LCD: 180ms // TotalF240ms (4.17fps) #include "OV7670.h" #include // Core graphics library version1.2.2 #include // Hardware-specific library version1.1.0 #include #include #include "BMP.h" const int SIOD = 21; //SDA const int SIOC = 22; //SCL const int VSYNC = 34; const int HREF = 35; const int XCLK = 32; const int PCLK = 33; const int D0 = 27; const int D1 = 17; const int D2 = 16; const int D3 = 15; const int D4 = 14; const int D5 = 13; const int D6 = 12; const int D7 = 4; const int TFT_DC = 2; const int TFT_CS = 5; //DIN <- MOSI 23 //CLK <- SCK 18 #define ssid "xxxxxxxxxxxxx" // Set your ssid #define password "xxxxxxxxxxxx" // Set your password Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, 0/*no reset*/); OV7670 *camera; WiFiServer server(80); unsigned char bmpHeader[BMP::headerSize]; void serve() { int i = 0; 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(); // Displays the site's title and a button to snap client.println(""); client.println(""); client.println(""); client.println(""); client.println(""); client.println(""); client.println("
"); client.println("ESP-WROOM-32
"); client.println("Wi-Fi Camera01

"); client.println("
"); client.println(""); client.println("
"); client.println(""); client.println(""); client.println(); break; } else { currentLine = ""; } } else if (c != '\r') { currentLine += c; } if (currentLine.endsWith("GET /?0=snap")) { Serial.println(); Serial.println("Sending BMP Image"); client.println("HTTP/1.1 200 OK"); client.println("Content-type:image/bmp"); client.println(); for (int i = 0; i < BMP::headerSize; i++) client.write(bmpHeader[i]); // BMP data have to be sent in reverse order, but I left the following description as it is. for (int i = 0; i < camera->xres * camera->yres * 2; i++) client.write(camera->frame[i]); } } } // close the connection: client.stop(); //Serial.println("Client Disconnected."); } } void setup() { Serial.begin(115200); tft.initR(INITR_BLACKTAB); tft.setRotation(1); // Valid only for the Aitendo M018C7735S tft.fillScreen(0); tft.setTextColor(ST7735_RED); tft.setCursor(0, 0); WiFi.begin(ssid, password);; Serial.println(); Serial.print("Connecting to "); Serial.print(ssid); tft.print("Connecting to "); tft.print(ssid); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); tft.print("."); } Serial.println(""); // Send the IP address Serial.println("WiFi connected."); Serial.print("IP address: "); Serial.println(WiFi.localIP()); tft.println(); // Displays the IP address on TFT LCD tft.println("WiFi connected."); tft.print("IP address: "); tft.println(WiFi.localIP()); camera = new OV7670(OV7670::Mode::QQVGA_RGB565, SIOD, SIOC, VSYNC, HREF, XCLK, PCLK, D0, D1, D2, D3, D4, D5, D6, D7); BMP::construct16BitHeader(bmpHeader, camera->xres, camera->yres); delay(1000); tft.fillScreen(0); server.begin(); } void displayY8(unsigned char * frame, int xres, int yres) { tft.setAddrWindow(0, 0, xres - 1, yres - 1); int i = 0; for (int y = 0; y < yres; y++) for (int x = 0; x < xres; x++) // Repeats horizontal scanning { i = y * xres + x; unsigned char c = frame[i]; unsigned short r = c >> 3; unsigned short g = c >> 2; unsigned short b = c >> 3; tft.pushColor(r << 11 | g << 5 | b); } } void displayRGB565(unsigned char * frame, int xres, int yres) { tft.setAddrWindow(0, 0, xres - 1, yres - 1); int i = 0; for (int y = 0; y < yres; y++) for (int x = 0; x < xres; x++) // Repeats horizontal scanning { i = (y * xres + x) << 1; tft.pushColor((frame[i] | (frame[i + 1] << 8))); } } void loop() { camera->oneFrame(); serve(); displayRGB565(camera->frame, camera->xres, camera->yres); }