【搬运】通过UDP将M5Camera图像发送至M5Stack-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 3078|回复: 0

【搬运】通过UDP将M5Camera图像发送至M5Stack

[复制链接]
发表于 2019-12-15 01:06 | 显示全部楼层 |阅读模式
     本例将介绍通过UDP发送图像至M5Stack,代码分为M5CameraB与M5Stack,由于UDP传输图像的时序很难控制,不可避免的会出现丢包现象,因此作者对ESP32-Camera库进行了拆分重写,视频画面大小为200x148,摄像头代码超过了1000行。ESP32_mgo_tec库文件地址https://github.com/mgo-tec/ESP32_mgo_tec 程序刚启动时可能会出现丢包现象,预热一段时间后基本会稳定。经过测试在无阻挡情况下,wifi图像接收范围在5米左右。 m5stack_m5camera_udp00-825x510.jpg
      简要说明:M5Camera开启了SoftAP,第58-59行配置为CIF模式,图像大小为200x148像素.第66行fix_div = 3的值是1460个字节,这是一个数据包中可以发送的最大字节数。第133-192行,M5Camera的ESP32 CPU核心1任务发送和接收WiFi和UDP。在第141-157行中可以看到M5Camera通过UDP从M5Stack接收到的数据包。现在当立即按下M5Stack的A按钮时, 将在数据包的第一个字节处接收send_ok = 1 ,并且图像将通过WiFi和UDP从M5Camera连续传输。如第159-192行所示,UDP由ESP32的CPU内核1发送。当发生数据包传输错误时,如第169行所示, 从核心函数返回errno == 12,在那种情况下,我认为延迟(3)不会导致数据包丢失,但似乎效果不大。接收到的数据包的第二个字节是自动白平衡开-关标志。接收到的数据包的第三个字节是自动曝光调整ON-OFF标志。通过将16位曝光时间值划分为8位来接收接收到的数据包的第4至第5字节。接收到的数据包的第6个字节是M5Camera复位标志。如第136行所示,如果按住M5Stack上的A按钮,receive_reset将接收值1并,如果检测到它,则通过ESP.restart()强制重置。第208​​-264行:M5Camera ESP32 CPU core 0任务不断从图像传感器OV2640获取图像。在这种情况下,看门狗定时器操作在第237行被禁用,因此如果长时间继续运行可能会出现问题。第967-986行:改变自动白平衡功能,此功能将M5Camera中图像传感器OV2640的自动白平衡调整(AWB)更改为ON / OFF。该寄存器用SCCB从M5Camera中的ESP32传输到图像传感器ov2640。988-1038行:修改自动曝光功能,该功能打开/关闭M5Camera中的图像传感器OV2640的自动曝光调整(AEC),并分三个阶段调整曝光时间。

[mw_shl_code=arduino,true]#include <rom/lldesc.h>
#include <driver/rtc_io.h>
#include <driver/i2s.h>
#include <driver/gpio.h>
#include <driver/i2c.h>
#include <esp_err.h>
#include <driver/ledc.h>

#include <WiFi.h>
#include <WiFiUdp.h>

const char * to_udp_address = "192.168.4.2"; //M5StackIP地址
const int to_server_udp_port = 55556; //接收端口
const int my_server_udp_port = 55555; //发送端口

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

boolean connected = false;
WiFiUDP udp;

const uint8_t ov2640_i2c_addrs = 0x30;

const int8_t cam_pin_PWDN = -1; //M5Camera引脚参照文档说明
const int8_t cam_pin_RESET = 15;
const int8_t cam_pin_XVCLK = 27;
const int8_t cam_pin_SIOD = 22;
const int8_t cam_pin_SIOC = 23;
const int8_t cam_pin_D7 = 19;
const int8_t cam_pin_D6 = 36;
const int8_t cam_pin_D5 = 18;
const int8_t cam_pin_D4 = 39;
const int8_t cam_pin_D3 = 5;
const int8_t cam_pin_D2 = 34;
const int8_t cam_pin_D1 = 35;
const int8_t cam_pin_D0 = 32;
const int8_t cam_pin_VSYNC = 25;
const int8_t cam_pin_HREF = 26;
const int8_t cam_pin_PCLK = 21;

uint8_t camera_pid = 0;
const uint16_t sensor_resolution_h = 400, sensor_resolution_v = 296; //CIF mode
const uint16_t oled_width_pix = 200, oled_height_pix = 148;
const uint16_t out_camera_w = sensor_resolution_h/2;
const uint16_t out_camera_h = sensor_resolution_v/2;
const uint16_t max_w_pix_buf = out_camera_w * 2;
const uint16_t max_w_disp_buf = oled_width_pix * 2;
uint8_t send_udp_buf[oled_height_pix][max_w_pix_buf + 1] = {};
boolean goDrawing_disp = false;
const uint8_t fix_div = 3;

const uint8_t ledc_duty = 1; //1bit value:1 = duty 50%
const double ledc_base_freq = 20000000.0;

const uint32_t sccb_freq = 200000; // I2C master frequency
const uint8_t i2c_write_bit = 0; // I2C master write
const uint8_t i2c_read_bit = 1;  // I2C master read
const uint8_t ack_check_en = 1; // I2C master will check ack from slave
//const uint8_t ack_check_dis = 0;
//const uint8_t ack_val = 0; // I2C ack value
const uint8_t nack_val = 1; // I2C nack value
const int sccb_i2c_port = 1;
uint8_t scan_i2c_addrs = 0;

typedef enum {
    SM_0A0B_0B0C = 0,
    SM_0A0B_0C0D = 1,
    SM_0A00_0B00 = 3,
} i2s_sampling_mode_t;

uint16_t dma_buf_size = out_camera_w * 2 * 4;
lldesc_t *dma_desc;

intr_handle_t i2s_intr_handle;
uint8_t y_pix_count = 0;

esp_err_t err = ESP_OK;
TaskHandle_t task_handl;

static inline void resetI2Sconf();
static void IRAM_ATTR i2s_isr(void* arg);

uint8_t send_ok = 0;
uint8_t receive_auto_white_balance = 0;
uint8_t receive_auto_exposure_control = 0;
uint8_t receive_exposure[2] = {};
uint8_t receive_reset = 0;

//*********************************************
void setup() {
  Serial.begin(115200);
  Serial.println();
  delay(1000);

  connectToWiFi(ssid, password);
  if(connected){
    Serial.println("connected!");
  }

  esp_err_t err = initCamera();
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }
  Serial.printf("Camera:%d x %d pix, OLED:%d x %d pix\r\n", out_camera_w, out_camera_h, oled_width_pix, oled_height_pix);

  dispOnColorBar();
  uint32_t time_out = millis();
  while(true){
    if(millis() - time_out > 5000) break;
    sendUDP();
    delay(1);
  }
  dispOffColorBar();
}

void loop() {
  sendUDP();
  receiveUDP();
  if(receive_reset == 1){
    ESP.restart();
  }
}

void receiveUDP(){
  int receive_packetSize = udp.parsePacket();
  if(receive_packetSize > 0){
    send_ok = udp.read();
    receive_auto_white_balance = udp.read();
    receive_auto_exposure_control = udp.read();
    udp.read(&receive_exposure[0], 2);
    receive_reset = udp.read();
    uint16_t exposure = (receive_exposure[0] << 8) | receive_exposure[1];
    Serial.printf("Receive UDP send_ok=%d, AWB=%d, AEC=%d\r\n", send_ok, receive_auto_white_balance, receive_auto_exposure_control);
    Serial.printf("Receive Exposure=%d\r\n", exposure);
    Serial.printf("Receive Reset=%d\r\n", receive_reset);
    changeAutoWhiteBalance(receive_auto_white_balance);
    changeAutoExposureControl(receive_auto_exposure_control, receive_exposure);
  }
  udp.flush();
}

void sendUDP(){
  if(send_ok){
    if(goDrawing_disp){
      if(connected){
        uint16_t udp_line = 0;
        udp.beginPacket(to_udp_address, to_server_udp_port);
        for(int i = 0; i < oled_height_pix; i++){
          if(i != 0 && (i % fix_div) == 0){
            udp.endPacket();

            if(errno ==12) {
              delay(3);
              break;
            }else{
              delay(1);
              delayMicroseconds(100);
            }

            udp.beginPacket(to_udp_address, to_server_udp_port);
          }
          udp.write((const uint8_t *)&send_udp_buf[0], max_w_disp_buf + 1);
          //Serial.printf("max_w_disp_buf=%d\r\n", max_w_disp_buf);
        }
        udp.endPacket();
        if(errno ==12) {
          delay(3);
        }else{
          delay(2);
        }
      }
      goDrawing_disp = false;
    }
  }
}
//*********************************************
void connectToWiFi(const char * ssid, const char * pwd){
  Serial.println("Connecting to WiFi network: " + String(ssid));
  WiFi.disconnect(true, true); //WiFi config
  WiFi.softAP(ssid, password);
  IPAddress myIP = WiFi.softAPIP();
  Serial.println("WiFi connected!");
  Serial.print("My IP address: ");
  Serial.println(myIP);
  udp.begin(myIP, my_server_udp_port);
  delay(1000);
  connected = true;
}

//****************************************
void taskDMA(void *pvParameters){
  Serial.println("taskDMA Start!!");
  disableCore0WDT(); //禁用看门狗
  uint32_t last_time = millis();
  while (true) {
    while(goDrawing_disp){
      delayMicroseconds(10); //※省略掉屏幕将无显示
    }

    uint32_t st_t = millis();
    while (getGpioLevel((gpio_num_t)cam_pin_VSYNC) == 0) {
      if ((millis() - st_t) > 1000000LL) {
        Serial.println("Timeout waiting for VSYNC");
        goto timeout;
      }
    }

    while (getGpioLevel((gpio_num_t)cam_pin_VSYNC) == 1) {
      ;
    }
    I2S0.conf.rx_start = 0;
    I2S0.in_link.start = 0;
    esp_intr_disable(i2s_intr_handle);

    while (getGpioLevel((gpio_num_t)cam_pin_VSYNC) == 0) {
      ;
    }

    I2S0.rx_eof_num = dma_buf_size;
    I2S0.in_link.addr = (uint32_t)dma_desc;
    I2S0.in_link.start = 1;
    I2S0.conf.rx_start = 1;
    I2S0.int_clr.val = I2S0.int_raw.val;
    I2S0.int_ena.val = 0;
    I2S0.int_ena.in_done = 1;

    esp_intr_enable(i2s_intr_handle);

    while(getGpioLevel((gpio_num_t)cam_pin_VSYNC) != 0){
      ; //把OV2640的像素数据通过DMA写入FIFO存储器
    }

    I2S0.conf.rx_start = 0;
    I2S0.in_link.start = 0;
    esp_intr_disable(i2s_intr_handle);
    resetI2Sconf();
     
    if(millis() - last_time > 10000) {
      enableCore0WDT();
      delay(5);
      disableCore0WDT();
      last_time = millis();
    }
  }
timeout:
  vTaskDelete(task_handl);
}
//*********************************************
static void IRAM_ATTR i2s_isr(void* arg){
  I2S0.int_clr.val = I2S0.int_raw.val;
  bool need_yield = false;
  lldesc_t *d = dma_desc;
  int i, pix_cnt = 0;
  for(i = 0; i < oled_height_pix; i++){
    send_udp_buf[0] = i;
  }
  pix_cnt = 1;

  for (i = 2; i < dma_buf_size; i += 4) {
    send_udp_buf[y_pix_count][pix_cnt++] = (uint8_t) * (d->buf + i);
  }

  if(y_pix_count == (oled_height_pix - 1)){
    I2S0.conf.rx_start = 0;
    I2S0.in_link.start = 0;
    y_pix_count = 0;
    goDrawing_disp = true;
    return;
  }
  y_pix_count = (y_pix_count + 1) % oled_height_pix;

  if (need_yield) {
      portYIELD_FROM_ISR();
  }
}

