电子测光表的成果展示视频见B站:https://www.bilibili.com/video/BV144zdYgEeK?t=150.1
-----------------------------------------------------------------------------------------------------------------------------
视频的前4分钟是基础功能,通过按键可设置电子测光表的曝光时间(Exposure Time)、光圈值(Aperture Value)以及感光度(ISO, sensitivity), 通过这三个数据,程序可计算住曝光值(Exposure Valuie), 光照度传感器采集到的环境光照度值(Illuminance)。 这5个数据都显示在LCD显示屏上,如下图所示。
当环境光照度值大于所设置的曝光照度值时,舵机会旋转,带动压杆压着蓝色按钮,蓝色按钮被按下,微处理器板上的LCD灯亮,模拟了照相快门按下的功能。
---------------------------------------------------------------------------------------------------------------------------------
视频的后半部分(第4分钟后)展示的是网络控制和显示功能。
在网络端用的是io.adafruit.com网站提供的网页开发环境,利用该开发环境可以通过拖拽的方法进行简单的图形界面的编程,实现与边缘端设备的通信。
测光表上显示的光照度值每隔10秒钟通过MQTT协议发送一次,传输到网络上,手机接受网络上的数据,同步的显示在屏幕上。
手机端的三个滑杆可以设置曝光时间(Exposure Time)、光圈值(Aperture Value)以及感光度(ISO, sensitivity),并将这些数据发送到测光表上。
在测光表上计算出来的曝光照度值,也能够显示在手机屏幕上
在电脑端也可以控制电子测光表:
------------------------------------------------------------------------------------------------------------------------------
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()
--------------------------------------------------------
参考链接: