最简单DIY基于ESP32CAM的物联网相机系统⑤(用1306OLED实现WIFI黑白屏照相机)

第一篇:最简单DIY基于ESP32CAM的物联网相机系统①(用网页实现拍照图传)
第二篇:最简单DIY基于ESP32CAM的物联网相机系统②(在JAVAWEB服务器实现图片查看器)
第三篇:最简单DIY基于ESP32CAM的物联网相机系统③(在JSP服务器图传相片给所有客户端欣赏)
第四篇:最简单DIY基于ESP32CAM的物联网相机系统④(用调试串口助手实现串口图传)
第五篇(上):最简单DIY基于ESP32CAM的物联网相机系统⑤(用1306OLED实现WIFI黑白屏照相机)



前言

    daodanjishui物联网核心原创技术之最简单DIY基于ESP32CAM的物联网相机系统⑤(用1306OLED实现WIFI黑白屏照相机)。
    该专栏的第四篇博文:最简单DIY基于ESP32CAM的物联网相机系统④(用调试串口助手实现串口图传) 实现的是用ESP32CAM拍摄照片传输到电脑串口调试助手,在串口调试助手里面拷贝图片信息出来放到图片查看器可以看到拍摄的图片,其实这样很麻烦。
    在这篇博文,我将会带大家用最便宜的0.96寸1306OLED黑白显示屏显示ESP32CAM单片机拍摄的图片,就像真正的相机一样拍完照片之后可以直接在相机的屏幕上查看拍摄照片的效果。显示屏是直接通过I2C总线连接在ESP32CAM单片机上的。
优酷视频演示地址:https://v.youku.com/v_show/id_XNTE1Mzk2MTUwOA==.html

最简单DIY基于ESP32CAM的物联网相机系统⑤(用1306OLED实现WIFI黑白屏照相机)

显示屏外形:
在这里插入图片描述

该设计的全家福如下所示:
在这里插入图片描述
另外我还加入了STA模式,相机可以连接路由器,在局域网的所有用户都可以根据OLED显示的局域网IP=192.168.252.10,访问相机的嵌入式主页,如下图所示,控制拍照的依旧是网页:
在这里插入图片描述


一、最简单DIY基于ESP32CAM的物联网相机系统⑤(用1306OLED实现WIFI黑白屏照相机)是什么?

    用0.96寸的OLED显示屏来显示ESP32CAM相机拍摄的黑白照片。


二、实现需求

1.先打开官方1306显示屏的代码

    在Arduino IDE有很多例子供开发者学习的。
(1)第一个相关的例子就是串口通信的例子了:
源码路径:
在这里插入图片描述

/**************************************************************************
 This is an example for our Monochrome OLEDs based on SSD1306 drivers

 Pick one up today in the adafruit shop!
 ------> http://www.adafruit.com/category/63_98

 This example is for a 128x64 pixel display using I2C to communicate
 3 pins are required to interface (two I2C and one reset).

 Adafruit invests time and resources providing this open
 source code, please support Adafruit and open-source
 hardware by purchasing products from Adafruit!

 Written by Limor Fried/Ladyada for Adafruit Industries,
 with contributions from the open source community.
 BSD license, check license.txt for more information
 All text above, and the splash screen below must be
 included in any redistribution.
 **************************************************************************/

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define NUMFLAKES     10 // Number of snowflakes in the animation example

#define LOGO_HEIGHT   16
#define LOGO_WIDTH    16
static const unsigned char PROGMEM logo_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };

void setup() {
  Serial.begin(9600);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  // Show initial display buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  display.display();
  delay(2000); // Pause for 2 seconds

  // Clear the buffer
  display.clearDisplay();

  // Draw a single pixel in white
  display.drawPixel(10, 10, SSD1306_WHITE);

  // Show the display buffer on the screen. You MUST call display() after
  // drawing commands to make them visible on screen!
  display.display();
  delay(2000);
  // display.display() is NOT necessary after every single drawing command,
  // unless that's what you want...rather, you can batch up a bunch of
  // drawing operations and then update the screen all at once by calling
  // display.display(). These examples demonstrate both approaches...

  testdrawline();      // Draw many lines

  testdrawrect();      // Draw rectangles (outlines)

  testfillrect();      // Draw rectangles (filled)

  testdrawcircle();    // Draw circles (outlines)

  testfillcircle();    // Draw circles (filled)

  testdrawroundrect(); // Draw rounded rectangles (outlines)

  testfillroundrect(); // Draw rounded rectangles (filled)

  testdrawtriangle();  // Draw triangles (outlines)

  testfilltriangle();  // Draw triangles (filled)

  testdrawchar();      // Draw characters of the default font

  testdrawstyles();    // Draw 'stylized' characters

  testscrolltext();    // Draw scrolling text

  testdrawbitmap();    // Draw a small bitmap image

  // Invert and restore display, pausing in-between
  display.invertDisplay(true);
  delay(1000);
  display.invertDisplay(false);
  delay(1000);

  testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps
}

void loop() {
}