int setFramesize(uint16_t out_width, uint16_t out_height){
  int ret = 0;
  ret = writeSCCB(0xFF, 0x00);//bank dsp
  if (!ret) {
    ret = writeSCCB(0x05, 0x00); //R_BYPASS:0x00 DSP use.
    if(ret) return ret;
  }
  delay(5);

  uint8_t pclk_div2 = 0x01; //PCLK clock divider 2
  uint16_t window_h_start = 137;
  uint16_t window_h_end = window_h_start + sensor_resolution_h;
  uint16_t window_v_start = 2;
  uint16_t window_v_end = window_v_start + sensor_resolution_v;
  uint8_t win_h_st_bit10_3 = (uint8_t)((window_h_start >> 3) & 0x00ff);
  uint8_t win_h_end_bit10_3 = (uint8_t)((window_h_end >> 3) & 0x00ff);
  uint8_t win_v_st_bit9_2 = (uint8_t)((window_v_start >> 2) & 0x00ff);
  uint8_t win_v_end_bit9_2 = (uint8_t)((window_v_end >> 2) & 0x00ff);
  uint8_t win_h_st_bit2_0 = (uint8_t)(window_h_start & 0x0007);
  uint8_t win_h_end_bit2_0 = (uint8_t)(window_h_end & 0x0007);
  uint8_t win_v_st_bit1_0 = (uint8_t)(window_v_start & 0x0003);
  uint8_t win_v_end_bit1_0 = (uint8_t)(window_v_end & 0x0003);

  writeSCCB(0xFF, 0x01); //BANK:sensor
  delay(5);
  writeSCCB(0x12, 0b00100000); //COM7 [6:4]CIF mode
  writeSCCB(0x17, win_h_st_bit10_3); //HREFST(default:0x11)
  writeSCCB(0x18, win_h_end_bit10_3); //HREFEND(SVGA,CIF default:0x43)
  writeSCCB(0x19, win_v_st_bit9_2); //VSTRT
  writeSCCB(0x1A, win_v_end_bit9_2); //VEND
  writeSCCB(0x32, 0x00 | (pclk_div2 << 7) | (win_h_end_bit2_0 << 3) | win_h_st_bit2_0); //REG32,[7:6]10CLK frequency devide by 2, [5:0]0x09:CIF
  writeSCCB(0x03, 0x00 | (win_v_end_bit1_0 << 2) | win_v_st_bit1_0); //COM1 0x0A:CIF?

  writeSCCB(0x11, pclk_div2); //CLKRC 1/2 clock divider
  delay(5);

  uint16_t HSIZE = sensor_resolution_h; //Image Horizontal Size
  uint16_t VSIZE = sensor_resolution_v; //Image Vertical Size
  uint16_t H_SIZE = HSIZE / 4;
  uint16_t V_SIZE = VSIZE / 4;

  uint8_t H_SIZE_bit7_0 = (uint8_t)(H_SIZE & 0x00ff);
  uint8_t V_SIZE_bit7_0 = (uint8_t)(V_SIZE & 0x00ff);
  uint8_t H_SIZE_bit8 = (uint8_t)((H_SIZE >> 8) & 0x0001);
  uint8_t H_SIZE_bit9 = (uint8_t)((H_SIZE >> 9) & 0x0001);
  uint8_t V_SIZE_bit8 = (uint8_t)((V_SIZE >> 8) & 0x0001);

  uint8_t zoom_speed = 0;
  uint16_t OUTW = (uint16_t)floor((double)out_width / 4.0);
  uint16_t OUTH = (uint16_t)floor((double)out_height / 4.0);
  uint8_t OUTW_bit7_0 = (uint8_t)(OUTW & 0x00ff);
  uint8_t OUTH_bit7_0 = (uint8_t)(OUTH & 0x00ff);
  uint8_t OUTW_bit9_8 = (uint8_t)((OUTW >> 8) & 0x0003);
  uint8_t OUTH_bit8 = (uint8_t)((OUTH >> 8) & 0x0001);

  uint8_t HSIZE_bit11 = (uint8_t)((HSIZE >> 11) & 0x0001);
  uint8_t HSIZE_bit2_0 = (uint8_t)(HSIZE & 0x0003);
  uint8_t VSIZE_bit2_0 = (uint8_t)(VSIZE & 0x0003);
  uint8_t HSIZE_bit10_3 = (uint8_t)((HSIZE >> 3) & 0x00ff);
  uint8_t VSIZE_bit10_3 = (uint8_t)((VSIZE >> 3) & 0x00ff);
  Serial.printf("HSIZE=%d, VSIZE=%d, H_SIZE=%d, V_SIZE=%d, OUTW=%d, OUTH=%d\r\n", HSIZE, VSIZE, H_SIZE, V_SIZE, OUTW, OUTH);

  writeSCCB(0xFF, 0x00); //BANKSP
  delay(5);
  writeSCCB(0xE0, 0b00000100); //RESET bit[2]VP ※DVP是并行数据格式
  delay(5);
  writeSCCB(0xC0, HSIZE_bit10_3); //HSIZE8是11位的高8位。这是h_pixel 400
  writeSCCB(0xC1, VSIZE_bit10_3); //VSIZE8是11位的高8位。这是v_pixel 296
  writeSCCB(0x8C, 0x00);

  writeSCCB(0x86, 0b00111101); //CTRL2
  writeSCCB(0x50, 0b10000000); //CTRLl LP_DP EN
  writeSCCB(0x51, H_SIZE_bit7_0); //H_SIZE
  writeSCCB(0x52, V_SIZE_bit7_0); //V_SIZE
  writeSCCB(0x53, 0x00); //XOFFL
  writeSCCB(0x54, 0x00); //YOFFL
  writeSCCB(0x55, 0x00 | (V_SIZE_bit8 << 7) | (H_SIZE_bit8 << 3)); //VHYX
  writeSCCB(0x57, (H_SIZE_bit9 << 7) | 0x00); //TEST
  writeSCCB(0x5A, OUTW_bit7_0); //ZMOW[7:0] (real/4)
  writeSCCB(0x5B, OUTH_bit7_0); //ZMOH[7:0] (real/4)
  writeSCCB(0x5C, 0x00 | (zoom_speed << 4) | (OUTH_bit8 << 2) | (OUTW_bit9_8)); //ZMHH

  writeSCCB(0xD3, 0b10000010); //R_DVP_SP

  writeSCCB(0xE0, 0x00); //RESET
  writeSCCB(0x05, 0x00); //R_BYPASS:0x00 DSP use.

  delay(10); //如果更改分辨率,加上延迟是必要的
  return ret;
}

