这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » [Let'sDo第3期]DIY一个电子测光表6成果贴

共1条 1/1 1 跳转至

[Let'sDo第3期]DIY一个电子测光表6成果贴

菜鸟
2024-12-02 11:16:40     打赏

[Let'sDo第3期]    DIY一个电子测光表      6成果贴

1733117021979.png                             image.png

很高兴能够参与由Digi-Key得捷电子联合EEPW电子产品世界举办的“Let's Do”活动,这是该系列活动的第三期,主题为DIY一个电子测光表。在这个项目中,我有幸使用了一系列高性能的电子组件,包括搭载了TFT屏幕的ESP32-S3型号5691,以及M5STACK的U136测光模块,以及DFROBOT的SER0049舵机。

这款电子测光表的核心功能是测量光照强度,并将其转换成摄影中的曝光值。通过精确的计算,它能够为摄影师提供在特定光照条件下,拍摄时所需的曝光、光圈和快门参数,从而帮助他们捕捉到理想的画面效果。

我的设计理念是将ESP32-S3 5691的三个内置按钮充分利用,实现三种不同的操作模式。第一个按钮用于启动本地测量模式,用户可以直接在设备的TFT屏幕上查看实时的光照强度数据。第二个按钮则允许用户暂停测量,短按和长按分别是调整光圈值(AV)、快门速度(TV),以便在需要时进行短暂的数据查看或分析。而第三个按钮则启动远程测量模式,通过Wi-Fi连接,用户可以在网页端实时查看测量数据以及计算得出的各项摄影参数。

在TFT屏幕上,用户可以直观地看到光照强度(LUX)、曝光值(EV)、光圈值(AV)、快门速度(TV)以及感光度(SV)。这些参数的实时显示,为用户提供了一个便捷的工具,无论是在户外摄影还是室内布光,都能够快速调整相机设置,以获得最佳的拍摄效果。

此外,通过远程测量功能,用户还可以在远离设备的地方监控光照变化,这对于需要长时间曝光或在复杂光照条件下工作的摄影师来说,无疑是一个巨大的便利。这种远程监控和控制的能力,使得电子测光表不仅是一款实用的工具,更是一个创新的解决方案,它将摄影技术与现代电子技术完美融合。

总的来说,这个项目不仅让我深入探索了电子工程的奥秘,也让我对摄影艺术有了更深的理解。我期待这个电子测光表能够成为摄影师和电子爱好者的得力助手,帮助他们在光影的世界里,捕捉每一个精彩瞬间。

 

以下为参加此次活动的记录贴,一步一步实现了我的预期目标:


https://forum.eepw.com.cn/thread/387676/1    

[Let'sDo第3期]     DIY一个电子测光表1开箱帖

https://forum.eepw.com.cn/thread/387677/1    

[Let'sDo第3期]     DIY一个电子测光表2过程贴(测试)

https://forum.eepw.com.cn/thread/387973/1    

[Let'sDo第3期]     DIY一个电子测光表3过程贴(wifi联网)

https://forum.eepw.com.cn/thread/388003/1    

[Let'sDo第3期]     DIY一个电子测光表4过程贴(屏幕显示)

https://forum.eepw.com.cn/thread/388145/1    

[Let'sDo第3期]     DIY一个电子测光表5过程贴(原理说明)


以下为最终演示视频

image.png


以下为项目代码     

# 导入所需的库
import board
import digitalio
import wifi
import socketpool
from adafruit_motor import servo
from adafruit_bh1750 import BH1750
import pwmio
import time
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import label
import displayio
import adafruit_bh1750
import math

# 定义曝光值列表
AV = [1, 1.4, 2, 2.8, 4, 5.6, 8, 11, 16, 22, 32]
TV = [1, 0.5, 0.25, 0.125, 0.0667, 0.0333, 0.0167, 0.0083, 0.0042, 0.0021, 0.0011]
SV = [100, 200, 400, 800, 1600]

# 初始化曝光指数和ISO值
lux = 1000
svIndex = 0
avIndex = 5
tvIndex = 0

# 计算曝光值(EV)的函数
def calculate_ev(lux):
    return round(2 + math.log(lux / 10) / math.log(2))

# 更新相机设置的函数
def update_settings(lux, svIndex, avIndex, tvIndex, press_time):
    ev = calculate_ev(lux)
    total_index = ev + svIndex
    
    if press_time == 'long_press':
        tvIndex = (tvIndex + 1) % len(TV)
        avIndex = (avIndex + total_index - tvIndex) % len(AV)
    elif press_time == 'short_press':
        avIndex = (avIndex + 1) % len(AV)
        tvIndex = (tvIndex + total_index - avIndex) % len(TV)
    
    return avIndex, tvIndex

# 显示相机设置的函数
def display_settings(lux, avIndex, tvIndex, svIndex):
    print("\nCurrent Settings:")
    print("")
    print(f"EV: {calculate_ev(lux):.1f}")
    print(f"ISO (SV): {SV[svIndex]}")
    print(f"Aperture (AV): {AV[avIndex]}")
    print(f"Shutter Speed (TV): {TV[tvIndex]}")
    text_light.text = f"(LUX): {lux:.1f}\n(EV): {calculate_ev(lux):.1f}\n(SV): {SV[svIndex]}\n(AV): {AV[avIndex]}\n(TV): {TV[tvIndex]}"
    display.refresh()

# 初始化I2C接口和光照传感器
i2c = board.I2C()
light_sensor = adafruit_bh1750.BH1750(i2c)

# 初始化显示参数
display = board.DISPLAY
display.brightness = 0.75
display.rotation = 90

# 加载字体
font = bitmap_font.load_font("LeagueSpartan-Bold-16.bdf")
color_FireBrick = 0xB22222

# WiFi凭证
SSID = 'username'
PASSWORD = 'password'

# LED设置
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT

# 伺服电机设置
pwm = pwmio.PWMOut(board.A0, duty_cycle=2 ** 15, frequency=50)
servo_motor = servo.Servo(pwm)

# 按钮设置
key0 = digitalio.DigitalInOut(board.D0)
key0.direction = digitalio.Direction.INPUT
key0.pull = digitalio.Pull.UP

key1 = digitalio.DigitalInOut(board.D1)
key1.direction = digitalio.Direction.INPUT
key1.pull = digitalio.Pull.DOWN

key2 = digitalio.DigitalInOut(board.D2)
key2.direction = digitalio.Direction.INPUT
key2.pull = digitalio.Pull.DOWN

# 全局变量
servo_running = False
current_angle = 0
mode = "normal"  # 可以是 "normal", "stop", 或 "wifi"

# 常量
BUFFER_SIZE = 512
MAX_RETRIES = 3
RETRY_DELAY = 0.1

# 加载字体
font = bitmap_font.load_font("LeagueSpartan-Bold-16.bdf")
color_GREEN = 0x005000
color_RED = 0x500000

# 创建文本标签
text_main = label.Label(
    font=font,
    text="  LIGHT TEST",
    x=2,
    y=20,
    color=color_GREEN,
)

text_light = label.Label(
    font=font,
    text="",
    x=2,
    y=60,
    color=color_RED,
)

show_group = displayio.Group()
show_group.append(text_main)
show_group.append(text_light)
display.root_group = show_group

current_angle=90

angle_direction=5

# 连接WiFi的函数
def connect_wifi():
    print("Connecting to WiFi...")
    text_main.text = "Connecting..."
    wifi.radio.connect(SSID, PASSWORD)
    print("Connected to WiFi")
    print("IP Address:", wifi.radio.ipv4_address)
    text_main.text = "IP: " + str(wifi.radio.ipv4_address)
    return socketpool.SocketPool(wifi.radio)

# 将伺服电机移动到90度的函数
def move_servo_to_90():
    global current_angle
    start_angle = current_angle
    for angle in range(start_angle, 91, 1 if start_angle < 90 else -1):
        servo_motor.angle = angle
        current_angle = angle
        time.sleep(0.01)

# 运行伺服电机的函数
def running():
    global current_angle, angle_direction, light_sensor
    if current_angle >= 180:
        angle_direction = -5
    elif current_angle <= 0:
        angle_direction = 5

    current_angle += angle_direction
    servo_motor.angle = current_angle

    light_level = light_sensor.lux
    display_settings(lux, avIndex, tvIndex, svIndex)

# 长按阈值
LONG_PRESS_THRESHOLD=0.05

# 处理按钮按压的函数
def handle_button_press():
    global servo_running, mode, lux, svIndex, avIndex, tvIndex
    if not key0.value:
        servo_running = True
        mode = "Running"
        print("Running Mode")
        running()
        text_main.text = "   TESTING"
    elif key1.value:
        start_time = time.time()
        while key1.value:
            current_time = time.time()
            if current_time - start_time > LONG_PRESS_THRESHOLD:
                text_main.text = "  Ajust TV"
                press_time = "long_press"
                avIndex, tvIndex = update_settings(lux, svIndex, avIndex, tvIndex, press_time)
                display_settings(lux, avIndex, tvIndex, svIndex)
                break
            elif not key1.value:
                text_main.text = "  Ajust AV"
                press_time = "short_press"
                avIndex, tvIndex = update_settings(lux, svIndex, avIndex, tvIndex, press_time)
                display_settings(lux, avIndex, tvIndex, svIndex)
                break
    elif key2.value:
        servo_running = False
        mode = "wifi"
        print("WiFi Mode")
        text_main.text = "WIFI"
        time.sleep(1)
        pool = connect_wifi()
        web_server(pool)

# 处理客户端连接的函数
def handle_client_connection(conn, addr):
    global lux, svIndex, avIndex, tvIndex, press_time
    for _ in range(MAX_RETRIES):
        try:
            request = bytearray(BUFFER_SIZE)
            request_length = conn.recv_into(request)
            if request_length == 0:
                return

            request_text = request[:request_length].decode()
            print(request_text)

            headers = [
                "HTTP/1.1 200 OK",
                "Access-Control-Allow-Origin: *",
                "Access-Control-Allow-Methods: GET",
                "Content-Type: text/plain",
            ]

            if "GET /on" in request_text:
                led.value = True
                response = f"(LUX): {lux:.1f}\n(EV): {calculate_ev(lux):.1f}\n(SV): {SV[svIndex]}\n(AV): {AV[avIndex]}\n(TV): {TV[tvIndex]}"
            elif "GET /off" in request_text:
                led.value = False
                response = "STOP TESTING"
            else:
                response = "Invalid command"

            if mode == "wifi":
                lux = light_sensor.lux
                print(lux)
                press_time = "short_press"
                avIndex, tvIndex = update_settings(lux, svIndex, avIndex, tvIndex, press_time)
                display_settings
            
            # 向HTTP响应头添加内容长度,并构造完整的HTTP响应
            headers.append(f"Content-Length: {len(response)}")
            http_response = "\r\n".join(headers) + "\r\n\r\n" + response
            print(http_response)

            # 带重试机制地发送HTTP响应
            for _ in range(MAX_RETRIES):
                try:
                    conn.send(http_response.encode())
                    return True
                except OSError as e:
                    if e.errno != 11:  # EAGAIN错误码
                        raise
                    time.sleep(RETRY_DELAY)

            return False   

        # 捕获处理客户端时的异常
        except OSError as e:
            if e.errno != 11:  # 如果不是EAGAIN错误码
                print(f"Error handling client: {e}")
                return False
            time.sleep(RETRY_DELAY)

        return False  
        
# 定义web_server函数,用于启动和管理Web服务器
def web_server(pool):
    addr = wifi.radio.ipv4_address    
    print(f"Starting web server at http://{addr}")
    
    with pool.socket() as s:
        s.bind((str(addr), 80))
        s.listen(1)
        
        while True:
            try:
                conn, addr = s.accept()
                print("Client connected from", addr)
                
                try:
                    success = handle_client_connection(conn, addr)
                    if not success:
                        print("Failed to handle client after retries")
                finally:
                    # 始终关闭连接
                    try:
                        conn.close()
                    except OSError:
                        pass
                    
            except OSError as e:
                if e.errno == 11:  # EAGAIN错误码
                    # 下一次accept前小延迟
                    time.sleep(RETRY_DELAY)
                    continue
                print(f"Server error: {e}")
                continue# 定义main函数,作为程序的主入口点
def main():
    global lux, svIndex, avIndex, tvIndex    
    while True:
        lux = light_sensor.lux        
        print(lux)
        handle_button_press()
        time.sleep(0.1)  # 小延迟以避免忙等# 检查是否为主模块,并运行main函数
if __name__ == "__main__":
        main()

   




关键词: 探索     电子     原理    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]