使用杜邦线搭好电路,其中数字光传感器U136负责测光,按键负责调整不同ISO下测光的效果。舵机负责按相机快门,感觉需要做3D打印,打印个支架才比较合适。现在用杜邦线连接,比较乱。由于ESP32-S3评估板,板子上只有一个GND排针,很不方便。这里使用了IIC扩展板,并且将扩展板上的GND焊接出来做了扩展处理,提供给舵机和按键使用。
实现了按键调整ISO值,并且进行测光获得快门值。通过蓝牙上传到手机显示,并且手机可以通过蓝牙控制舵机动作,去按下相机快门。
1、ISO的调整,不同的ISO值,对应着不同的测光模式。这里使用了最常见的几种ISO值,通过红蓝两个按键进行切换。红色按键增加ISO的值,蓝色按键减少ISO的值。
int isoLevels[5] = {100, 200, 400, 500, 1000}; // ISO等级 int offsetiso = 3; // 两个按键 红色的控制ISO增加 蓝色的减少ISO值 void clickRed() { // Serial.println("Red Button click."); offsetiso = offsetiso == 4 ? offsetiso : offsetiso + 1; // Serial.print(offsetiso); // Serial.print(" "); // Serial.println(isoLevels[offsetiso]); } void clickBlue() { offsetiso = offsetiso == 0 ? offsetiso : offsetiso - 1; // Serial.print(offsetiso); // Serial.print(" "); // Serial.println(isoLevels[offsetiso]); }
2、蓝牙功能。将ESP32-S3设置为蓝牙服务端。建立了两个服务,一个是发送信息,通过notify方式,定时(1秒)将测光信息通过蓝牙发送出去,手机端使用的“eFR Connect”,可以从手机端读取到测光信息,并且可以控制舵机拍照。另一个服务是“write”服务,只要有消息从蓝牙上写入,则ESP32-S3端,就会驱动舵机动作,模拟按下快门。
#include <SPI.h> #include <TFT_eSPI.h> #include "OneButton.h" #include <Adafruit_BMP280.h> #include <BH1750.h> #include <BLEDevice.h> #include <BLEUtils.h> #include <BLEServer.h> #include <BLECharacteristic.h> #include <ESP32Servo.h> #define KEYRED 17 #define KEYBLUE 18 #define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" //服务UUID #define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" //特征UUID #define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" BLECharacteristic *pCharacteristic; //创建一个BLE特性pCharacteristic bool deviceConnected = false; //连接否标志位 TFT_eSPI tft = TFT_eSPI(); ///创建屏幕对象 Adafruit_BMP280 bmp; // I2C BH1750 lightMeter(0x23); //光线传感器 float lux = 0, ev = 0, fspeed = 0; int isoLevels[5] = {100, 200, 400, 500, 1000}; // ISO等级 int offsetiso = 3; Servo servo; //舵机驱动 int servoPin = 13; OneButton redButton(KEYRED, true); OneButton blueButtton(KEYBLUE, true); // 两个按键 红色的控制ISO增加 蓝色的减少ISO值 void clickRed() { // Serial.println("Red Button click."); offsetiso = offsetiso == 4 ? offsetiso : offsetiso + 1; // Serial.print(offsetiso); // Serial.print(" "); // Serial.println(isoLevels[offsetiso]); } void clickBlue() { offsetiso = offsetiso == 0 ? offsetiso : offsetiso - 1; // Serial.print(offsetiso); // Serial.print(" "); // Serial.println(isoLevels[offsetiso]); } void tftInit() { pinMode(21, OUTPUT); // TFT电源脚置1 digitalWrite(21, 1); tft.init(); // st7789屏幕初始化 tft.setRotation(1); // 屏幕旋转90度 tft.fillScreen(TFT_BLACK); //全屏填充黑色(即清屏) tft.setTextColor(TFT_WHITE, TFT_BLACK); //设置前景色与背景色 tft.setTextSize(2); } // 计算ev值,曝光 void calc_ev() // f:光圈 { float evWithISO, aperture; if (lightMeter.measurementReady()) { lux = lightMeter.readLightLevel(); //光强 ev = 2.0 + log10(lux / 10.0); //计算曝光 evWithISO = ev - log2(isoLevels[offsetiso] / 100.0); // 根据 ISO 调整 EV 值 // 计算光圈和快门速度 aperture = pow(2, evWithISO - 2); // 初始光圈为 2.8,可根据需要调整 // Serial.print("Aperture: "); // Serial.println(aperture); fspeed = pow(2, log2(aperture * aperture) - ev); //计算快门时间 } } //屏幕显示 测光值 void tft_show() { char buf[120]; snprintf(buf, sizeof(buf), "Light:%.1flux", lux); tft.setCursor(10, 0); //设置坐标开始位置 tft.print(buf); tft.setCursor(10, 30); //设置坐标开始位置 snprintf(buf, sizeof(buf), "ISO:%4d", isoLevels[offsetiso]); tft.print(buf); tft.setCursor(160, 30); //设置坐标开始位置 tft.print("F:2.8"); snprintf(buf, sizeof(buf), "EV:%.2f", ev); tft.setCursor(10, 60); //设置坐标开始位置 tft.print(buf); snprintf(buf, sizeof(buf), "T:%f", fspeed); tft.setCursor(10, 90); //设置坐标开始位置 tft.print(buf); //发送给蓝牙 if (deviceConnected) { snprintf(buf, sizeof(buf), "Light:%.1flux,ISO:%d,ev:%.2f,T:%.4f", lux, isoLevels[offsetiso], ev, fspeed); pCharacteristic->setValue(buf); pCharacteristic->notify(); } } //服务器回调 class MyServerCallbacks : public BLEServerCallbacks { void onConnect(BLEServer *pServer) { deviceConnected = true; }; void onDisconnect(BLEServer *pServer) { deviceConnected = false; } }; //特性回调 class MyCallbacks : public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string rxValue = pCharacteristic->getValue(); if (rxValue.length() > 0) { String rxload = ""; for (int i = 0; i < rxValue.length(); i++) { rxload += (char)rxValue[i]; Serial.print(rxValue[i], HEX); Serial.print(" "); } Serial.println(""); // 收到消息就 驱动舵机拍照 servo.write(90); delay(fspeed*1000); servo.write(0); } } }; void setup(void) { Serial.begin(115200); pinMode(KEYRED, INPUT_PULLUP); pinMode(KEYBLUE, INPUT_PULLUP); redButton.attachClick(clickRed); blueButtton.attachClick(clickBlue); servo.attach(servoPin, 500, 2500); servo.write(0); tftInit(); Wire.begin(); lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE); BLEDevice::init("BLE_ESP32S3"); //创建设备 BLEServer *pServer = BLEDevice::createServer(); //设置为服务器 pServer->setCallbacks(new MyServerCallbacks()); //服务器回调函数设置为MyServerCallbacks BLEService *pService = pServer->createService(SERVICE_UUID); //使用上面的服务UUID创建服务 pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY); pCharacteristic->setValue(""); BLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE); //创建一个(写)特征 类型是写入 pCharacteristic->setCallbacks(new MyCallbacks()); pService->start(); pServer->getAdvertising()->start(); //服务器开始广播 } uint32_t last_time = 0; void loop(void) { redButton.tick(); blueButtton.tick(); if (millis() - last_time > 1000) { last_time = millis(); calc_ev(); tft_show(); } }
源码及效果演示
https://www.bilibili.com/video/BV1eVBQYzEyY/