本贴主要记录在完成4个基础任务过程中的一些完成细节,包括软件开发环境部署、硬线连接,调试开发过程中遇到的问题等的记录。
软件开发环境准备。打开Arduino IDE,在首选项里面,添加:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json
之后选择TFT屏幕驱动:
之前安装的库比较旧,可以在线更新。
任务一、编程实现按键状态采集
硬线连接:
从上图可以看到,红色与蓝色按键的信号分别连接到开发板的A1与A0.
在代码中定义如下:
int buttonPinRed = 17; int buttonPinBlue = 18;
设置为输入模式,下降沿触发中断。
pinMode(buttonPinRed, INPUT); pinMode(buttonPinBlue, INPUT); attachInterrupt(digitalPinToInterrupt(buttonPinRed), updateScreen_BtnRedPressed, FALLING); attachInterrupt(digitalPinToInterrupt(buttonPinBlue), updateScreen_BtnBluePressed, FALLING);
在按键按下后,分别在彩屏上显示红色与蓝色的实心圆,这样比较直观。因此要解决TFT屏幕显示问题。这里采用的是Adafruit官方的GFX与ST7789库。包含如下头文件。
#include <Adafruit_GFX.h> // Core graphics library #include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
接下来是屏幕初始化:
// turn on backlite pinMode(TFT_BACKLITE, OUTPUT); digitalWrite(TFT_BACKLITE, HIGH); // turn on the TFT / I2C power supply pinMode(TFT_I2C_POWER, OUTPUT); digitalWrite(TFT_I2C_POWER, HIGH); delay(10); // initialize TFT tft.init(135, 240); // Init ST7789 240x135 tft.setRotation(3); tft.fillScreen(ST77XX_BLACK); Serial.println(F("Initialized")); tft.setTextColor(ST77XX_YELLOW); tft.setTextSize(2); tft.println("Hello EEPW & DigiKey"); tft.setCursor(0, 0); delay(1000);
接下来定义按键中断回调函数:
void updateScreen_BtnRedPressed() { Serial.println("Inside ISR: push button down!!!"); tft.fillRect(16 * 10, 32, 32, 16, ST77XX_BLACK); tft.drawBitmap(16 * 10, 32, str_f_HONG, 16, 16, ST77XX_RED); tft.drawBitmap(16 * 11, 32, str_f_SE, 16, 16, ST77XX_RED); tft.fillCircle(16 * 13, 38, 10, ST77XX_RED); } void updateScreen_BtnBluePressed(){ tft.fillRect(16*10,32,32,16,ST77XX_BLACK); tft.drawBitmap(16*10, 32, str_f_LAN, 16, 16, ST77XX_BLUE); tft.drawBitmap(16*11, 32, str_f_SE, 16, 16, ST77XX_BLUE); tft.fillCircle(16*13, 38, 10, ST77XX_BLUE); }
此外,采用取字模的方式,显示汉字:
const uint8_t PROGMEM str_f_SE[] = { 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x07, 0xC0, 0x08, 0x80, 0x01, 0x00, 0x03, 0xE0, 0x1E, 0x40, 0x12, 0x40, 0x13, 0x80, 0x1C, 0x00, 0x10, 0x04, 0x10, 0x04, 0x0C, 0x3C, 0x03, 0xC0, 0x00, 0x00 }; /*"色",0*/ const uint8_t PROGMEM str_f_HONG[] = { 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x12, 0x18, 0x34, 0xE0, 0x08, 0x20, 0x10, 0x20, 0x1E, 0x20, 0x02, 0x20, 0x04, 0x3E, 0x3B, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /*"红",1*/ const uint8_t PROGMEM str_f_LAN[] = { 0x00, 0x00, 0x00, 0x40, 0x04, 0x40, 0x03, 0xF8, 0x1E, 0x80, 0x04, 0x60, 0x0A, 0x40, 0x0A, 0xB0, 0x0A, 0x20, 0x0A, 0x20, 0x00, 0xF0, 0x0F, 0xD0, 0x0A, 0xA0, 0x0A, 0xFE, 0x35, 0x00, 0x00, 0x00 }; /*"蓝",2*/
烧录到板子:
可以看到已经成功驱动屏幕函数实现字符显示“Hello EEPW & Digikey”,并且成功实现了按键状态的采集。
遇到的烧录失败:
此类问题解决办法:手动按住D0按键,然后再插上USB线缆,这样就使得ESP32S3进入BOOT模式。
DO按键在本开发板上有两个功能:1,BOOT按键;2,正常的INPUT引脚。
任务三、基于屏幕驱动函数实现字符的显示,例如显示Hello EEPW & DigiKey;也可显示自己喜欢的名言警句
这部分字符显示在任务一的展示部分已经记录,并成功展示。
任务二、编程实现数字光传感器BH1750的数据读取
根据M5stack官网介绍,其提供了Arduino的驱动库:
安装成功后会有提示:
在源代码中包含头文件:
#include <M5_DLight.h>
初始化BH1750传感器:
Serial.println("Sensor begin....."); sensor.begin(); sensor.setMode(CONTINUOUSLY_H_RESOLUTION_MODE);
在主循环中读取亮度数据:
void loop() { lux = sensor.getLUX(); Serial.printf("lux: %dn", lux); delay(500); }
可以看到用手挡住传感器的时候,串口打印的传感器数据值较小;手移开后,亮度值较大。
任务四、实现光强信息的屏幕显示
有了之前驱动TFT屏幕以及上一步后去光照传感器数据的代码,下面使用脏矩形填充固定区域,然后把传感器数据打印到屏幕上即可。
void loop() { lux = sensor.getLUX(); Serial.printf("lux: %dn", lux); tft.fillRect(30, 60, 200, 50, ST77XX_BLACK); tft.setCursor(30, 60); tft.setTextSize(3); tft.print("lux = "); tft.print(lux); delay(500); }
实现效果:
接下来就是根据LUX值计算出曝光值EV,这里可以参考老师提供的公式:
之后就可以利用右边的公式来根据光圈F的大小来计算出快门速度T。当前的公式是在ISO100的感光值下。更完整的公式如下:
上述公式可以进行变形:
EV = LOG2(F*F) + (-LOG2(T)) - (LOG2(ISO/100))= AV + TV - SV.
基本的实现思路就是按键控制F光圈大小,另一个按键控制调节ISO感光值,然后就可以计算出快门速度T。接下来就是把这些结果在TFT屏幕上显示出来即可。
lux = sensor.getLUX(); ev = round(2 + log(lux / 10) / log(2)); //one btn control ISO (svIdex), another button control Speed (tvIndex) tvIdex = ev + svIdex - avIdex;
为了实现快速计算,已经预先计算好了一系列光圈值对应的曝光值,一系列快门速度对应的曝光值,一些列ISO感光等级对应的曝光值,从而实现快速计算。
const char *AV[] = { "1 ", "1.4", "2 ", "2.8", "4 ", "5.6", "8 ", "11 ", "16 ", "22 ", "32 " }; const char *TV[] = { "1 ", "1/2 ", "1/4 ", "1/8 ", "1/15 ", "1/30 ", "1/60 ", "1/125 ", "1/250 ", "1/500 ", "1/1000" }; const char *SV[] = { "100 ", "200 ", "400 ", "800 ", "1600" };
最终完整的显示效果如下: