合宙ESP32 S3 板載16M flash,8m psram和一個(gè)FPC相機(jī)接口,價(jià)格卻不到30元,無(wú)疑比價(jià)格將近50元的第三方ESP32 S3和將近30的ESP32 Cam更具性價(jià)比。
但是雖然板載FPC,由于接口沖突,導(dǎo)致相機(jī)與psram不能同時(shí)開啟,作為ESP32 Cam的替代品來(lái)看,還缺少了板載SD卡,而且作為一塊發(fā)布不久的開發(fā)板,網(wǎng)上資料資料非常少,甚至連樂鑫的ESP32 S3開發(fā)板關(guān)于如何用Arduino配置連接SD卡模塊的資料都很少。
但是經(jīng)過多次試錯(cuò)終于發(fā)現(xiàn)了連接方法,Arduino ESP32中默認(rèn)使用VSPI模式連接,而且官方示例中也沒有怎么定義引腳,但是S3中用VSPI模式連接會(huì)報(bào)錯(cuò),只能用HSPI連接
//SDCard
#include <SD.h>
#include <SPI.h>
SPIClass sdSPI(HSPI); // 使用vspi模式會(huì)報(bào)錯(cuò)
#define SD_MISO 17
#define SD_MOSI 16
#define SD_SCLK 18
#define SD_CS 14
void SDCheck() { // 測(cè)試SD卡連接
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE)
{
Serial.println("未連接存儲(chǔ)卡");
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("掛載了未知存儲(chǔ)卡");
}
Serial.printf("存儲(chǔ)卡總大小是: %lluMB \n", SD.cardSize() / (1024 * 1024)); // "/ (1024 * 1024)"可以換成">> 20"
Serial.printf("文件系統(tǒng)總大小是: %lluB \n", SD.totalBytes());
Serial.printf("文件系統(tǒng)已用大小是: %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("存儲(chǔ)卡掛載失敗");
return;
}
SDCheck();
?相機(jī)部分配置:
//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() { // 相機(jī)配置
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;
}
}
獲取圖片幀函數(shù):
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卡中文件夾存儲(chǔ)代碼,合宙這塊板貌似沒有板載RTC,獲取不了準(zhǔn)確的時(shí)間,而且不連接WiFi,所以只能計(jì)數(shù)命名文章來(lái)源:http://www.zghlxwxcb.cn/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("存儲(chǔ)卡掛載失敗");
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(".");
}
}
完整代碼:文章來(lái)源地址http://www.zghlxwxcb.cn/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("存儲(chǔ)卡掛載失敗");
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);
}
到了這里,關(guān)于Arduino 合宙 ESP32 S3 + OV2640 實(shí)現(xiàn)低成本SD存儲(chǔ)卡相機(jī)(ESP32連接SD模塊引腳)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!