void initI2S(){
  gpio_num_t pins[] = {
    (gpio_num_t)cam_pin_D7,
    (gpio_num_t)cam_pin_D6,
    (gpio_num_t)cam_pin_D5,
    (gpio_num_t)cam_pin_D4,
    (gpio_num_t)cam_pin_D3,
    (gpio_num_t)cam_pin_D2,
    (gpio_num_t)cam_pin_D1,
    (gpio_num_t)cam_pin_D0,
    (gpio_num_t)cam_pin_VSYNC,
    (gpio_num_t)cam_pin_HREF,
    (gpio_num_t)cam_pin_PCLK
  };
  gpio_config_t conf;
  conf.mode = GPIO_MODE_INPUT;
  conf.pull_up_en = GPIO_PULLUP_ENABLE;
  conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
  conf.intr_type = GPIO_INTR_DISABLE;

  for (int i = 0; i < sizeof(pins) / sizeof(gpio_num_t); ++i) {
    if (rtc_gpio_is_valid_gpio(pins)) {
      rtc_gpio_deinit(pins);
    }
    conf.pin_bit_mask = 1LL << pins;
    gpio_config(&conf);
  }

  gpio_matrix_in(cam_pin_D0, I2S0I_DATA_IN0_IDX, false);
  gpio_matrix_in(cam_pin_D1, I2S0I_DATA_IN1_IDX, false);
  gpio_matrix_in(cam_pin_D2, I2S0I_DATA_IN2_IDX, false);
  gpio_matrix_in(cam_pin_D3, I2S0I_DATA_IN3_IDX, false);
  gpio_matrix_in(cam_pin_D4, I2S0I_DATA_IN4_IDX, false);
  gpio_matrix_in(cam_pin_D5, I2S0I_DATA_IN5_IDX, false);
  gpio_matrix_in(cam_pin_D6, I2S0I_DATA_IN6_IDX, false);
  gpio_matrix_in(cam_pin_D7, I2S0I_DATA_IN7_IDX, false);
  gpio_matrix_in(cam_pin_VSYNC, I2S0I_V_SYNC_IDX, false);
  gpio_matrix_in(0x38, I2S0I_H_SYNC_IDX, false);
  gpio_matrix_in(cam_pin_HREF, I2S0I_H_ENABLE_IDX, false);
  gpio_matrix_in(cam_pin_PCLK, I2S0I_WS_IN_IDX, false);

  // Enable and configure I2S peripheral
  periph_module_enable(PERIPH_I2S0_MODULE);
  // Toggle some reset bits in LC_CONF register
  // Toggle some reset bits in CONF register
  resetI2Sconf();
  // Enable slave mode (sampling clock is external)
  I2S0.conf.rx_slave_mod = 1;
  // Enable parallel mode
  I2S0.conf2.lcd_en = 1;
  // Use HSYNC/VSYNC/HREF to control sampling
  I2S0.conf2.camera_en = 1;
  // Configure clock divider
  I2S0.clkm_conf.clkm_div_a = 1;
  I2S0.clkm_conf.clkm_div_b = 0;
  I2S0.clkm_conf.clkm_div_num = 2;
  // FIFO will sink data to DMA
  I2S0.fifo_conf.dscr_en = 1;
  // FIFO configuration
  I2S0.fifo_conf.rx_fifo_mod = SM_0A00_0B00; //fifo mode = 3
  I2S0.fifo_conf.rx_fifo_mod_force_en = 1;
  I2S0.conf_chan.rx_chan_mod = 1;
  // Clear flags which are used in I2S serial mode
  I2S0.sample_rate_conf.rx_bits_mod = 0;
  I2S0.conf.rx_right_first = 0;
  I2S0.conf.rx_msb_right = 0;
  I2S0.conf.rx_msb_shift = 0;
  I2S0.conf.rx_mono = 0;
  I2S0.conf.rx_short_sync = 0;
  I2S0.timing.val = 0;
  I2S0.timing.rx_dsync_sw = 1;

  // Allocate I2S interrupt, keep it disabled
  esp_intr_alloc(ETS_I2S0_INTR_SOURCE,
                 ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM,
                 &i2s_isr, NULL, &i2s_intr_handle);
}

int getGpioLevel(gpio_num_t gpio_num){
  if (gpio_num < 32) {
    return (GPIO.in >> gpio_num) & 0x1;
  } else {
    return (GPIO.in1.data >> (gpio_num - 32)) & 0x1;
  }
}

static inline void resetI2Sconf(){
  const uint32_t lc_conf_reset_flags = I2S_IN_RST_M | I2S_AHBM_RST_M
                                       | I2S_AHBM_FIFO_RST_M;
  I2S0.lc_conf.val |= lc_conf_reset_flags;
  I2S0.lc_conf.val &= ~lc_conf_reset_flags;

  const uint32_t conf_reset_flags = I2S_RX_RESET_M | I2S_RX_FIFO_RESET_M
                                    | I2S_TX_RESET_M | I2S_TX_FIFO_RESET_M;
  I2S0.conf.val |= conf_reset_flags;
  I2S0.conf.val &= ~conf_reset_flags;
  while (I2S0.state.rx_fifo_reset_back) {
    ;
  }
}

esp_err_t initDMAdesc(){
  Serial.println("initDMAdesc");
  assert(out_camera_w % 4 == 0); //预先确定宽度像素是否可被4整除

  Serial.printf("DMA buffer size: %d\r\n", dma_buf_size);

  dma_desc = (lldesc_t*) malloc(sizeof(lldesc_t));
  if (dma_desc == NULL) {
    return ESP_ERR_NO_MEM;
  }

  Serial.printf("Allocating DMA buffer size=%d\r\n", dma_buf_size);

  lldesc_t* pd = dma_desc;
  pd->length = dma_buf_size;
  pd->size = pd->length;
  pd->owner = 1;
  pd->sosf = 1;
  pd->buf = (uint8_t*) malloc(dma_buf_size);
  if (pd->buf == NULL) {
    Serial.println("pd->buf NULL");
    return ESP_ERR_NO_MEM;
  }
  pd->offset = 0;
  pd->empty = 0;
  pd->eof = 1;
  pd->qe.stqe_next = dma_desc;

  return ESP_OK;
}

int reset(){
  int ret = 0;
  ret = writeSCCB(0xFF, 0x01);//bank sensor
  if (!ret) {
    Serial.println("OV2640 System Resister Reset (COM7)");
    ret = writeSCCB(0x12, 0b10100000); //COM7:SRST System Reset & CIF mode
    if(ret) return ret;
  }
  delay(10);
  writeRegisterCIF();
  delay(100);
  return ret;
}

