单片机/MCU论坛
直播中

sipower

4年用户 26经验值
擅长:嵌入式技术
私信 关注
[文章]

【FireBeetle 2 ESP32-S3开发板体验】004:拍照,显示,存储

上一帖介绍增加屏幕和SD卡组件,并通过Arduino编写基础程序模块,为后面实验做准备。这一贴介绍在前面工作基础上,使用摄像头拍照,将图像缩小显示在屏幕上,将原图保存在SD卡上。
我预期的最终作品是一个鱼缸监视器,其中一个重要功能就是定时拍照鱼缸的图片并存储,本次实验实现这个功能。在上一贴中,已经实现图片缩小和显示,这次要实现拍照,存储,并和上一次的程序整合到一起。
最开始设计的基本流程是:a、设置摄像头参数;b、从摄像头获得图片数据;c、打开SD目录;d、建立图片文件;e、写入文件并关闭文件;f、读取文件;g、用《TJpg_Decoder》库缩小后显示到屏幕上;h、显示图片名称。
其中实现a-e拍照并存储的代码如下。
001.png
图1、拍照并存储图片
其中,使用EEPROM的目的是实现图片名称的连续存储,即使掉电也能接续上之前的名称序号继续存储,而不会导致名称重置覆盖掉之前的图片。
在调试过程中,我发现《TJpg_Decoder》库是支持从数组直接进行显示的,这样就不用频繁操作SD卡了,我又把流程进行了更改如下。
a、设置摄像头参数;b、从摄像头获得图片数据;c、用《TJpg_Decoder》库缩小后显示到屏幕上;d、显示图片名称;e、打开SD目录;f、建立图片文件;g、写入文件并关闭文件。
如此更改后,减少了一步读卡过程,提高了效率,减少SD卡寿命磨损。代码如下。
002.png
图2、
我设置了连续存储十张照片,并通过串口输出照片的相关信息,可以实时看到程序运行状态。串口输出效果如下。
003.png
图3、串口输出
存完的照片,在SD卡上的结果如下图所示。
04.png
图4、存到卡上的照片
整体代码如下。
  1. #include "esp_camera.h"
  2. #include
  3. #include "DFRobot_AXP313A.h"
  4. #include "Arduino.h"
  5. #include "FS.h"
  6. #include
  7. #include "SD.h"
  8. #include "SPI.h"
  9. // Include the jpeg decoder library
  10. #include
  11. #include   // Hardware-specific library
  12. TFT_eSPI tft = TFT_eSPI();  // Invoke custom library
  13. // This next function will be called during decoding of the jpeg file to
  14. // render each block to the TFT.  If you use a different TFT library
  15. // you will need to adapt this function to suit.
  16. bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap) {
  17.   // Stop further decoding as image is running off bottom of screen
  18.   if (y >= tft.height()) return 0;
  19.   // This function will clip the image block rendering automatically at the TFT boundaries
  20.   tft.pushImage(x, y, w, h, bitmap);
  21.   // This might work instead if you adapt the sketch to use the Adafruit_GFX library
  22.   // tft.drawRGBBitmap(x, y, bitmap, w, h);
  23.   // Return 1 to decode next block
  24.   return 1;
  25. }
  26. #define EEPROM_SIZE 1
  27. int pictureNumber = 0;
  28. unsigned long times = 0;
  29. unsigned long timess = 0;
  30. DFRobot_AXP313A axp;
  31. #define FORWARD 1
  32. #define BACKWARD -1
  33. #define PWDN_GPIO_NUM -1
  34. #define RESET_GPIO_NUM -1
  35. #define XCLK_GPIO_NUM 45
  36. #define SIOD_GPIO_NUM 1
  37. #define SIOC_GPIO_NUM 2
  38. #define Y9_GPIO_NUM 48
  39. #define Y8_GPIO_NUM 46
  40. #define Y7_GPIO_NUM 8
  41. #define Y6_GPIO_NUM 7
  42. #define Y5_GPIO_NUM 4
  43. #define Y4_GPIO_NUM 41
  44. #define Y3_GPIO_NUM 40
  45. #define Y2_GPIO_NUM 39
  46. #define VSYNC_GPIO_NUM 6
  47. #define HREF_GPIO_NUM 42
  48. #define PCLK_GPIO_NUM 5
  49. void setupCamera() {
  50.   while (axp.begin() != 0) {
  51.     Serial.println("init error");
  52.     delay(1000);
  53.   }
  54.   axp.enableCameraPower(axp.eOV2640);
  55.   camera_config_t config;
  56.   config.ledc_channel = LEDC_CHANNEL_0;
  57.   config.ledc_timer = LEDC_TIMER_0;
  58.   config.pin_d0 = Y2_GPIO_NUM;
  59.   config.pin_d1 = Y3_GPIO_NUM;
  60.   config.pin_d2 = Y4_GPIO_NUM;
  61.   config.pin_d3 = Y5_GPIO_NUM;
  62.   config.pin_d4 = Y6_GPIO_NUM;
  63.   config.pin_d5 = Y7_GPIO_NUM;
  64.   config.pin_d6 = Y8_GPIO_NUM;
  65.   config.pin_d7 = Y9_GPIO_NUM;
  66.   config.pin_xclk = XCLK_GPIO_NUM;
  67.   config.pin_pclk = PCLK_GPIO_NUM;
  68.   config.pin_vsync = VSYNC_GPIO_NUM;
  69.   config.pin_href = HREF_GPIO_NUM;
  70.   config.pin_sscb_sda = SIOD_GPIO_NUM;
  71.   config.pin_sscb_scl = SIOC_GPIO_NUM;
  72.   config.pin_pwdn = PWDN_GPIO_NUM;
  73.   config.pin_reset = RESET_GPIO_NUM;
  74.   config.xclk_freq_hz = 20000000;
  75.   config.frame_size = FRAMESIZE_UXGA;  //FRAMESIZE_HVGA;  //
  76.   config.pixel_format = PIXFORMAT_JPEG;
  77.   config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  78.   config.fb_location = CAMERA_FB_IN_PSRAM;
  79.   config.jpeg_quality = 12;
  80.   config.fb_count = 1;
  81.   if (config.pixel_format == PIXFORMAT_JPEG) {
  82.     if (psramFound()) {
  83.       config.jpeg_quality = 10;
  84.       config.fb_count = 1;
  85.       config.grab_mode = CAMERA_GRAB_LATEST;
  86.     } else {
  87.       config.frame_size = FRAMESIZE_SVGA;
  88.       config.fb_location = CAMERA_FB_IN_DRAM;
  89.     }
  90.   } else {
  91.     config.frame_size = FRAMESIZE_240X240;
  92. #if CONFIG_IDF_TARGET_ESP32S3
  93.     config.fb_count = 2;
  94. #endif
  95.   }
  96.   esp_err_t err = esp_camera_init(&config);
  97.   if (err != ESP_OK) {
  98.     Serial.printf("Camera init failed with error 0x%x", err);
  99.     return;
  100.   }
  101.   if (psramFound()) {
  102.     heap_caps_malloc_extmem_enable(20000);
  103.     Serial.printf("PSRAM initialized. malloc to take memory from psram above this size");
  104.   }
  105. }
  106. void SDinitialization() {
  107.   if (!SD.begin(GDI_SDCS)) {
  108.     Serial.println("Card Mount Failed");
  109.     return;
  110.   }
  111.   uint8_t cardType = SD.cardType();
  112.   if (cardType == CARD_NONE) {
  113.     Serial.println("No SD card attached");
  114.     return;
  115.   }
  116.   Serial.print("SD Card Type: ");
  117.   if (cardType == CARD_MMC) {
  118.     Serial.println("MMC");
  119.   } else if (cardType == CARD_SD) {
  120.     Serial.println("SDSC");
  121.   } else if (cardType == CARD_SDHC) {
  122.     Serial.println("SDHC");
  123.   } else {
  124.     Serial.println("UNKNOWN");
  125.   }
  126.   uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  127.   Serial.printf("SD Card Size: %lluMB\n", cardSize);
  128. }
  129. void tft_init(void) {
  130.   // Initialise the TFT
  131.   tft.begin();
  132.   tft.setTextColor(0xFFFF, 0x0000);
  133.   tft.fillScreen(TFT_BLACK);
  134.   tft.setSwapBytes(true);  // We need to swap the colour bytes (endianess)
  135.   tft.setRotation(1);      // portrait
  136.   // The jpeg image can be scaled by a factor of 1, 2, 4, or 8
  137.   // TJpgDec.setJpgScale(1);//for 480*320
  138.   TJpgDec.setJpgScale(4);  //for 1600*1200
  139.   // The decoder must be given the exact name of the rendering function above
  140.   TJpgDec.setCallback(tft_output);
  141. }
  142. void setup(void) {
  143.   Serial.begin(115200);
  144.   // Set all chip selects high to avoid bus contention during initialisation of each peripheral
  145.   pinMode(GDI_CS, OUTPUT);
  146.   pinMode(GDI_TCS, OUTPUT);
  147.   pinMode(GDI_SDCS, OUTPUT);
  148.   digitalWrite(GDI_TCS, HIGH);   // Touch controller chip select (if used)
  149.   digitalWrite(GDI_CS, HIGH);    // TFT screen chip select
  150.   digitalWrite(GDI_SDCS, HIGH);  // SD card chips select, must use GPIO 5 (ESP32 SS)
  151.   setupCamera();
  152.   SDinitialization();
  153.   tft_init();
  154.   EEPROM.begin(EEPROM_SIZE);
  155.   EEPROM.write(0, pictureNumber);
  156.   EEPROM.commit();
  157. }
  158. void Imagestorage() {
  159.   camera_fb_t *fb = NULL;
  160.   fb = esp_camera_fb_get();
  161.   if (!fb) {
  162.     Serial.println("Camera capture failed");
  163.     return;
  164.   }
  165.   EEPROM.begin(EEPROM_SIZE);
  166.   pictureNumber = EEPROM.read(0) + 1;
  167.   String path = "/picture" + String(pictureNumber) + ".jpg";
  168.   //////////////////////////////////////////////////////////////////////////////////////////////////////////
  169.   tft.fillScreen(TFT_RED);
  170.   // Time recorded for test purposes
  171.   uint32_t t = millis();
  172.   // Get the width and height in pixels of the jpeg if you wish
  173.   uint16_t w = 0, h = 0;
  174.   TJpgDec.getJpgSize(&w, &h, fb->buf, fb->len);
  175.   Serial.print("Width = ");
  176.   Serial.print(w);
  177.   Serial.print(", height = ");
  178.   Serial.println(h);
  179.   // Draw the image, top left at 0,0
  180.   TJpgDec.drawJpg(0, 0, fb->buf, fb->len);
  181.   // How much time did rendering take (ESP8266 80MHz 262ms, 160MHz 149ms, ESP32 SPI 111ms, 8bit parallel 90ms
  182.   t = millis() - t;
  183.   Serial.print(t);
  184.   Serial.println(" ms");
  185.   tft.drawString(path.c_str() + 1, 0, 290, 4);
  186.   //////////////////////////////////////////////////////////////////////////////////////////////////////////
  187.   fs::FS &fs = SD;
  188.   Serial.printf("Picture file name: %s\n", path.c_str());
  189.   File file = fs.open(path.c_str(), FILE_WRITE);
  190.   if (!file) {
  191.     Serial.println("Failed to open file in writing mode");
  192.   } else {
  193.     file.write(fb->buf, fb->len);
  194.     Serial.printf("Saved file to path: %s\n", path.c_str());
  195.     EEPROM.write(0, pictureNumber);
  196.     EEPROM.commit();
  197.   }
  198.   file.close();
  199.   esp_camera_fb_return(fb);
  200. }
  201. void loop() {
  202.   delay(2000);
  203.   Imagestorage();
  204.   times++;
  205.   if (times > 9) {
  206.     Serial.println("finished!");
  207.     while (1)
  208.       ;
  209.   }
  210. }

整个过程视频如下。

拍照存卡

更多回帖

发帖
×
20
完善资料,
赚取积分