void testdrawline() {
  int16_t i;

  display.clearDisplay(); // Clear display buffer

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, 0, i, display.height()-1, SSD1306_WHITE);
    display.display(); // Update screen with each newly-drawn line
    delay(1);
  }
  for(i=0; i<display.height(); i+=4) {
    display.drawLine(0, 0, display.width()-1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, display.height()-1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(0, display.height()-1, display.width()-1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=display.width()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.height(); i+=4) {
    display.drawLine(display.width()-1, 0, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=0; i<display.width(); i+=4) {
    display.drawLine(display.width()-1, 0, i, display.height()-1, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000); // Pause for 2 seconds
}

void testdrawrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=2) {
    display.drawRect(i, i, display.width()-2*i, display.height()-2*i, SSD1306_WHITE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testfillrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=3) {
    // The INVERSE color is used so rectangles alternate white/black
    display.fillRect(i, i, display.width()-i*2, display.height()-i*2, SSD1306_INVERSE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testdrawcircle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=2) {
    display.drawCircle(display.width()/2, display.height()/2, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillcircle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=3) {
    // The INVERSE color is used so circles alternate white/black
    display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE);
    display.display(); // Update screen with each newly-drawn circle
    delay(1);
  }

  delay(2000);
}

void testdrawroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    // The INVERSE color is used so round-rects alternate white/black
    display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawtriangle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=5) {
    display.drawTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfilltriangle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=5) {
    // The INVERSE color is used so triangles alternate white/black
    display.fillTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawchar(void) {
  display.clearDisplay();

  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(0, 0);     // Start at top-left corner
  display.cp437(true);         // Use full 256 char 'Code Page 437' font

  // Not all the characters will fit on the display. This is normal.
  // Library will draw what it can and the rest will be clipped.
  for(int16_t i=0; i<256; i++) {
    if(i == '\n') display.write(' ');
    else          display.write(i);
  }

  display.display();
  delay(2000);
}

void testdrawstyles(void) {
  display.clearDisplay();

  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,0);             // Start at top-left corner
  display.println(F("Hello, world!"));

  display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
  display.println(3.141592);

  display.setTextSize(2);             // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.print(F("0x")); display.println(0xDEADBEEF, HEX);

  display.display();
  delay(2000);
}

void testscrolltext(void) {
  display.clearDisplay();

  display.setTextSize(2); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 0);
  display.println(F("scroll"));
  display.display();      // Show initial text
  delay(100);

  // Scroll in various directions, pausing in-between:
  display.startscrollright(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrollleft(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrolldiagright(0x00, 0x07);
  delay(2000);
  display.startscrolldiagleft(0x00, 0x07);
  delay(2000);
  display.stopscroll();
  delay(1000);
}

void testdrawbitmap(void) {
  display.clearDisplay();

  display.drawBitmap(
    (display.width()  - LOGO_WIDTH ) / 2,
    (display.height() - LOGO_HEIGHT) / 2,
    logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
  display.display();
  delay(1000);
}

#define XPOS   0 // Indexes into the 'icons' array in function below
#define YPOS   1
#define DELTAY 2

void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  int8_t f, icons[NUMFLAKES][3];

  // Initialize 'snowflake' positions
  for(f=0; f< NUMFLAKES; f++) {
    icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
    icons[f][YPOS]   = -LOGO_HEIGHT;
    icons[f][DELTAY] = random(1, 6);
    Serial.print(F("x: "));
    Serial.print(icons[f][XPOS], DEC);
    Serial.print(F(" y: "));
    Serial.print(icons[f][YPOS], DEC);
    Serial.print(F(" dy: "));
    Serial.println(icons[f][DELTAY], DEC);
  }

  for(;;) { // Loop forever...
    display.clearDisplay(); // Clear the display buffer

    // Draw each snowflake:
    for(f=0; f< NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE);
    }

    display.display(); // Show the display buffer on the screen
    delay(200);        // Pause for 1/10 second

    // Then update coordinates of each flake...
    for(f=0; f< NUMFLAKES; f++) {
      icons[f][YPOS] += icons[f][DELTAY];
      // If snowflake is off the bottom of the screen...
      if (icons[f][YPOS] >= display.height()) {
        // Reinitialize to a random position, just off the top
        icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
        icons[f][YPOS]   = -LOGO_HEIGHT;
        icons[f][DELTAY] = random(1, 6);
      }
    }
  }
}

值得注意的是需要安装一个“水果库”,#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h> 否则有可能出错。


2.再打开官方ESP32CAM照相机程序

源码路径是(只要读者正确安装了ESP32开发环境,这个源码可以在Arduino里面按照下面截图的方式打开的):
在这里插入图片描述

#include "esp_camera.h"
#include <WiFi.h>

//
// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
//            Ensure ESP32 Wrover Module or other board with PSRAM is selected
//            Partial images will be transmitted if image exceeds buffer size
//

// Select camera model
#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
//#define CAMERA_MODEL_ESP_EYE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE	// Has PSRAM
//#define CAMERA_MODEL_AI_THINKER // Has PSRAM
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM

#include "camera_pins.h"

const char* ssid = "*********";
const char* password = "*********";

void startCameraServer();

void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println();

  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  
  // if PSRAM IC present, init with UXGA resolution and higher JPEG quality
  //                      for larger pre-allocated frame buffer.
  if(psramFound()){
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

#if defined(CAMERA_MODEL_ESP_EYE)
  pinMode(13, INPUT_PULLUP);
  pinMode(14, INPUT_PULLUP);
#endif

  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  sensor_t * s = esp_camera_sensor_get();
  // initial sensors are flipped vertically and colors are a bit saturated
  if (s->id.PID == OV3660_PID) {
    s->set_vflip(s, 1); // flip it back
    s->set_brightness(s, 1); // up the brightness just a bit
    s->set_saturation(s, -2); // lower the saturation
  }
  // drop down frame size for higher initial frame rate
  s->set_framesize(s, FRAMESIZE_QVGA);

#if defined(CAMERA_MODEL_M5STACK_WIDE)
  s->set_vflip(s, 1);
  s->set_hmirror(s, 1);
#endif

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  startCameraServer();

  Serial.print("Camera Ready! Use 'http://");
  Serial.print(WiFi.localIP());
  Serial.println("' to connect");
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(10000);
}

3.修改上面1和2的官方源码变成自己的源码

(1)编写图像处理代码(注释相当详细):

  void my_camera_show(void)
{
  
  camera_fb_t *fb = esp_camera_fb_get();
  int i = 0;
  for(y = 0; y < SCREEN_HEIGHT; y++)
  {
    for(x = 0;x < SCREEN_WIDTH; x++)
    {
      oldpixel = fb->buf[i]; //保持原始的灰度值
      newpixel = (255*(oldpixel >> 7)); //门槛值128,只留下最后高位的第八位二进制数据,右移7位变成0或者1,再与255相乘,结果就是0或者255
      fb->buf[i] = newpixel; //缓冲区现在是单通道,0或255
      // floyd-steignburg抖动算法
      quanterror = oldpixel - newpixel; //像素之间的误差
      //将此错误分发给相邻像素:
      //右
      if(x < SCREEN_WIDTH-1)//边界检查...
      {
        fb->buf[(x + 1)+(y * SCREEN_WIDTH)] += ((quanterror * 7)>> 4);
      }
      // 左下
      if((x > 1) && (y < SCREEN_HEIGHT-1))//边界检查...
      {
        fb->buf [(x-1)+((y + 1)* SCREEN_WIDTH)] == ((quanterror * 3)>> 4); 
      }
      //下
      if(y < 63)//边界检查...
      {
        fb->buf [(x)+((y + 1)* SCREEN_WIDTH)] == ((quanterror * 5)>> 4);
      }
      // 右下
      if((x < SCREEN_WIDTH-1) && (y < SCREEN_HEIGHT-1))//边界检查...
      {
        fb->buf [(x + 1) + ((y + 1)* SCREEN_WIDTH)] == (quanterror >> 4);
      }
      // 画这个像素
      switch(fb->buf[i]%2)
      {
      case 0:
        //display.setColor(BLACK);
       display.drawPixel(x,y,BLACK);
        break;
      case 1:
        //display.setColor(WHITE);
       // draw a single pixel
        display.drawPixel(x,y,WHITE);
        break;
      case 2:
        //display.setColor(INVERSE);
        
        // draw a single pixel
        display.drawPixel(x,y,INVERSE);
        break;
      }
      //display.setPixel(x, y);  
      i++;
    }
  }
  display.display();
  esp_camera_fb_return(fb);
}

(2)结合图像采集和图像处理完成最终的OLED显示的设计
需要完整代码的读者请到最后面的链接下载工程源码。这里省去几千字的代码······


三、运行与调试

(1)按照下图接线:
在这里插入图片描述

(1.1)配置好路由器的账号和密码烧录代码开机,查看OLED显示屏的IP地址:在这里插入图片描述

(2)打开浏览器输入IP地址进入智能照相机主页(相机和浏览器都要在一个局域网):
在这里插入图片描述

(3)点击send之后就会触发ESP32CAM在拍照,OLED 马上显示拍摄的黑白照片。
在这里插入图片描述

调试到此结束,根据结果可以满足博文提出的要求。


总结

总结:读者可以在这里学会了AJAX技术,可以在不刷新网页的前提下不断点击send按钮拍照,并且网页会显示一个变化的随机数nocathe=1620924773578 提示用户拍照成功,这个反馈不知道有多少个技术开发者想写都难写出来的,因为这个技术要熟悉JS技术才能使用得淋漓尽致了,还有就是可以学到嵌入式网页设计及嵌入式服务器的设计及嵌入式服务器如何接受get请求和用异步响应get请求,服务器根据请求验证提交表单的账号和密码,并没有使用到数据库又可以实现账号密码认证,多少硬件工程师都想不出来是这样写的,根据密码认证的结果解析指令控制照相机硬件摄像头拍照,总的来说不简单的,网上开源的老外代码没有我的那么详细和简洁的,相信daodanjishui品牌的力量,后期我可能会去编写一本关于ESP32CAM的技术书籍,玩技术又有冒险的尝试和收割成果的喜悦,大概就是所谓的技术真爱吧!这是我以前的项目中没有出现过的知识点(后期还会开源在ESP32CAM本机加载JS库的开源代码实现图像处理,敬请期待······)包括串口图传,WIFI图传,C#图传,JAVA图传,安卓图传,JSP图传,MFC图传······精彩值得期待。

代码工程下载链接:https://gf.bilibili.com/item/detail/1107789114
点我直接跳转

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
openwrt是一个Linux系统简单的说他是一个路由器系统,但很多人用来做机器人系统,可想而知,他基本能干的事真他娘的非常多哦。智能路由器、家居网关、Wifi音响、wifi开关、wifi硬盘、wifi摄像头、wifi小车、wifi机器人等等 按功能如:搭建VPN、小型服务器、安装BitTorrent客户端、SSH隧道 从这期的《openwrt摄像头》,让大家最简单入门openwrt,DIY家居摄像头,让在公司也可以时时了解家里的活动,猫猫狗狗人人物物! 这是我们用3D打印机把外壳做出来了,是不是离产品又接近一步了? 如果大家想学如何做用软件简单做3D模型(像我们做这样的盒子外壳等)那就大量向我们JJYY吧! 所需要到的配件清单: 本帖隐藏的内容1、3D打印盒子。 2、AR9331板(wifi主板)。 3、摄像头。 淘宝党:https://item.taobao.com/item.htm?id=41706174433 原理非常简单,用AR9331板刷入openwrt固件,然后使用一个笔记本摄像头接到usb,然后启动摄像头命令就可以了! 如果需要在公司访问,就映射端口就可以了! 虽然这个功能非常简单,但你有了这个openwrt,以后我们会出更多教程都是关于openwrt制作智能产品,那么你学会openwrt又牛b了一吧! 第一部份:配置wifi板(设置ap、sta之类的)。 前往第一篇:WIFI作品DIY教程01-《wifi开发板》介绍和联网等配置教程 网址链接:https://www.znck007.com/forum.php?mod=viewthread&tid=21570 第二部份:配置摄像头。 一、下载putty软件(电脑连接openwrt系统) https://pan.baidu.com/s/1pJluOwN 二、使用putty安装摄像头驱动 连接192.168.1.1 输入root,和密码 登陆成功! opkg update 更新软件 opkg install mjpg-streamer 安装摄像头驱动(如果已经安装了,就可以不用安装!) mjpg_streamer -i "input_uvc.so /dev/video0 -r 640x480 " -o "output_http.so -p 8080 -w /www/webcam" 启动摄像头,如上图表示成功!有时usb供电不足,或摄像头坏了都是启动不成功的! 第三部份:电脑或手机监控摄像头。 一、电脑摄像头。 1、使用火狐浏览器(ie不行,苹果、谷歌都可以) https://www.firefox.com.cn/ 2、浏览器打开 https://192.168.1.1:8080 二、手机摄像头 1、手机首先连接openwrt的wifi,如果已经设置了dhcp,那就会自动获得IP了! 2、苹果手机直接打开 https://192.168.1.1:8080(像电脑一样,可以直接连接摄像头) 2、安卓手机下载app连接吧 APP下载:https://pan.baidu.com/s/1gdtcDTT APP源码下载:https://pan.baidu.com/s/1pJOA0iB ok,那么摄像头就已经正常了! 第四部份:设置路由器端口映射(在外网<公司等>也可以监控家里的情况)。 设置路由器端口映射比较麻烦,所以大家一定得慢慢来! 原理:家里路由器-》映射到openwrt-》再映射到192.168.1.1的8080端口上! 一、设置openwrt静态IP,只能这样才能指定映射! 选择 网络-》接口。 点击修改 选择静态地址,然后切换协议! 这里非常重要啊,设置也是要非常注意的。 比如我家里的路由器网关是192.168.14.1,所以我设置的IP就是192.168.14.100到192.168.14.250都可以! 在电脑上查看自己的网关是多少,只需要程序-》运行,打开cmd,然后ipconfig就可以看到网关了! 二、设置openwrt映射到192.168.1.1的8080端口上(也叫端口转发)! 也就是,外面有8080的连接进来,就自动转到192.168.1.1 三、设置上级路由器的端口映射(端口转发)! 这里呢你家的路由器不同而界面不同,一般都会有这个设置。 现在拿我们家里的路由器设置演示给你看看哦! 输入家里路由器的网关,就能登陆到网页了,不行就看说明或百度吧! 找到端口转发(或NAT或映射,多种不同的叫法) 设置openwrt静态IP和端口。 确认添加! 四、使用公网IP:端口访问摄像头 ok了,这样子只要能上网,就可以连接查看家里的时时视频了! 注意了:部分地区的一些端口是被运营商封了的,所以你要学会变通。 如下面做法:如下界面添加多个端口转发到80

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

daodanjishui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值