esp_err_t probeCamera(){
  enableOutClockToCamera();

  sccbInit(cam_pin_SIOD, cam_pin_SIOC);

  Serial.println("Resetting camera");
  gpio_config_t conf = { 0 };
  conf.pin_bit_mask = 1LL << cam_pin_RESET;
  conf.mode = GPIO_MODE_OUTPUT;
  gpio_config(&conf);

  gpio_set_level((gpio_num_t)cam_pin_RESET, 0);
  delay(10);
  gpio_set_level((gpio_num_t)cam_pin_RESET, 1);
  delay(10);

  Serial.println("Searching for camera address");
  delay(10);
  uint8_t slv_addr = sccbProbe();

  if (slv_addr == ov2640_i2c_addrs) {
    Serial.println("Detected camera OV2640");
  }else{
    disableOutClockToCamera();
    return ESP_FAIL;
  }

  uint8_t reg_PIDH = 0x0A; //Product ID Number MSB
  uint8_t reg_PIDL = 0x0B; //Product ID Number LSB
  uint8_t reg_MIDH = 0x1C; //Manufacture ID Byte MSB
  uint8_t reg_MIDL = 0x1D; //Manufacture ID Byte LSB

  writeSCCB(0xFF, 0x01);//bank sensor

  camera_pid = readSCCB(reg_PIDH);
  uint8_t ver = readSCCB(reg_PIDL);
  uint8_t midh = readSCCB(reg_MIDH);
  uint8_t midl = readSCCB(reg_MIDL);
  delay(10);

  Serial.printf("roduct ID=0x%02X\r\n", camera_pid);
  Serial.printf("roduct Ver=0x%02X\r\n", ver);
  Serial.printf("Manufacture ID High=0x%02X\r\n", midh);
  Serial.printf("Manufacture ID Low=0x%02X\r\n", midl);

  if(camera_pid == 0x26){
      Serial.println("camera_model = CAMERA_OV2640");
  }else{
      disableOutClockToCamera();
      Serial.println("Detected camera not supported.");
      return ESP_FAIL;
  }

  reset();
  return ESP_OK;
}

void enableOutClockToCamera(){
  ledcSetup(LEDC_CHANNEL_0, ledc_base_freq, LEDC_TIMER_1_BIT); //40MHz、bit=1
  ledcAttachPin(cam_pin_XVCLK, LEDC_CHANNEL_0);
  ledcWrite(LEDC_CHANNEL_0, ledc_duty); //duty:50%
}

void disableOutClockToCamera(){
  periph_module_disable(PERIPH_LEDC_MODULE);
}

esp_err_t initCamera()
{
  esp_err_t err = probeCamera();
  if (err != ESP_OK) {
    Serial.printf("Camera probe failed with error 0x%x", err);
    goto fail;
  }

  if (setFramesize(out_camera_w, out_camera_h) != 0) {
    Serial.println("Failed to set frame size");
    err = ESP_FAIL;
    goto fail;
  }

  writeRegisterRGB565();

  writeSCCB(0xFF, 0x01);//bank sensor
  Serial.printf("Now Gain ceiling=%d\r\n", readSCCB(0x14));

  if (camera_pid == 0x26) {
    uint8_t s_value1, s_value2;
    //set AGC(Auto Gain Ceiling)
    writeSCCB(0xFF, 0x01); //Bank Sensor
    s_value1 = readSCCB(0x14); //COM9
    delay(5);
    writeSCCB(0xFF, 0x01); //readの後のwriteは必ずbank設定必要
    writeSCCB(0x14, s_value1 | 0b01000000); //COM9 AGC(Auto Gain Ceiling) 8x
    delay(5);
    //set BPC(Black Point Corrections?),WPC(White Point Corrections?), LENC(Lens Corrections?)
    writeSCCB(0xFF, 0x00); //Bank DSP
    s_value1 = readSCCB(0x87); //CTRL3
    s_value2 = readSCCB(0xC3); //CTRL1
    delay(5);
    writeSCCB(0xFF, 0x00); //Bank DSP
    writeSCCB(0x87, 0b10010000 | s_value1); //CTRL3 [7]BPC:1, [6]WPC:1
    writeSCCB(0xC3, 0b00000000 | s_value2); //CTRL1 [3]AWB, [1]LENC
    writeSCCB(0xC2, 0b10001100); //CTRL0 [7]AEC_EN
    delay(10);

    writeSCCB(0xFF, 0x01);
    Serial.printf("After set Gain ceiling=%d\r\n", readSCCB(0x14));
    writeSCCB(0xFF, 0x00); //Bank DSP
    Serial.print("After set CTRL3= ");
    Serial.println(readSCCB(0x87), BIN);
  }

  initI2S();

  err = initDMAdesc();
  if (err != ESP_OK) {
    Serial.println("Failed to initialize I2S and DMA");
    goto fail;
  }

  if (!xTaskCreatePinnedToCore(&taskDMA, "taskDMA", 8192, NULL, 10, &task_handl, 0)) {
    Serial.println("Failed to create DMA filter task");
    err = ESP_ERR_NO_MEM;
    goto fail;
  }

  return ESP_OK;

fail:
  disableOutClockToCamera();
  Serial.println("ERROR camera init");
  return err;
}

void sccbInit(int pin_sda, int pin_scl){
  i2c_config_t conf;
  conf.mode = I2C_MODE_MASTER;
  conf.sda_io_num = (gpio_num_t)pin_sda;
  conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
  conf.scl_io_num = (gpio_num_t)pin_scl;
  conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
  conf.master.clk_speed = sccb_freq;

  i2c_param_config((i2c_port_t)sccb_i2c_port, &conf);
  i2c_driver_install((i2c_port_t)sccb_i2c_port, conf.mode, 0, 0, 0);
}

uint8_t sccbProbe(){
  uint8_t slave_addr = 0x0;
  while (slave_addr < 0x7f) {
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, ( slave_addr << 1 ) | i2c_write_bit, ack_check_en);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin((i2c_port_t)sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    if ( ret == ESP_OK) {
      scan_i2c_addrs = slave_addr;
      Serial.printf("Detected Slave Address=%02X\r\n", scan_i2c_addrs);
      return scan_i2c_addrs;
    }
    slave_addr++;
  }
  return scan_i2c_addrs;
}

