一、开箱
好开心,看着包裹漂洋过海来看我。我选了 评估板:ESP32-S3评估板;数字光传感器U136;按钮模块U025;还有一个舵机SE0049。
主控板Adafruit ESP32-S3 TFT Feather,使用ESP32S3做主控4 MB Flash + 2 MB of PSRAM。
板子背面有个焊盘空着的,上网查了一下,可以接一个BMP280气压计,强迫症不容忍有空焊盘。动手焊上去。
基础任务1:编程实现按键状态的采集。
按键背面有按键实现的电路图,很简单,就是两个开关,按下就和GND短路,松开就开路。电源部分标注为5V,猜测使用3.3v也是能正常工作的。开关模块使用了一个GROVE接口,GROVE接口线好贵啊,ESP32S3主控板那边没有提供GROVE接口,这里找了个2.0PH接口线,用小刀削一下接头,就能将GROVE转接为杜邦接头了。按这个思路,将开关接到了17、18管脚,电源使用3.3V电源。
使用arduino编程,编程工具使用vscode+platformio。arduino下有针对按键处理的库“OneButton”,使用中断方式检测单击、双击。
#include "OneButton.h" #define KEYRED 17 #define KEYBLUE 18 OneButton redButton(KEYRED, true); OneButton blueButtton(KEYBLUE, true); void clickRed() { Serial.println("Red Button click."); } void doubleclickRed() { Serial.println("Red Button doubleclick."); } void clickBlue() { Serial.println("Blue Button click."); } void doubleclickBlue() { Serial.println("Blue Button doubleclick."); } void setup(void) { Serial.begin(115200); pinMode(KEYRED, INPUT_PULLUP); pinMode(KEYBLUE, INPUT_PULLUP); redButton.attachClick(clickRed); redButton.attachDoubleClick(doubleclickRed); blueButtton.attachClick(clickBlue); blueButtton.attachDoubleClick(doubleclickBlue); } void loop(void) { redButton.tick(); blueButtton.tick(); delay(10); }
基础任务2:编程实现数字光传感器BH1750的数据读取.
这里遇到一个很尬的问题,主控板Adafruit ESP32-S3 TFT Feather的排针中只有一个GND的针脚,接了开关,就没法接数字光传感器BH1750了。只能先拆掉开关了。
首先是硬件连接,数字光传感器BH1750使用杜邦线连接到ESP32S3板子的SCL、SDA针脚。电源使用了3.3v。依旧是使用arduino的库“BH1750”,直接读取BH1750传感器。
[env:adafruit_feather_esp32s3_tft] platform = espressif32 board = adafruit_feather_esp32s3_tft framework = arduino monitor_speed = 115200 upload_speed = 1500000 board_build.f_cpu = 240000000L board_build.f_flash = 80000000L board_build.flash_mode = dio build_flags = -DCORE_DEBUG_LEVEL=3 -Iinclude lib_deps = mathertel/OneButton @ ^2.6.1 claws/BH1750 @ ^1.3.0
#include <BH1750.h> BH1750 lightMeter(0x23); void setup(void) { Serial.begin(115200); Wire.begin(); if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) { Serial.println(F("BH1750 Advanced begin")); } else { Serial.println(F("Error initialising BH1750")); } } void loop(void) { if (lightMeter.measurementReady()) { float lux = lightMeter.readLightLevel(); Serial.print("Light: "); Serial.print(lux); Serial.println(" lx"); } delay(1000); }
基础任务3 基于屏幕驱动函数实现字符的显示,例如显示Hello EEPW & DigiKey;也可显示自己喜欢的名言警句
接下来就是驱动屏幕啦!主控板Adafruit ESP32-S3 TFT Feather带着一块135X240的tft彩色屏幕,这里使用TFT_eSPI库来控制屏幕,使用之前要先修改User_Setup.h文件,用来适应这个开发板上的屏幕。
... #define ST7789_DRIVER //该开发板使用ST7789屏幕驱动 ... #define TFT_WIDTH 135 //定义屏幕的宽和高 #define TFT_HEIGHT 240 ... #define TFT_BL 45 //定义背光控制引脚 ... //定义信号脚,时钟脚,复位脚等其他引脚(查询电路原理https://github.com/adafruit/Adafruit-ESP32-S3-TFT-Feather-PCB图) #define TFT_MISO 37 #define TFT_MOSI 35 #define TFT_SCLK 36 #define TFT_CS 7 // Chip select control pin (library pulls permanently low #define TFT_DC 39// Data Command control pin - must use a pin in the range 0-31 #define TFT_RST 40 // Reset pin, toggles on startup ... #define SMOOTH_FONT
在main函数中做屏幕的初始化。
TFT_eSPI tft = TFT_eSPI(); ///创建屏幕对象 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); }
然后在屏幕上显示任务要求的字符串,额外地还显示了自己焊接的BMP280测量的温度、气压、高度信息,很可惜,这个BM280芯片在屏幕背面,会受板子的散热影响,测量温度偏高。
void setup(void) { Serial.begin(115200); tftInit(); tft.setCursor(0, 10); //设置坐标开始位置 tft.println("Hello EEPW & DigiKey"); if (!bmp.begin()) { Serial.println(F("Could not find a valid BMP280 sensor, check wiring!")); while (1) ; } /* Default settings from datasheet. */ bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */ Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */ Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */ Adafruit_BMP280::FILTER_X16, /* Filtering. */ Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */ } uint32_t last_time = 0; void loop(void) { char buf[20]; float f, P, A; if (millis() - last_time > 4000) { last_time = millis(); f = bmp.readTemperature(); // Conversion from C to F snprintf(buf, sizeof(buf), "T:%.1fC", f); tft.setCursor(0, 50); //设置坐标开始位置 tft.print(buf); P = bmp.readPressure() / 1000.0; // displaying the Pressure in inches of mercury, you can change the unit snprintf(buf, sizeof(buf), "P:%.1fkPa", P); tft.setCursor(120, 50); //设置坐标开始位置 tft.print(buf); A = bmp.readAltitude(1013.25); // The "1019.66" is the pressure(hPa) at sea level in day in your region snprintf(buf, sizeof(buf), "H:%.1f M", A); tft.setCursor(0, 90); //设置坐标开始位置 tft.print(buf); } delay(10); }
基础任务4 实现光强信息的屏幕显示
光强信息,感觉影响的相关因素挺多。光圈,是指放入光线的量,是个倒数值。光圈值越大,放入的光线就越少,景深就越深;光圈值越小,放入的光线就越多,景深就越浅。常用的光圈有 F2、F2.8、F4、F5.6、F8、F11、F16、F22等。ISO则是感光度。值越高,感光越灵敏,但是噪点也越严重。常用的感光度有ISO100、ISO200、ISO400、ISO800等。
#include <SPI.h> #include <TFT_eSPI.h> #include <Adafruit_BMP280.h> #include <BH1750.h> Adafruit_BMP280 bmp; // I2C TFT_eSPI tft = TFT_eSPI(); ///创建屏幕对象 BH1750 lightMeter(0x23); //光线传感器 const float F = 2.8; //先使用固定光圈2.8 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); } void setup(void) { Serial.begin(115200); tftInit(); Wire.begin(); if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) { Serial.println(F("BH1750 Advanced begin")); } else { Serial.println(F("Error initialising BH1750")); } } uint32_t last_time = 0; void loop(void) { char buf[20]; float lux, ev, t; if (millis() - last_time > 1000) { last_time = millis(); if (lightMeter.measurementReady()) { lux = lightMeter.readLightLevel(); ev = 2.0 + log10(lux / 10.0); //计算曝光 t = pow(2, log2(F * F) - ev); //计算快门时间 Serial.print("Light: "); Serial.print(lux); Serial.print(" lx"); Serial.print(" EV: "); Serial.print(ev); Serial.print(" t: "); Serial.print(t); Serial.println(); snprintf(buf, sizeof(buf), "Light:%.1flux", lux); tft.setCursor(10, 0); //设置坐标开始位置 tft.print(buf); tft.setCursor(10, 30); //设置坐标开始位置 tft.print("ISO100"); 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", t); tft.setCursor(10, 90); //设置坐标开始位置 tft.print(buf); } } delay(10); }
感觉感光度ISO100,在室内还是很不合适拍照啊!这快门需要支架才能保证拍摄清晰啊!