这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 成果贴-电子测光表的基础功能和扩展功能展示

共1条 1/1 1 跳转至

成果贴-电子测光表的基础功能和扩展功能展示

菜鸟
2024-12-01 18:07:42     打赏

电子测光表的成果展示视频见B站:https://www.bilibili.com/video/BV144zdYgEeK?t=150.1


image.png

-----------------------------------------------------------------------------------------------------------------------------

视频的前4分钟是基础功能,通过按键可设置电子测光表的曝光时间(Exposure Time)、光圈值(Aperture Value)以及感光度(ISO, sensitivity), 通过这三个数据,程序可计算住曝光值(Exposure Valuie), 光照度传感器采集到的环境光照度值(Illuminance)。 这5个数据都显示在LCD显示屏上,如下图所示。

a12df6f9f7335b3283cf2551ff690f1.png

当环境光照度值大于所设置的曝光照度值时,舵机会旋转,带动压杆压着蓝色按钮,蓝色按钮被按下,微处理器板上的LCD灯亮,模拟了照相快门按下的功能。

---------------------------------------------------------------------------------------------------------------------------------

视频的后半部分(第4分钟后)展示的是网络控制和显示功能。

在网络端用的是io.adafruit.com网站提供的网页开发环境,利用该开发环境可以通过拖拽的方法进行简单的图形界面的编程,实现与边缘端设备的通信。

测光表上显示的光照度值每隔10秒钟通过MQTT协议发送一次,传输到网络上,手机接受网络上的数据,同步的显示在屏幕上。

image.png

手机端的三个滑杆可以设置曝光时间(Exposure Time)、光圈值(Aperture Value)以及感光度(ISO, sensitivity),并将这些数据发送到测光表上。

在测光表上计算出来的曝光照度值,也能够显示在手机屏幕上

1733047339706.png

在电脑端也可以控制电子测光表:

image.png

------------------------------------------------------------------------------------------------------------------------------

code.py的代码:

import time
import ssl
import os
from random import randint
import microcontroller
import socketpool
import wifi
import board
import neopixel
import adafruit_minimqtt.adafruit_minimqtt as MQTT
from adafruit_io.adafruit_io import IO_MQTT
import displayio
import terminalio
from adafruit_display_text.text_box import TextBox
import adafruit_bh1750
from digitalio import DigitalInOut, Direction, Pull
import pwmio
from adafruit_motor import servo
# create a PWMOut object on the control pin.
pwm = pwmio.PWMOut(board.D5, duty_cycle=0, frequency=50)
servo = servo.Servo(pwm)
# aperture value
AV_value = (1, 1.4, 2, 2.8, 4, 5.6, 8, 11, 16, 22, 32)
#exposure time
TV_value = (1, 1/2, 1/4, 1/8, 1/15, 1/30, 1/60, 1/125, 1/250, 1/500, 1/1000)
#sensitivity or ISO
SV_value = (100, 200, 400, 800, 1600, 3200, 6400, 12800, 25600)
#exposure value
EV_value = (2.5, 5, 10, 20, 40, 80, 160, 320, 640, 1280, 2560)
TV_index = 3
SV_index = 0
AV_index = 2
pre_TV_index = 3
pre_SV_index = 0
pre_AV_index = 2
EV_index = 5
#actinometer part
i2c = board.I2C()  # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller
sensor = adafruit_bh1750.BH1750(i2c)
print("%.2f Lux" % sensor.lux)
# LED setup.
led = DigitalInOut(board.LED)
# For QT Py M0. QT Py M0 does not have a D13 LED, so you can connect an external LED instead.
# led = DigitalInOut(board.SCK)
led.direction = Direction.OUTPUT
# For Gemma M0, Trinket M0, Metro M0 Express, ItsyBitsy M0 Express, Itsy M4 Express, QT Py M0
switch_red = DigitalInOut(board.D1)
switch_red.direction = Direction.INPUT
switch_red.pull = Pull.UP
switch_blue = DigitalInOut(board.D2)
switch_blue.direction = Direction.INPUT
switch_blue.pull = Pull.UP
main_group = displayio.Group()
#TV_value_text = "Exposure Time"
TV_value_text = "Exposure Time"
UpperLeft_text_area = TextBox(
    terminalio.FONT,
    110,
    30,
    align=TextBox.ALIGN_CENTER,
    text=TV_value_text,
    background_color=0xFF00FF,
    color=0x000000,
    scale=1,
)
UpperLeft_text_area.x = 0
UpperLeft_text_area.y = 10
main_group.append(UpperLeft_text_area)
#AV_value_text = "Aperture Value"
AV_value_text = "Aperture Value"
UpperRight_text_area = TextBox(
    terminalio.FONT,
    110,
    30,
    align=TextBox.ALIGN_CENTER,
    text=AV_value_text,
    background_color=0xFF00FF,
    color=0x000000,
    scale=1,
)
UpperRight_text_area.x = 130
UpperRight_text_area.y = 10
main_group.append(UpperRight_text_area)
#ISO_value_text = "ISO"
ISO_value_text = "ISO:\n 100"
MidLeft_text_area = TextBox(
    terminalio.FONT,
    110,
    30,
    align=TextBox.ALIGN_CENTER,
    text=ISO_value_text,
    background_color=0xFF00FF,
    color=0x000000,
    scale=1,
)
MidLeft_text_area.x = 0
MidLeft_text_area.y = 50
main_group.append(MidLeft_text_area)
#EV_value_text = "Exposure Value"
EV_value_text = "Exposure Value"
MidRight_text_area = TextBox(
    terminalio.FONT,
    110,
    30,
    align=TextBox.ALIGN_CENTER,
    text=EV_value_text,
    background_color=0xFFFF00,
    color=0x000000,
    scale=1,
)
MidRight_text_area.x = 130
MidRight_text_area.y = 50
main_group.append(MidRight_text_area)
#ISO_value_text = "Illuminance"
Illuminance_value_text = "Illuminance"
BottomLeft_text_area = TextBox(
    terminalio.FONT,
    110,
    30,
    align=TextBox.ALIGN_CENTER,
    text=Illuminance_value_text,
    background_color=0x00FFFF,
    color=0x000000,
    scale=1,
)
BottomLeft_text_area.x = 0
BottomLeft_text_area.y = 90
main_group.append(BottomLeft_text_area)
# #EV_value_text = "Exposure Value"
# EV_value_text = "Exposure Value"
# BottomRight_text_area = TextBox(
#     terminalio.FONT,
#     110,
#     30,
#     align=TextBox.ALIGN_CENTER,
#     text=EV_value_text,
#     background_color=0xFFFF00,
#     color=0x000000,
#     scale=1,
# )
# 
# BottomRight_text_area.x = 130
# BottomRight_text_area.y = 90
# main_group.append(BottomRight_text_area)
board.DISPLAY.root_group = main_group
# WiFi
try:
    print("Connecting to %s" % os.getenv("CIRCUITPY_WIFI_SSID"))
    wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
    print("Connected to %s!" % os.getenv("CIRCUITPY_WIFI_SSID"))
# Wi-Fi connectivity fails with error messages, not specific errors, so this except is broad.
except Exception as e:  # pylint: disable=broad-except
    print("Failed to connect to WiFi. Error:", e, "\nBoard will hard reset in 30 seconds.")
    time.sleep(30)
    microcontroller.reset()
# Initialise NeoPixel
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.3)
# Define callback functions which will be called when certain events happen.
def connected(client):
    print("Connected to Adafruit IO!  Listening for NeoPixel changes...")
    # Subscribe to Adafruit IO feed called "neopixel"
    client.subscribe("neopixel")
    client.subscribe("TV")
    client.subscribe("SV")
    client.subscribe("AV")
def message(client, feed_id, payload):  # pylint: disable=unused-argument
    """
    函数功能:
    根据不同的feed_id处理接收到的payload,并更新相应的界面文本区域显示以及记录相关索引值。
    参数说明:
    - client:当前未在函数内使用,可能后续会用到或者是符合接口规范传入的参数。
    - feed_id:用于标识消息来源的字符串,取值可能为"TV"、"SV"、"AV"等,用于区分不同类型的数据。
    - payload:承载具体数据内容的对象,在函数内会尝试转换为整数作为索引去获取对应_value列表中的元素。
    """
    global TV_index
    global SV_index
    global AV_index
    global EV_index    
    try:
        payload_as_int = int(payload)
    except ValueError:
        print(f"无法将payload {payload} 转换为整数,跳过当前处理步骤。")
        return
    if feed_id == "TV":
        """
        处理feed_id为"TV"的情况:
        1. 打印接收到新值的提示信息。
        2. 更新UpperLeft_text_area的文本内容。
        3. 记录TV_index的值。
        """
        try:
            print("Feed {0} received new value: {1}".format(feed_id, TV_value[payload_as_int]))
            UpperLeft_text_area.text = "{0}:\n {1} - {2}s".format(feed_id, payload_as_int, TV_value[payload_as_int])
            TV_index = payload_as_int
        except IndexError:
            print(f"索引 {payload_as_int} 超出TV_value列表范围,跳过更新操作。")
    elif feed_id == "SV":
        """
        处理feed_id为"SV"的情况:
        1. 打印接收到新值的提示信息。
        2. 更新MidLeft_text_area的文本内容。
        3. 记录SV_index的值。
        """
        try:
            print("Feed {0} received new value: {1}".format(feed_id, SV_value[payload_as_int]))
            MidLeft_text_area.text = "{0}:\n {1} - ISO{2}".format(feed_id, payload_as_int, SV_value[payload_as_int])
            SV_index = payload_as_int
        except IndexError:
            print(f"索引 {payload_as_int} 超出SV_value列表范围,跳过更新操作。")
    elif feed_id == "AV":
        """
        处理feed_id为"AV"的情况:
        1. 打印接收到新值的提示信息。
        2. 更新UpperRight_text_area的文本内容。
        3. 记录AV_index的值。
        """
        try:
            print("Feed {0} received new value: {1}".format(feed_id, AV_value[payload_as_int]))
            UpperRight_text_area.text = "{0}:\n {1} - F/{2}".format(feed_id, payload_as_int, AV_value[payload_as_int])
            AV_index = payload_as_int
        except IndexError:
            print(f"索引 {payload_as_int} 超出AV_value列表范围,跳过更新操作。")