uint8_t readSCCB(uint8_t reg){
  uint8_t data = 0;
  esp_err_t ret = ESP_FAIL;
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, ( scan_i2c_addrs << 1 ) | i2c_write_bit, ack_check_en);
  i2c_master_write_byte(cmd, reg, ack_check_en);
  i2c_master_stop(cmd);
  ret = i2c_master_cmd_begin((i2c_port_t)sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
  i2c_cmd_link_delete(cmd);

  if (ret != ESP_OK) {
    Serial.println(ret);
    Serial.println("fail");
    return -1;
  }
  cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, ( scan_i2c_addrs << 1 ) | i2c_read_bit, ack_check_en);
  i2c_master_read_byte(cmd, &data, (i2c_ack_type_t)nack_val);
  i2c_master_stop(cmd);
  ret = i2c_master_cmd_begin((i2c_port_t)sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
  i2c_cmd_link_delete(cmd);
  if (ret != ESP_OK) {
    Serial.printf("readSCCB Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", scan_i2c_addrs, reg, data, ret);
  }
  return data;
}

uint8_t writeSCCB(uint8_t reg, uint8_t data){
  esp_err_t ret = ESP_FAIL;
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, ( scan_i2c_addrs << 1 ) | i2c_write_bit, ack_check_en);
  i2c_master_write_byte(cmd, reg, ack_check_en);
  i2c_master_write_byte(cmd, data, ack_check_en);
  i2c_master_stop(cmd);
  ret = i2c_master_cmd_begin((i2c_port_t)sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
  i2c_cmd_link_delete(cmd);
  //Serial.printf("writeSCCB ret=%d\r\n", ret);
  if (ret != ESP_OK) {
    Serial.printf("writeSCCB Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d\r\n", scan_i2c_addrs, reg, data, ret);
  }
  return ret == ESP_OK ? 0 : -1;
}

void writeRegisterCIF(){
  Serial.println("writeRegisterCIF");
  writeSCCB(0xff, 0x00);
  delay(5);
  writeSCCB(0x2c, 0xff);
  writeSCCB(0x2e, 0xdf);
  delay(5);
  writeSCCB(0xff, 0x01);
  delay(5);
  writeSCCB(0x3c, 0x32);
  //
  writeSCCB(0x11, 0x00); //CLKRC: none clock divide
  writeSCCB(0x09, 0x02);
  writeSCCB(0x04, 0x28);
  writeSCCB(0x13, 0x11100111); //COM8:default C7, [2]AGC 0:manual 1:auto [0]AEC(自動露出) 0:manual 1:auto
  writeSCCB(0x14, 0x48);
  writeSCCB(0x2c, 0x0c);
  writeSCCB(0x33, 0x78);
  writeSCCB(0x3a, 0x33);
  writeSCCB(0x3b, 0xfB);
  //
  writeSCCB(0x3e, 0x00);
  writeSCCB(0x43, 0x11);
  writeSCCB(0x16, 0x10);
  //
  writeSCCB(0x39, 0x92);
  //
  writeSCCB(0x35, 0xda);
  writeSCCB(0x22, 0x1a);
  writeSCCB(0x37, 0xc3);
  writeSCCB(0x23, 0x00);
  writeSCCB(0x34, 0xc0); //ARCOM2
  writeSCCB(0x36, 0x1a);
  writeSCCB(0x06, 0x88);
  writeSCCB(0x07, 0xc0);
  writeSCCB(0x0d, 0x87);
  writeSCCB(0x0e, 0x41);
  writeSCCB(0x4c, 0x00);
  writeSCCB(0x48, 0x00);
  writeSCCB(0x5B, 0x00);
  writeSCCB(0x42, 0x03);
  //
  writeSCCB(0x4a, 0x81);
  writeSCCB(0x21, 0x99);
  //
  writeSCCB(0x24, 0x40);
  writeSCCB(0x25, 0x38);
  writeSCCB(0x26, 0b10000010); //VV Fast Mode Large Step Threshold. [7:4]High threshold, [3:0]Low threshold
  writeSCCB(0x5c, 0x00);
  writeSCCB(0x63, 0x00);
  writeSCCB(0x46, 0x22);
  writeSCCB(0x0c, 0x3c);
  //
  writeSCCB(0x61, 0x70);
  writeSCCB(0x62, 0x80);
  writeSCCB(0x7c, 0x05);
  //
  writeSCCB(0x20, 0x80);
  writeSCCB(0x28, 0x30);
  writeSCCB(0x6c, 0x00);
  writeSCCB(0x6d, 0x80);
  writeSCCB(0x6e, 0x00);
  writeSCCB(0x70, 0x02);
  writeSCCB(0x71, 0x94);
  writeSCCB(0x73, 0xc1);
  //
  writeSCCB(0x12, 0x40); //COM7
  writeSCCB(0x17, 0x11);
  writeSCCB(0x18, 0x43);
  writeSCCB(0x19, 0x00);
  writeSCCB(0x1a, 0x4b);
  writeSCCB(0x32, 0x09);
  writeSCCB(0x37, 0xc0);
  writeSCCB(0x4f, 0xca); //BD50
  writeSCCB(0x50, 0xa8); //BD60
  writeSCCB(0x5a, 0x23);
  writeSCCB(0x6d, 0x00);
  writeSCCB(0x3d, 0x38);
  //
  delay(5);
  writeSCCB(0xff, 0x00);
  delay(5);
  writeSCCB(0xe5, 0x7f);
  writeSCCB(0xf9, 0xc0);
  writeSCCB(0x41, 0x24);
  writeSCCB(0xe0, 0x14);
  writeSCCB(0x76, 0xff);
  writeSCCB(0x33, 0xa0);
  writeSCCB(0x42, 0x20);
  writeSCCB(0x43, 0x18);
  writeSCCB(0x4c, 0x00);
  writeSCCB(0x87, 0xd5);
  writeSCCB(0x88, 0x3f);
  writeSCCB(0xd7, 0x03);
  writeSCCB(0xd9, 0x10);
  writeSCCB(0xd3, 0x82);
  //
  writeSCCB(0xc8, 0x08);
  writeSCCB(0xc9, 0x80);
  //
  writeSCCB(0x7c, 0x00);
  writeSCCB(0x7d, 0x00);
  writeSCCB(0x7c, 0x03);
  writeSCCB(0x7d, 0x48);
  writeSCCB(0x7d, 0x48);
  writeSCCB(0x7c, 0x08);
  writeSCCB(0x7d, 0x20);
  writeSCCB(0x7d, 0x10);
  writeSCCB(0x7d, 0x0e);
  //
  writeSCCB(0x90, 0x00);
  writeSCCB(0x91, 0x0e);
  writeSCCB(0x91, 0x1a);
  writeSCCB(0x91, 0x31);
  writeSCCB(0x91, 0x5a);
  writeSCCB(0x91, 0x69);
  writeSCCB(0x91, 0x75);
  writeSCCB(0x91, 0x7e);
  writeSCCB(0x91, 0x88);
  writeSCCB(0x91, 0x8f);
  writeSCCB(0x91, 0x96);
  writeSCCB(0x91, 0xa3);
  writeSCCB(0x91, 0xaf);
  writeSCCB(0x91, 0xc4);
  writeSCCB(0x91, 0xd7);
  writeSCCB(0x91, 0xe8);
  writeSCCB(0x91, 0x20);
  //
  writeSCCB(0x92, 0x00);
  writeSCCB(0x93, 0x06);
  writeSCCB(0x93, 0xe3);
  writeSCCB(0x93, 0x05);
  writeSCCB(0x93, 0x05);
  writeSCCB(0x93, 0x00);
  writeSCCB(0x93, 0x04);
  writeSCCB(0x93, 0x00);
  writeSCCB(0x93, 0x00);
  writeSCCB(0x93, 0x00);
  writeSCCB(0x93, 0x00);
  writeSCCB(0x93, 0x00);
  writeSCCB(0x93, 0x00);
  writeSCCB(0x93, 0x00);
  //
  writeSCCB(0x96, 0x00);
  writeSCCB(0x97, 0x08);
  writeSCCB(0x97, 0x19);
  writeSCCB(0x97, 0x02);
  writeSCCB(0x97, 0x0c);
  writeSCCB(0x97, 0x24);
  writeSCCB(0x97, 0x30);
  writeSCCB(0x97, 0x28);
  writeSCCB(0x97, 0x26);
  writeSCCB(0x97, 0x02);
  writeSCCB(0x97, 0x98);
  writeSCCB(0x97, 0x80);
  writeSCCB(0x97, 0x00);
  writeSCCB(0x97, 0x00);
  //
  writeSCCB(0xc3, 0b11100001); //CTRL1
  writeSCCB(0xa4, 0x00);
  writeSCCB(0xa8, 0x00);
  writeSCCB(0xc5, 0x11);
  writeSCCB(0xc6, 0x51);
  writeSCCB(0xbf, 0x80);
  writeSCCB(0xc7, 0x10);
  writeSCCB(0xb6, 0x66);
  writeSCCB(0xb8, 0xA5);
  writeSCCB(0xb7, 0x64);
  writeSCCB(0xb9, 0x7C);
  writeSCCB(0xb3, 0xaf);
  writeSCCB(0xb4, 0x97);
  writeSCCB(0xb5, 0xFF);
  writeSCCB(0xb0, 0xC5);
  writeSCCB(0xb1, 0x94);
  writeSCCB(0xb2, 0x0f);
  writeSCCB(0xc4, 0x5c);
  //
  writeSCCB(0xc0, 0x64);
  writeSCCB(0xc1, 0x4B);
  writeSCCB(0x8c, 0x00);
  writeSCCB(0x86, 0x3D);
  writeSCCB(0x50, 0x00); //bank00, CTRl
  writeSCCB(0x51, 0xC8);
  writeSCCB(0x52, 0x96);
  writeSCCB(0x53, 0x00);
  writeSCCB(0x54, 0x00);
  writeSCCB(0x55, 0x00);
  writeSCCB(0x5a, 0xC8); //ZMOW(Zoom Output Width) 200px
  writeSCCB(0x5b, 0x96); //ZMOH(Zoom Output Height) 150px
  writeSCCB(0x5c, 0x00);
  writeSCCB(0xd3, 0x82);
  //
  writeSCCB(0xc3, 0b11100001); //CTRL1
  writeSCCB(0x7f, 0x00);
  //
  writeSCCB(0xda, 0x08); //IMAGE_MODE RGB565
  //
  writeSCCB(0xe5, 0x1f);
  writeSCCB(0xe1, 0x67);
  writeSCCB(0xe0, 0x00);
  writeSCCB(0xdd, 0x7f);
  writeSCCB(0x05, 0x00);
}

