合宙ESP32 S3 板载16M flash,8m psram和一个FPC相机接口,价格却不到30元,无疑比价格将近50元的第三方ESP32 S3和将近30的ESP32 Cam更具性价比。
但是虽然板载FPC,由于接口冲突,导致相机与psram不能同时开启,作为ESP32 Cam的替代品来看,还缺少了板载SD卡,而且作为一块发布不久的开发板,网上资料资料非常少,甚至连乐鑫的ESP32 S3开发板关于如何用Arduino配置连接SD卡模块的资料都很少。
但是经过多次试错终于发现了连接方法,Arduino ESP32中默认使用VSPI模式连接,而且官方示例中也没有怎么定义引脚,但是S3中用VSPI模式连接会报错,只能用HSPI连接
//SDCard
#include <SD.h>
#include <SPI.h>
SPIClass sdSPI(HSPI); // 使用vspi模式会报错
#define SD_MISO 17
#define SD_MOSI 16
#define SD_SCLK 18
#define SD_CS 14
void SDCheck() { // 测试SD卡连接
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE)
{
Serial.println("未连接存储卡");
return;
}
else 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("挂载了未知存储卡");
}
Serial.printf("存储卡总大小是: %lluMB \n", SD.cardSize() / (1024 * 1024)); // "/ (1024 * 1024)"可以换成">> 20"
Serial.printf("文件系统总大小是: %lluB \n", SD.totalBytes());
Serial.printf("文件系统已用大小是: %lluB \n", SD.usedBytes());
}
void setup() {
bool SDstart = false;
Serial.begin(115200);
sdSPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS);
if (!SD.begin(SD_CS, sdSPI))
{
Serial.println("存储卡挂载失败");
return;
}
SDCheck();
相机部分配置:
//Cam
#include "esp_camera.h"
#include "esp_timer.h"
#include "soc/soc.h" // Disable brownour problems
#include "soc/rtc_cntl_reg.h" // Disable brownour problems
//cam gpio
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 39
#define SIOD_GPIO_NUM 21
#define SIOC_GPIO_NUM 46
#define Y2_GPIO_NUM 34
#define Y3_GPIO_NUM 47
#define Y4_GPIO_NUM 48
#define Y5_GPIO_NUM 33
#define Y6_GPIO_NUM 35
#define Y7_GPIO_NUM 37
#define Y8_GPIO_NUM 38
#define Y9_GPIO_NUM 40
#define VSYNC_GPIO_NUM 42
#define HREF_GPIO_NUM 41
#define PCLK_GPIO_NUM 36
void setup() { // 相机配置
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_sccb_sda = SIOD_GPIO_NUM;
config.pin_sccb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.frame_size = FRAMESIZE_SVGA;
config.pixel_format = PIXFORMAT_JPEG;
// config.grab_mode = CAMERA_GRAB_LATEST;
config.grab_mode = config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_DRAM;
config.jpeg_quality = 30;
config.fb_count = 1; // 没有psram建议写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;
}
}
获取图片帧函数:
void getimg(){
camera_fb_t *fb = NULL;
fb = esp_camera_fb_get();
// if (!fb)
// {
// Serial.println("Camera capture failed");
// return;
// }
// else
// {
// Serial.println("Camera Captured");
// }
String filePath = dirPath + "/" + String(count) + ".jpg";
// Serial.println(filePath);
File file = SD.open(filePath,FILE_WRITE);
if(file){
file.write(fb->buf,fb -> len);
}
file.close();
count ++;
esp_camera_fb_return(fb);
fb = NULL;
}
SD卡中文件夹存储代码,合宙这块板貌似没有板载RTC,获取不了准确的时间,而且不连接WiFi,所以只能计数命名文章来源:https://www.toymoban.com/news/detail-766614.html
void setup() {
bool SDstart = false;
Serial.begin(115200);
sdSPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS);
if (!SD.begin(SD_CS, sdSPI))
{
Serial.println("存储卡挂载失败");
return;
}else{
while (!SD.exists("/Camera")) {
SD.mkdir("/Camera");
SDstart = true;
Serial.print(".");
}
if(!SPIFFS.begin()){
Serial.println("mount SPIFFS failed!");
}else {
if(!SPIFFS.exists("/Statue")){
SPIFFS.mkdir("/Statue");
File file = SPIFFS.open("/Statue",FILE_WRITE);
file.write(1);
file.close();
}
File file = SPIFFS.open("/Statue",FILE_READ);
if(file.read() == 1){
file = SPIFFS.open("/Statue",FILE_WRITE);
file.write(0);
file.close();
Serial.println("start");
} else {
file = SPIFFS.open("/Statue",FILE_WRITE);
file.write(1);
file.close();
Serial.println("stop");
while (1);
}
if(SDstart == true){
file = SPIFFS.open("/count.txt",FILE_WRITE);
file.println("1");
file.close();
}else{
if(!SPIFFS.exists("/count.txt")){
Serial.println("create file Success!");
file = SPIFFS.open("/count.txt",FILE_WRITE);
file.println((String)fileCount);
Serial.println(fileCount);
file.close();
}else{
Serial.println("file exist!");
File file = SPIFFS.open("/count.txt",FILE_READ);
fileCount = atoi(file.readStringUntil('\n').c_str());
file.close();
Serial.println(fileCount);
file = SPIFFS.open("/count.txt",FILE_WRITE);
file.println(String(++fileCount));
file.close();
}
}
}
SPIFFS.end();
dirPath = "/Camera/" + (String)fileCount;
while (!SD.exists(dirPath.c_str())) {
SD.mkdir(dirPath.c_str());
Serial.print(".");
}
}
完整代码:文章来源地址https://www.toymoban.com/news/detail-766614.html
//SDCard
#include <SD.h>
#include <SPI.h>
//File
#include "SPIFFS.h"
//Cam
#include "esp_camera.h"
#include "esp_timer.h"
#include "soc/soc.h" // Disable brownour problems
#include "soc/rtc_cntl_reg.h" // Disable brownour problems
SPIClass sdSPI(HSPI);
#define SD_MISO 17
#define SD_MOSI 16
#define SD_SCLK 18
#define SD_CS 14
//cam gpio
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 39
#define SIOD_GPIO_NUM 21
#define SIOC_GPIO_NUM 46
#define Y2_GPIO_NUM 34
#define Y3_GPIO_NUM 47
#define Y4_GPIO_NUM 48
#define Y5_GPIO_NUM 33
#define Y6_GPIO_NUM 35
#define Y7_GPIO_NUM 37
#define Y8_GPIO_NUM 38
#define Y9_GPIO_NUM 40
#define VSYNC_GPIO_NUM 42
#define HREF_GPIO_NUM 41
#define PCLK_GPIO_NUM 36
String dirPath;
uint32_t count = 0;
uint16_t fileCount = 1;
void getimg(){
camera_fb_t *fb = NULL;
fb = esp_camera_fb_get();
String filePath = dirPath + "/" + String(count) + ".jpg";
// Serial.println(filePath);
File file = SD.open(filePath,FILE_WRITE);
if(file){
file.write(fb->buf,fb -> len);
}
file.close();
count ++;
esp_camera_fb_return(fb);
fb = NULL;
}
void setup() {
bool SDstart = false;
Serial.begin(115200);
sdSPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS);
if (!SD.begin(SD_CS, sdSPI))
{
Serial.println("存储卡挂载失败");
return;
}else{
while (!SD.exists("/Camera")) {
SD.mkdir("/Camera");
SDstart = true;
Serial.print(".");
}
if(!SPIFFS.begin()){
Serial.println("mount SPIFFS failed!");
}else {
if(!SPIFFS.exists("/Statue")){
SPIFFS.mkdir("/Statue");
File file = SPIFFS.open("/Statue",FILE_WRITE);
file.write(1);
file.close();
}
File file = SPIFFS.open("/Statue",FILE_READ);
if(file.read() == 1){
file = SPIFFS.open("/Statue",FILE_WRITE);
file.write(0);
file.close();
Serial.println("start");
} else {
file = SPIFFS.open("/Statue",FILE_WRITE);
file.write(1);
file.close();
Serial.println("stop");
while (1);
}
if(SDstart == true){
file = SPIFFS.open("/count.txt",FILE_WRITE);
file.println("1");
file.close();
}else{
if(!SPIFFS.exists("/count.txt")){
Serial.println("create file Success!");
file = SPIFFS.open("/count.txt",FILE_WRITE);
file.println((String)fileCount);
Serial.println(fileCount);
file.close();
}else{
Serial.println("file exist!");
File file = SPIFFS.open("/count.txt",FILE_READ);
fileCount = atoi(file.readStringUntil('\n').c_str());
file.close();
Serial.println(fileCount);
file = SPIFFS.open("/count.txt",FILE_WRITE);
file.println(String(++fileCount));
file.close();
}
}
}
SPIFFS.end();
dirPath = "/Camera/" + (String)fileCount;
while (!SD.exists(dirPath.c_str())) {
SD.mkdir(dirPath.c_str());
Serial.print(".");
}
}
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_sccb_sda = SIOD_GPIO_NUM;
config.pin_sccb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.frame_size = FRAMESIZE_SVGA;
config.pixel_format = PIXFORMAT_JPEG;
config.grab_mode = config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_DRAM;
config.jpeg_quality = 30;
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;
}
}
void loop() {
getimg();
delay(100);
}
到了这里,关于Arduino 合宙 ESP32 S3 + OV2640 实现低成本SD存储卡相机(ESP32连接SD模块引脚)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!