334eba5c5033e0ec13ddbc4e19b0b1ee_raw
前言
相信大家看了顶部的演示视频之后,可能都会怀疑串口真的能否实现这种帧率的视频流实时传输,其实我一开始做的时候也在考虑是否要用C51内核驱动OV2640摄像头,还是说考虑用串口传输摄像头JPEG数据。结果就是串口传输完全不会输直接驱动。视频流的帧率可以稳定在10~17帧,并且几乎没有出现花屏和卡顿。
正文
想要实现视频中的效果,必须实现以下几点:
①使用两个图标叠加控件来回切换显示,如果只有1个图标叠加控件显示,那会在串口传输jpeg数据时出现图片刷新的过程,如视频所示https://v.superbed.cn/play/624f1986239250f7c5c522e3。所以使用两个图标叠加切换显示,可以隐藏正在刷新的图标叠加控件,同时显示另一个已经刷新完成的图标控件。
②两个图标叠加控件重合在一起,一个在顶层,一个在底层。底层的控件一定不要移动坐标隐藏,我们只需要移动顶层的控件来实现显示和隐藏。如果让两个控件交替显示和隐藏,在图片刷新速度很快的情况下,会闪烁出现背景图片,通过该文章的底部视频可以看到闪烁的现象。
③迪文CFG配置文件的波特率设置为3225600。没错!使用迪文的串口屏的最大波特率,这样能够明显的加快图片刷新的速度。迪文屏的串口能够在这么快的串口传输速度下很少受到干扰,并且能够很好的很快的处理接收的数据,这无疑体现了迪文屏的硬件强大之处。
④图片大小不能超过64kB,最好不要超过30kB,具体大小得看你分配给图标叠加控件的变量地址。如果超出图片大小就可能出现花屏和显示错误。
步骤一:
配置迪文控件,放图标叠加控件2(底层),描述地址为1200,变量地址为7FFE。放图标叠加控件1(顶层),描述地址为1100,变量地址为1FFE。放数据变量显示控件,描述地址默认,变量地址为1000,用于显示FPS。配置CFG波特率。保存并生成工程文件,将背景图片生成icl。放入SD卡烧录。
步骤二:
了解迪文控件移动坐标的协议,我们将图标叠加控件移动到屏幕外的坐标即视为隐藏控件,移动回(0,0)坐标则回到控件原点显示图像。
步骤三:
了解迪文图标叠加控件的传输图像协议,并且注意,图中的的红线部分是“补齐”0x00和0x00直到迪文屏接收到240字节的图像数据,而不是在结尾添加0x00和0x00。
步骤四:
以下代码是烧录进入ESP32CAM摄像头模组的,用于获取视频流并将图像数据分包发送给迪文屏。以下代码包含串口图传、SD卡图传与上传图片至巴法云服务器,代码中只运行了串口图传,SD图传和上传图片至运动的代码写了但并没有运行到,无视这部分代码即可。如果感兴趣的可以看懂之后用SD卡进行图传。
- #include
- #include
- #include
- #include "ArduinoJson.h"
- #include "esp_camera.h"
- #include "esp_http_client.h"
- #include "SD.h"
- #include "FS.h"
- #include
- #include
- #include "SD_MMC.h"
- #include <time.h>
- #include "string.h"
- const char *uid = "填写私钥"; //用户私钥,巴法云控制台获取
- const char *topic = "numberpic"; //主题名字,可在控制台新建
- const char *post_url = "http://images.bemfa.com/upload/v1/upimages.php"; // 默认巴法云上传地址
- static String httpResponseString; //接收服务器返回信息
- int page = 0;
- // CAMERA_MODEL_AI_THINKER
- #define PWDN_GPIO_NUM 32
- #define RESET_GPIO_NUM -1
- #define XCLK_GPIO_NUM 0
- #define SIOD_GPIO_NUM 26
- #define SIOC_GPIO_NUM 27
- #define Y9_GPIO_NUM 35
- #define Y8_GPIO_NUM 34
- #define Y7_GPIO_NUM 39
- #define Y6_GPIO_NUM 36
- #define Y5_GPIO_NUM 21
- #define Y4_GPIO_NUM 19
- #define Y3_GPIO_NUM 18
- #define Y2_GPIO_NUM 5
- #define VSYNC_GPIO_NUM 25
- #define HREF_GPIO_NUM 23
- #define PCLK_GPIO_NUM 22
- String comdata = ""; //缓存清零
- HTTPClient http_client;
- char data_json[40000];
- String url1;
- int fps = 0;
- unsigned long previousMillis = 0; //毫秒时间记录
- const long interval = 1000; //时间间隔
- char path[] = "";
- int num = 35;
- void WiFi_Connect()
- {
- WiFi.begin("WIFI账号", "WIFI密码");
- while (WiFi.status() != WL_CONNECTED)
- { //这里是阻塞程序,直到连接成功
- delay(300);
- Serial.print(".");
- }
- }
- void sd_init()
- {
- if (!SD_MMC.begin())
- {
- Serial.println("Card Mount Failed");
- return;
- }
- uint8_t cardType = SD_MMC.cardType();
- if (cardType == CARD_NONE)
- {
- Serial.println("No SD card attached");
- return;
- }
- Serial.print("SD Card Type: ");
- if (cardType == CARD_MMC)
- {
- Serial.println("MMC");
- }
- else if (cardType == CARD_SD)
- {
- Serial.println("SDSC");
- }
- else if (cardType == CARD_SDHC)
- {
- Serial.println("SDHC");
- }
- else
- {
- Serial.println("UNKNOWN");
- }
- uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024); //获取SD卡大小,大小单位是MB
- Serial.printf("SD 卡容量大小: %lluMBn", cardSize);
- }
- void num_to_path(void)
- {
- memset(path,'\0',strlen(path));
- char str1[50];
- strcat(path,"/video/pic");
- itoa(num,str1,10);
- strcat(path,str1);
- strcat(path,".jpg");
- //strcat(path1,path);
-
- }
- void setup()
- {
- Serial.begin(3225600); // open the serial port at 115200 bps;
- delay(100);
- Serial.print("Connecting.. ");
- // WiFi_Connect();
- Serial.println("WiFi connected");
- Serial.println("IP address: ");
- Serial.println(WiFi.localIP());
- 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;
- // init with high specs to pre-allocate larger buffers
- if (psramFound())
- {
- config.frame_size = FRAMESIZE_VGA;
- config.jpeg_quality = 28;
- config.fb_count = 2;
- }
- else
- {
- config.frame_size = FRAMESIZE_SVGA;
- config.jpeg_quality = 12;
- config.fb_count = 1;
- }
- // 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;
- }
- else
- {
- Serial.println("Camera init successed.");
- }
- sd_init(); // SD卡初始化
- }
- /********http请求处理函数*********/
- esp_err_t _http_event_handler(esp_http_client_event_t *evt)
- {
- if (evt->event_id == HTTP_EVENT_ON_DATA)
- {
- httpResponseString.concat((char *)evt->data);
- }
- return ESP_OK;
- }
- /********推送图片*********/
- static esp_err_t take_send_photo()
- {
- Serial.println("Taking picture...");
- camera_fb_t *fb = NULL;
- esp_err_t res = ESP_OK;
- fb = esp_camera_fb_get();
- if (!fb)
- {
- Serial.println("Camera capture failed");
- return ESP_FAIL;
- }
- fps++;
- if (page == 0)
- {
- size_t jpg_size = fb->len;
- Serial.println(jpg_size);
- int packnum = 0;
- packnum = jpg_size / 240;
- char jpg_head_char[4] = {90, 165, 243, 130};
- if (jpg_size % 240 != 0)
- {
- packnum = packnum + 1;
- }
- int jpg_add_num = 0x8000;
- int j = 0;
- int i = 0;
- int jpg_trans = 0;
- while (j < packnum)
- {
- Serial.write(jpg_head_char[0]);
- Serial.write(jpg_head_char[1]);
- Serial.write(jpg_head_char[2]);
- Serial.write(jpg_head_char[3]);
- if (j != 0)
- {
- jpg_add_num = jpg_add_num + 120; // 0x8000+0*0x78
- }
- // Serial.printf("j:%drn",j);
- // Serial.printf("jpg_add_num:%drn",jpg_add_num);
- Serial.write(jpg_add_num >> 8);
- Serial.write(jpg_add_num);
- i = j * 240; // 0,240
- // Serial.printf("i:%drn",i);
- jpg_trans = ((j + 1) * 240) - 1; //((0+1)*240)-1=239
- // Serial.printf("jpg_trans:%drn",jpg_trans);
- while (i <= jpg_trans) //发送[0]-[239]
- {
- Serial.write(fb->buf[i]);
- if (fb->buf[i - 1] == 0xFF && fb->buf[i] == 0xD9)
- {
- break;
- }
- i++;
- }
- j++;
- // delay(1);//10
- }
- if (jpg_size % 240 != 0)
- {
- int k = 0;
- while (k < 240)
- {
- Serial.write(0);
- k++;
- }
- }
- // delay(5);
- // delay(5000);
- // char jpg_show[10]={90,165,7,130,127,254,90,165,128,0};
- /*
- Serial.write(90);
- Serial.write(165);
- Serial.write(7);
- Serial.write(130);
- Serial.write(127);
- Serial.write(254);
- Serial.write(90);
- Serial.write(165);
- Serial.write(128);
- Serial.write(0);
- */
- // delay(2000);
- Serial.write(90);
- Serial.write(165);
- Serial.write(7);
- Serial.write(130);
- Serial.write(127);
- Serial.write(254);
- Serial.write(90);
- Serial.write(165);
- Serial.write(128);
- Serial.write(0);
- page = 1;
- // delay(100);
- //
- int l = 0;
- /*
- Serial.write(90); //显示2
- Serial.write(165);
- Serial.write(7);
- Serial.write(130);
- Serial.write(18);
- Serial.write(1);
- Serial.write(0);
- Serial.write(0);
- Serial.write(0);
- Serial.write(0);
- l++;
- */
- //
- delay(10);
- Serial.write(90); //隐藏1
- Serial.write(165);
- Serial.write(7);
- Serial.write(130);
- Serial.write(17);
- Serial.write(1);
- Serial.write(3);
- Serial.write(32);
- Serial.write(3);
- Serial.write(32);
- // delay(1000);
- }
- else
- {
- size_t jpg_size = fb->len;
- Serial.println(jpg_size);
- int packnum = 0;
- packnum = jpg_size / 240;
- char jpg_head_char[4] = {90, 165, 243, 130};
- if (jpg_size % 240 != 0)
- {
- packnum = packnum + 1;
- }
- int jpg_add_num = 0x2000;
- int j = 0;
- int i = 0;
- int jpg_trans = 0;
- while (j < packnum)
- {
- Serial.write(jpg_head_char[0]);
- Serial.write(jpg_head_char[1]);
- Serial.write(jpg_head_char[2]);
- Serial.write(jpg_head_char[3]);
- if (j != 0)
- {
- jpg_add_num = jpg_add_num + 120; // 0x8000+0*0x78
- }
- // Serial.printf("j:%drn",j);
- // Serial.printf("jpg_add_num:%drn",jpg_add_num);
- Serial.write(jpg_add_num >> 8);
- Serial.write(jpg_add_num);
- i = j * 240; // 0,240
- // Serial.printf("i:%drn",i);
- jpg_trans = ((j + 1) * 240) - 1; //((0+1)*240)-1=239
- // Serial.printf("jpg_trans:%drn",jpg_trans);
- while (i <= jpg_trans) //发送[0]-[239]
- {
- Serial.write(fb->buf[i]);
- if (fb->buf[i - 1] == 0xFF && fb->buf[i] == 0xD9)
- {
- break;
- }
- i++;
- }
- j++;
- // delay(1);//10
- }
- if (jpg_size % 240 != 0)
- {
- int k = 0;
- while (k < 240)
- {
- Serial.write(0);
- k++;
- }
- }
- // delay(2000);
- Serial.write(90);
- Serial.write(165);
- Serial.write(7);
- Serial.write(130);
- Serial.write(31);
- Serial.write(254);
- Serial.write(90);
- Serial.write(165);
- Serial.write(32);
- Serial.write(0);
- page = 0;
- // delay(100);
- //
- Serial.write(90); //显示1
- Serial.write(165);
- Serial.write(7);
- Serial.write(130);
- Serial.write(17);
- Serial.write(1);
- Serial.write(0);
- Serial.write(0);
- Serial.write(0);
- Serial.write(0);
- //
- /*
- Serial.write(90); //隐藏2
- Serial.write(165);
- Serial.write(7);
- Serial.write(130);
- Serial.write(18);
- Serial.write(1);
- Serial.write(3);
- Serial.write(32);
- Serial.write(3);
- Serial.write(32);
- */
- // delay(1000);
- }
- /*
- //int i=0;
- while(i
- {
- Serial.write(fb->buf[i]);
- i++;
- }*/
- // Serial.print(fb->buf[0]);
- /*
- Serial.println("");
- httpResponseString = "";
- esp_http_client_handle_t http_client;
- esp_http_client_config_t config_client = {0};
- config_client.url = post_url;
- config_client.event_handler = _http_event_handler;
- config_client.method = HTTP_METHOD_POST;
- http_client = esp_http_client_init(&config_client);
- esp_http_client_set_post_field(http_client, (const char *)fb->buf, fb->len);//设置http发送的内容和长度
- esp_http_client_set_header(http_client, "Content-Type", "image/jpg"); //设置http头部字段
- esp_http_client_set_header(http_client, "Authorization", uid); //设置http头部字段
- esp_http_client_set_header(http_client, "Authtopic", topic); //设置http头部字段
- esp_err_t err = esp_http_client_perform(http_client);//发送http请求
- if (err == ESP_OK) {
- //json数据解析
- StaticJsonDocument<200> doc;
- DeserializationError error = deserializeJson(doc, httpResponseString);
- if (error) {
- Serial.print(F("deserializeJson() failed: "));
- Serial.println(error.c_str());
- }
- String url = doc["url"];
- url1=url;
- Serial.println(url);//打印获取的URL
- }
- esp_http_client_cleanup(http_client);
- */
- esp_camera_fb_return(fb);
- }
- static esp_err_t send_photo()
- {
- //将sd卡图片数据提取到fb中
- camera_fb_t *fb = esp_camera_fb_get();
- fb->len = 0;
- *fb->buf = NULL;
- Serial.println(*fb->buf);
- fs::FS &fs = SD_MMC;
- num_to_path(); //文件名组合 数字+文件后缀
- Serial.println(path);
- if(num>0)
- {
- num--;
- }else{
- num=35;
- }
- File file = fs.open("/video/0.jpg", FILE_READ);//File file = fs.open(path, FILE_READ);
- if (!file)
- {
- Serial.println("文件打开失败");
- file.close();
- }
- else
- {
- fb->len = file.size(); //读取文件内大小
- file.read(fb->buf, fb->len); //第一个参数是储存的buf,第二个是读取的信息长度
- file.close();
- Serial.println("成功读取照片");
-
- fps++;
- if (page == 0)
- {
- size_t jpg_size = fb->len;
- Serial.println(jpg_size);
- int packnum = 0;
- packnum = jpg_size / 240;
- char jpg_head_char[4] = {90, 165, 243, 130};
- if (jpg_size % 240 != 0)
- {
- packnum = packnum + 1;
- }
- int jpg_add_num = 0x8000;
- int j = 0;
- int i = 0;
- int jpg_trans = 0;
- while (j < packnum)
- {
- Serial.write(jpg_head_char[0]);
- Serial.write(jpg_head_char[1]);
- Serial.write(jpg_head_char[2]);
- Serial.write(jpg_head_char[3]);
- if (j != 0)
- {
- jpg_add_num = jpg_add_num + 120; // 0x8000+0*0x78
- }
- // Serial.printf("j:%drn",j);
- // Serial.printf("jpg_add_num:%drn",jpg_add_num);
- Serial.write(jpg_add_num >> 8);
- Serial.write(jpg_add_num);
- i = j * 240; // 0,240
- // Serial.printf("i:%drn",i);
- jpg_trans = ((j + 1) * 240) - 1; //((0+1)*240)-1=239
- // Serial.printf("jpg_trans:%drn",jpg_trans);
- while (i <= jpg_trans) //发送[0]-[239]
- {
- Serial.write(fb->buf[i]);
- if (fb->buf[i - 1] == 0xFF && fb->buf[i] == 0xD9)
- {
- break;
- }
- i++;
- }
- j++;
- // delay(1);//10
- }
- if (jpg_size % 240 != 0)
- {
- int k = 0;
- while (k < 240)
- {
- Serial.write(0);
- k++;
- }
- }
- Serial.write(90);
- Serial.write(165);
- Serial.write(7);
- Serial.write(130);
- Serial.write(127);
- Serial.write(254);
- Serial.write(90);
- Serial.write(165);
- Serial.write(128);
- Serial.write(0);
- page = 1;
- int l = 0;
- delay(10);
- Serial.write(90); //隐藏1
- Serial.write(165);
- Serial.write(7);
- Serial.write(130);
- Serial.write(17);
- Serial.write(1);
- Serial.write(3);
- Serial.write(32);
- Serial.write(3);
- Serial.write(32);
- }
- else
- {
- size_t jpg_size = fb->len;
- Serial.println(jpg_size);
- int packnum = 0;
- packnum = jpg_size / 240;
- char jpg_head_char[4] = {90, 165, 243, 130};
- if (jpg_size % 240 != 0)
- {
- packnum = packnum + 1;
- }
- int jpg_add_num = 0x2000;
- int j = 0;
- int i = 0;
- int jpg_trans = 0;
- while (j < packnum)
- {
- Serial.write(jpg_head_char[0]);
- Serial.write(jpg_head_char[1]);
- Serial.write(jpg_head_char[2]);
- Serial.write(jpg_head_char[3]);
- if (j != 0)
- {
- jpg_add_num = jpg_add_num + 120; // 0x8000+0*0x78
- }
- Serial.write(jpg_add_num >> 8);
- Serial.write(jpg_add_num);
- i = j * 240; // 0,240
- jpg_trans = ((j + 1) * 240) - 1; //((0+1)*240)-1=239
- while (i <= jpg_trans) //发送[0]-[239]
- {
- Serial.write(fb->buf[i]);
- if (fb->buf[i - 1] == 0xFF && fb->buf[i] == 0xD9)
- {
- break;
- }
- i++;
- }
- j++;
- }
- if (jpg_size % 240 != 0)
- {
- int k = 0;
- while (k < 240)
- {
- Serial.write(0);
- k++;
- }
- }
- Serial.write(90);
- Serial.write(165);
- Serial.write(7);
- Serial.write(130);
- Serial.write(31);
- Serial.write(254);
- Serial.write(90);
- Serial.write(165);
- Serial.write(32);
- Serial.write(0);
- page = 0;
- Serial.write(90); //显示1
- Serial.write(165);
- Serial.write(7);
- Serial.write(130);
- Serial.write(17);
- Serial.write(1);
- Serial.write(0);
- Serial.write(0);
- Serial.write(0);
- Serial.write(0);
- }
- }
- //清空数据
- esp_camera_fb_return(fb);
- }
- // 获取粉丝数
- void getPicNum()
- {
- memset(data_json, '\0', strlen(data_json)); //将数组清空
- strcat(data_json, "{");
- strcat(data_json, ""url":"https://s3.bmp.ovh/imgs/2022/02/51491c953c2345ba.jpg""); //
- // strcat(data_json,""url":"");
- // strcat(data_json,""");
- // strcat(data_json,"}");
- // Serial.println(data_json);
- Serial.println("..........................");
- int httpCode;
- http_client.begin("https://aip.baidubce.com/rest/2.0/ocr/v1/numbers?access_token=24.596f1bb08a48ee2a26689169a483a1a7.2592000.1648374558.282335-25667508");
- http_client.addHeader("Content-Type", "application/x-www-form-urlencoded");
- httpCode = http_client.POST(url1); //("{"text":"food"}");
- Serial.printf("Confirm URL:");
- Serial.println(url1); //打印获取的URL1
- if (httpCode > 0)
- {
- // httpCode will be negative on error
- Serial.printf("HTTP Get Code: %drn", httpCode);
- if (httpCode == HTTP_CODE_OK) // 收到正确的内容
- {
- String resBuff = http_client.getString();
- Serial.println("Number recognition result:");
- Serial.println(resBuff);
- }
- }
- else
- {
- Serial.printf("HTTP Get Error: %sn", http_client.errorToString(httpCode).c_str());
- }
- http_client.end();
- }
- void loop()
- {
- take_send_photo();
- //delay(3000);
- //send_photo();
- //num_to_path();
- /*
- if(num>0)
- {
- num--;
- }else{
- num=0;
- }*/
- //Serial.printf(path);
- unsigned long currentMillis = millis(); //读取当前时间
- if (currentMillis - previousMillis >= interval) //如果和前次时间大于等于时间间隔
- {
- previousMillis = currentMillis; //更新时间记录
- // Serial.println(fps); //打印当前时间
- Serial.write(90);
- Serial.write(165);
- Serial.write(5);
- Serial.write(130);
- Serial.write(16);
- Serial.write(0);
- if (fps <= 255)
- {
- Serial.write(0);
- Serial.write(fps);
- }
- else
- {
- Serial.write(fps);
- }
- fps = 0;
- }
-
- // delay(5000);
- // getPicNum();
- // delay(10000);
- }
复制代码
步骤五:
在编译烧写代码后,连接ESP32CAM和迪文屏之间的串口与 电源,通电即可运行视频流效果。
494f09fde971ea457cb40623ccb1b5d7
|