void writeRegisterRGB565(){
  Serial.println("writeRegisterRGB565");
  writeSCCB(0xff, 0x00); //bank dsp
  writeSCCB(0xE0, 0x04); //RESET DVP
  writeSCCB(0xDA, 0x08); //IMAGE_MODE, RGB565
  writeSCCB(0xE0, 0x00); //RESET
}

void dispOnColorBar(){
  writeSCCB(0xff, 0x01); //bank sensor
  writeSCCB(0x12, 0b00100010); //COM7 CIF mode, colorbar en
}

void dispOffColorBar(){
  writeSCCB(0xff, 0x01); //bank sensor
  writeSCCB(0x12, 0b00100000); //COM7 CIF mode, colorbar en
}

void changeAutoWhiteBalance(uint8_t receive_data){
  Serial.println("AWB change!");
  uint8_t CTRL1;
  writeSCCB(0xff, 0x00);
  CTRL1 = readSCCB(0xC3);
  Serial.print("Old CTRL1=");
  Serial.println(CTRL1, BIN);
  uint8_t CTRL1_bit3_2 = 0, awb_bit = 0, awb_gain_bit = 0;
  awb_bit = receive_data << 3;
  awb_gain_bit = receive_data << 2;
  CTRL1_bit3_2 = awb_bit | awb_gain_bit;
  uint8_t msb, lsb;
  msb = CTRL1 & 0b11110000;
  lsb = CTRL1 & 0b00000011;
  CTRL1 = (lsb | CTRL1_bit3_2) | msb;
  writeSCCB(0xff, 0x00);
  writeSCCB(0xC3, CTRL1);
  Serial.print("New CTRL1=");
  Serial.println(CTRL1, BIN);
}

