
使用杜邦线搭好电路,其中数字光传感器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/
EETV视频链接:https://v.eepw.com.cn/video/play/id/16203
我要赚赏金