#     # 确保前面的索引变量都已正确赋值(非默认值)后再进行计算和更新MidRight_text_area的文本内容
#     if TV_index!= -1 and SV_index!= -1 and AV_index!= -1:
#         try:
#             EV_index = TV_index + AV_index - SV_index
#             if EV_index < 0:
#                 EV_index = 0
#             elif EV_index >= len(EV_value):
#                 EV_index = len(EV_value) - 1
#             MidRight_text_area.text = "Exposure Value : {}Lux".format(EV_value[EV_index])
#         except IndexError:
#             print(f"计算得到的索引 {TV_index + AV_index - SV_index} 超出EV_value列表范围,跳过更新操作。")
#     else:
#         print("部分索引变量未正确赋值,无法更新MidRight_text_area的文本内容。")
# Create a socket pool
pool = socketpool.SocketPool(wifi.radio)
# Initialize a new MQTT Client object
mqtt_client = MQTT.MQTT(
    broker="io.adafruit.com",
    username=os.getenv("ADAFRUIT_AIO_USERNAME"),
    password=os.getenv("ADAFRUIT_AIO_KEY"),
    socket_pool=pool,
    ssl_context=ssl.create_default_context(),
)
# Initialize Adafruit IO MQTT "helper"
io = IO_MQTT(mqtt_client)
# Set up the callback methods above
io.on_connect = connected
io.on_message = message
timestamp = 0
red_pre_value = True
blue_pre_value = True
red_current_value = True
blue_current_value = True
while True:
    try:
        # If Adafruit IO is not connected...
        if not io.is_connected:
            # Connect the client to the MQTT broker.
            print("Connecting to Adafruit IO...")
            io.connect()
        # Explicitly pump the message loop.
        io.loop()
        if (time.monotonic() - timestamp) >= 10:
            print("%.2f Lux" % sensor.lux)                               
            io.publish("bv", "%.2f Lux" % sensor.lux)
            io.publish("actinometer.ev", str(AV_index + TV_index - SV_index))
            print("AV_index: {0}; TV_index: {1}; SV_index: {2}; EV_index: {3}".format(AV_index, TV_index, SV_index, EV_index))
            BottomLeft_text_area.text = "Illuminance:/n %.2f Lux" % sensor.lux
            timestamp = time.monotonic()
        red_current_value = switch_red.value
        if red_pre_value and not red_current_value:
            if  AV_index >= len(AV_value) -1:
                AV_index = 0
            else : 
                AV_index += 1
            UpperRight_text_area.text = "Aperture Value:\n {0}  F/{1}".format(AV_index, AV_value[AV_index])    
            print("AV_index: {0}; TV_index: {1}; SV_index: {2}".format(AV_index, TV_index, SV_index))    
        red_pre_value = red_current_value
        blue_current_value = switch_blue.value
        if blue_pre_value and not blue_current_value:
            if  TV_index >= len(TV_value) -1:
                TV_index = 0
            else : 
                TV_index += 1
            UpperLeft_text_area.text = "Exposure Time:\n {0}s".format(TV_index, TV_value[TV_index])
            print("AV_index: {0}; TV_index: {1}; SV_index: {2}".format(AV_index, TV_index, SV_index))    
        blue_pre_value = blue_current_value
        time.sleep(0.01)
        
        # 确保前面的索引变量都已正确赋值(非默认值)后再进行计算和更新MidRight_text_area的文本内容
        if TV_index!= pre_TV_index or SV_index!= pre_SV_index or AV_index!= pre_AV_index:
            pre_TV_index = TV_index
            pre_SV_index = SV_index
            pre_AV_index = AV_index
            try:
                EV_index = TV_index + AV_index - SV_index
                if EV_index < 0:
                    EV_index = 0
                elif EV_index >= len(EV_value):
                    EV_index = len(EV_value) - 1
                MidRight_text_area.text = "Exposure Value : {}Lux".format(EV_value[EV_index])
            except IndexError:
                print(f"计算得到的索引 {TV_index + AV_index - SV_index} 超出EV_value列表范围,跳过更新操作。")
        
        if sensor.lux > EV_value[EV_index]:
            print("Sweep from 0 to 1.0 fractionally")
            fraction = 0.0
            while fraction < 1.0:
                servo.fraction = fraction
                fraction += 0.01
                time.sleep(0.01)
                
        if switch_blue.value:
            led.value = False
        else:
            led.value = True
           
    # Adafruit IO fails with internal error types and WiFi fails with specific messages.
    # This except is broad to handle any possible failure.
    except Exception as e:  # pylint: disable=broad-except
        print("Failed to get or send data, or connect. Error:", e,
              "\nBoard will hard reset in 30 seconds.")
        time.sleep(30)
        microcontroller.reset()






--------------------------------------------------------

参考链接:

过程贴-软件调试篇-电子产品世界论坛

过程贴-硬件装配-电子产品世界论坛

电子测光仪DIY过程贴,硬件设计篇-电子产品世界论坛

电子测光表DIY开箱贴-电子产品世界论坛





关键词: 电子     测光     基础     扩展     功能     展示     CIRCUIT    

共1条 1/1 1 跳转至

回复

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