void changeAutoExposureControl(uint8_t change, uint8_t exposure[2]){
  uint8_t COM8 = 0;
  writeSCCB(0xff, 0x01);
  COM8 = readSCCB(0x13);
  Serial.print("Old COM8=");
  Serial.println(COM8, BIN);
  uint8_t change_aec = 0;
  if(change) {
    change_aec = 0b11100111;
  }else{
    change_aec = 0b11000110;
    exposureResister(exposure);
  }
  if(COM8 != change_aec){
    COM8 = change_aec;
    writeSCCB(0xff, 0x01);
    writeSCCB(0x13, COM8);
    Serial.print("New COM8=");
    Serial.println(COM8, BIN);
  }
}

void exposureResister(uint8_t exposure[2]){
  writeSCCB(0xff, 0x01);
  uint8_t old_REG45 = readSCCB(0x45);
  uint8_t old_AEC = readSCCB(0x10);
  uint8_t old_REG04 = readSCCB(0x04);

  uint16_t old_ex[3] = {};
  uint16_t temp = 0;
  old_ex[0] = (((uint16_t)old_REG45 & 0x003f)) << 10;
  old_ex[1] = ((uint16_t)old_AEC) << 2;
  old_ex[2] = ((uint16_t)old_REG04) & 0x0003;
  uint16_t old_exposure = old_ex[0] | old_ex[1] | old_ex[1];
  Serial.printf("old_exposure=%d\r\n", old_exposure);
  uint8_t new_REG45 = 0;
  uint8_t new_AEC = 0;
  uint8_t new_REG04 = 0;

  new_REG45 = (old_REG45 & 0b11000000);
  new_REG45 = new_REG45 | (exposure[0] >> 2);
  new_AEC = (exposure[0] << 6) | (exposure[1] >> 6);
  new_REG04 = (new_REG04 & 0b11111100);
  new_REG04 = new_REG04 | (exposure[1] & 0b00000011);
  writeSCCB(0xff, 0x01);
  writeSCCB(0x45, new_REG45);
  writeSCCB(0x10, new_AEC);
  writeSCCB(0x04, new_REG04);
  uint16_t new_exposure = (exposure[0] << 8) | exposure[1];
  Serial.printf("new_exposure=%d\r\n", new_exposure);
}[/mw_shl_code]


以下为M5Stack端的代码,作者自己封装了一个显示库改写了默认的字体并增加了菜单样式,可以自行修改。建议先从github进行下载mgo_tec库进行验证
[mw_shl_code=arduino,true]#define MGO_TEC_BV1_M5STACK_SD_SKETCH
#include <mgo_tec_bv1_m5stack_sd_simple1.h> //ESP32_mgo_tec library. beta ver 1.0.69

#include <WiFi.h>
#include <WiFiUdp.h>

const char* utf8sjis_file = "/font/Utf8Sjis.tbl"; //UTF8 Shift_JIS 描述转换表文件名
const char* shino_half_font_file = "/font/shnm8x16.bdf"; //定义半角字体文件名
const char* shino_full_font_file = "/font/MYshnmk16.bdf"; //修改的双字节Shinonome字体文件

const char * to_udp_address = "192.168.4.1";
const int to_server_udp_port = 55555;
const int my_server_udp_port = 55556;

const char* ssid = "xxxxxxxxx"; //M5Camera的SSID
const char* password = "xxxxxxxxx"; //密码

WiFiUDP udp;
boolean connected = false;

const uint16_t disp_w_pix = 200;
const uint16_t disp_h_pix = 148;
const uint8_t fix_div = 3;
const uint8_t div_h = disp_h_pix / fix_div;
uint16_t udp_line = 0;
boolean isDisp_ok = false;
const uint16_t line_max_bytes = disp_w_pix * 2;
unsigned char line_num_buf[fix_div] = {};
unsigned char pix_buf[disp_h_pix][line_max_bytes] = {};
TaskHandle_t task_handl;

enum UdpSendStatus {
  udp_stop = 0,
  udp_start = 1
} UdpSendState = udp_stop;

enum UdpSendAwb {
  awb_off = 0,
  awb_on = 1
} UdpSendAWB = awb_off;

enum UdpSendAec {
  aec_off = 0,
  aec_on = 1
} UdpSendAEC = aec_on;

uint8_t udp_send_reset = 0;

int16_t exposure[4] = {0, 192, 256, 8192};
int8_t exposure_count = 0;
String aec_str[4] = {"Auto ",
                     " - 1 ",
                     " + 1 ",
                     " + 2 "};
String stream_str[3] = {"Stop ", "Start", "RESET"};
String awb_str[2] = {" OFF ", " O N "};

uint8_t send_auto_white_balance = 0;
uint8_t send_auto_exposure_control = 0;
uint8_t send_data[6] = {};
uint8_t offset = 1;
boolean isSend_ok = false;

uint16_t btn1_x0 = 0, btn1_x1 = 107;
uint16_t btn2_x0 = 107, btn2_x1 = 212;
uint16_t btn3_x0 = 212, btn3_x1 = 319;
uint16_t btn_y0 = 197, btn_y1 = 233;

//********CPU core 1 task********************
void setup(){
  Serial.begin(115200);
  delay(1000);
  xTaskCreatePinnedToCore(&taskDisplay, "taskDisplay", 8192, NULL, 10, &task_handl, 0);
  connectToWiFi();
  while(!connected){
    delay(1);
  }
  send_data[2] = (uint8_t)UdpSendAEC;
}

void loop(){
  receiveUDP();
  sendUDP(send_data);
}

void receiveUDP(){
  if(!isDisp_ok){
    if(connected){
      int packetSize = udp.parsePacket();
      if(packetSize > 0){
        for(int i = 0; i < fix_div; i++){
          udp.read(&line_num_buf, 1);
          udp.read(&pix_buf[line_num_buf][0], line_max_bytes);
        }
        udp_line = (uint16_t)floor((double)line_num_buf[0] / (double)fix_div);
        //Serial.printf("udp_line=%2d, packet_size =%d, (", udp_line, packetSize);
        if(udp_line == (div_h - 1)) isDisp_ok = true;
      }
      udp.flush();
      delayMicroseconds(500);
    }
  }
}

void sendUDP(uint8_t send_data[5]){
  if(isSend_ok){
    udp.beginPacket(to_udp_address, to_server_udp_port);
    udp.write(send_data, 6);
    udp.endPacket();
    isSend_ok = false;[/mw_shl_code]



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-12-28 09:52 , Processed in 0.086299 second(s), 19 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表