From f6b7a398cdefa916da9870e92a5f15ecfd7fa88a Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Mon, 6 Mar 2023 20:57:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B0=86=E7=8E=AF=E5=A2=83=E5=85=89?= =?UTF-8?q?=E3=80=81=E8=B7=9D=E7=A6=BB=E4=BC=A0=E6=84=9F=E5=99=A8=E4=BB=8E?= =?UTF-8?q?=209930=20=E5=8D=87=E7=BA=A7=E5=88=B0=20APDS9960.=20#4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/CMakeLists.txt | 2 +- main/ambient_light.c | 2 +- main/apds_9960.c | 262 ++++++++++++++++++++++++++++++++++++++++ main/embedded_display.c | 2 +- main/i2c.c | 7 +- main/main.c | 6 +- 6 files changed, 273 insertions(+), 8 deletions(-) create mode 100644 main/apds_9960.c diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 904f7fe..e6cd9ff 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,2 +1,2 @@ -idf_component_register(SRCS "pca9555.c" "i2c.c" "asr_pro.c" "ci_03t.c" "ui_input.c" "ambient_light.c" "temperature.c" "embedded_display.c" "mqtt.c" "main.c" "wifi.c" "light.c" "mqtt.c" +idf_component_register(SRCS "apds_9960.c" "pca9555.c" "i2c.c" "asr_pro.c" "ci_03t.c" "ui_input.c" "ambient_light.c" "temperature.c" "embedded_display.c" "mqtt.c" "main.c" "wifi.c" "light.c" "mqtt.c" INCLUDE_DIRS ".") \ No newline at end of file diff --git a/main/ambient_light.c b/main/ambient_light.c index 77e1915..41bfffb 100644 --- a/main/ambient_light.c +++ b/main/ambient_light.c @@ -183,7 +183,7 @@ void ambient_light_auto_fetch() { void ambient_light_init() { if (is_apds_9930_online == 0) { - ESP_LOGI(AMBIENT_LIGHT_TAG, "AMG8833 is offline"); + ESP_LOGI(AMBIENT_LIGHT_TAG, "APDS 9930 is offline"); return; } ESP_LOGI(AMBIENT_LIGHT_TAG, "Initializing APDS-9930"); diff --git a/main/apds_9960.c b/main/apds_9960.c new file mode 100644 index 0000000..3affe3e --- /dev/null +++ b/main/apds_9960.c @@ -0,0 +1,262 @@ +#include +#include + +#include "driver/i2c.h" +#include "embedded_display.c" +#include "esp_log.h" +#include "i2c.c" + +// #define APDS_9930_CMD_REPEATED 0x80 // 命令重复地址 +// #define APDS_9930_CMD_AUTO_INCREMENT 0x90 // 命令自动递增地址 + +// 0x80 ENABLE R/W Enable states and interrupts 0x00 +// 0x81 ATIME R/W ADC integration time 0xFF +// 0x83 WTIME R/W Wait time (non-gesture) 0xFF +// 0x84 AILTL R/W ALS interrupt low threshold low byte -- +// 0x85 AILTH R/W ALS interrupt low threshold high byte -- +// 0x86 AIHTL R/W ALS interrupt high threshold low byte 0x00 +// 0x87 AIHTH R/W ALS interrupt high threshold high byte 0x00 +// 0x89 PILT R/W Proximity interrupt low threshold 0x00 +// 0x8B PIHT R/W Proximity interrupt high threshold 0x00 +// 0x8C PERS R/W Interrupt persistence filters (non-gesture) 0x00 +// 0x8D CONFIG1 R/W Configuration register one 0x60 +// 0x8E PPULSE R/W Proximity pulse count and length 0x40 +// 0x8F CONTROL R/W Gain control 0x00 +// 0x90 CONFIG2 R/W Configuration register two 0x01 +// 0x92 ID R Device ID ID +// 0x93 STATUS R Device status 0x00 +// 0x94 CDATAL R Low byte of clear channel data 0x00 +// 0x95 CDATAH R High byte of clear channel data 0x00 +// 0x96 RDATAL R Low byte of red channel data 0x00 +// 0x97 RDATAH R High byte of red channel data 0x00 +// 0x98 GDATAL R Low byte of green channel data 0x00 +// 0x99 GDATAH R High byte of green channel data 0x00 +// 0x9A BDATAL R Low byte of blue channel data 0x00 +// 0x9B BDATAH R High byte of blue channel data 0x00 +// 0x9C PDATA R Proximity data 0x00 +// 0x9D POFFSET_UR R/W Proximity offset for UP and RIGHT photodiodes 0x00 +// 0x9E POFFSET_DL R/W Proximity offset for DOWN and LEFT photodiodes 0x00 +// 0x9F CONFIG3 R/W Configuration register three 0x00 +// 0xA0 GPENTH R/W Gesture proximity enter threshold 0x00 +// 0xA1 GEXTH R/W Gesture exit threshold 0x00 +// 0xA2 GCONF1 R/W Gesture configuration one 0x00 +// 0xA3 GCONF2 R/W Gesture configuration two 0x00 +// 0xA4 GOFFSET_U R/W Gesture UP offset register 0x00 +// 0xA5 GOFFSET_D R/W Gesture DOWN offset register 0x00 +// 0xA7 GOFFSET_L R/W Gesture LEFT offset register 0x00 +// 0xA9 GOFFSET_R R/W Gesture RIGHT offset register 0x00 +// 0xA6 GPULSE R/W Gesture pulse count and length 0x40 +// 0xAA GCONF3 R/W Gesture configuration three 0x00 +// 0xAB GCONF4 R/W Gesture configuration four 0x00 +// 0xAE GFLVL R Gesture FIFO level 0x00 +// 0xAF GSTATUS R Gesture status 0x00 +// 0xE4 (1) IFORCE W Force interrupt 0x00 +// 0xE5 (1) PICLEAR W Proximity interrupt clear 0x00 +// 0xE6 (1) CICLEAR W ALS clear channel interrupt clear 0x00 +// 0xE7 (1) AICLEAR W All non-gesture interrupts clear 0x00 +// 0xFC GFIFO_U R Gesture FIFO UP value 0x00 +// 0xFD GFIFO_D R Gesture FIFO DOWN value 0x00 +// 0xFE GFIFO_L R Gesture FIFO LEFT value 0x00 +// 0xFF GFIFO_R R Gesture FIFO RIGHT value 0x00 +// ----------------------------------- 描述 默认值 +#define APDS_9960_REG_ENABLE 0x80 // 状态和中断的启用 0x00 +#define APDS_9960_REG_ATIME 0x81 // ADC 积分时间 0xff +#define APDS_9960_REG_WTIME 0x83 // 等待时间(非手势) 0xff +#define APDS_9960_REG_AILTL 0x84 // ALS 中断低阈值低字节 -- +#define APDS_9960_REG_AILTH 0x85 // ALS 中断低阈值高字节 -- +#define APDS_9960_REG_AIHTL 0x86 // ALS 中断高阈值低字节 0x00 +#define APDS_9960_REG_AIHTH 0x87 // ALS 中断高阈值高字节 0x00 +#define APDS_9960_REG_PILT 0x89 // 接近中断低阈值 0x00 +#define APDS_9960_REG_PIHT 0x8B // 接近中断高阈值 0x00 +#define APDS_9960_REG_PERS 0x8C // 中断持续性过滤器(非手势) 0x00 +#define APDS_9960_REG_CONFIG1 0x8D // 配置寄存器一 0x60 +#define APDS_9960_REG_PPULSE 0x8E // 接近脉冲计数和长度 0x40 +#define APDS_9960_REG_CONTROL 0x8F // 增益控制 0x00 +#define APDS_9960_REG_CONFIG2 0x90 // 配置寄存器二 0x01 +#define APDS_9960_REG_ID 0x92 // 设备 ID ID +#define APDS_9960_REG_STATUS 0x93 // 设备状态 0x00 +#define APDS_9960_REG_CDATAL 0x94 // 清除通道数据低字节 0x00 +#define APDS_9960_REG_CDATAH 0x95 // 清除通道数据高字节 0x00 +#define APDS_9960_REG_RDATAL 0x96 // 红色通道数据低字节 0x00 +#define APDS_9960_REG_RDATAH 0x97 // 红色通道数据高字节 0x00 +#define APDS_9960_REG_GDATAL 0x98 // 绿色通道数据低字节 0x00 +#define APDS_9960_REG_GDATAH 0x99 // 绿色通道数据高字节 0x00 +#define APDS_9960_REG_BDATAL 0x9A // 蓝色通道数据低字节 0x00 +#define APDS_9960_REG_BDATAH 0x9B // 蓝色通道数据高字节 0x00 +#define APDS_9960_REG_PDATA 0x9C // 接近数据 0x00 +#define APDS_9960_REG_POFFSET_UR 0x9D // 接近偏移量上和右 0x00 +#define APDS_9960_REG_POFFSET_DL 0x9E // 接近偏移量下和左 0x00 +#define APDS_9960_REG_CONFIG3 0x9F // 配置寄存器三 0x00 +#define APDS_9960_REG_GPENTH 0xA0 // 手势进入阈值 0x28 +#define APDS_9960_REG_GEXTH 0xA1 // 手势退出阈值 0x1E +#define APDS_9960_REG_GCONF1 0xA2 // 手势配置寄存器一 0x40 +#define APDS_9960_REG_GCONF2 0xA3 // 手势配置寄存器二 0x66 +#define APDS_9960_REG_GOFFSET_U 0xA4 // 手势偏移量上 0x00 +#define APDS_9960_REG_GOFFSET_D 0xA5 // 手势偏移量下 0x00 +#define APDS_9960_REG_GOFFSET_L 0xA7 // 手势偏移量左 0x00 +#define APDS_9960_REG_GOFFSET_R 0xA9 // 手势偏移量右 0x00 +#define APDS_9960_REG_GPULSE 0xA6 // 手势脉冲计数和长度 0xC5 +#define APDS_9960_REG_GCONF3 0xAA // 手势配置寄存器三 0x00 +#define APDS_9960_REG_GCONF4 0xAB // 手势配置寄存器四 0x00 +#define APDS_9960_REG_GFLVL 0xAE // 手势 FIFO 级别 0x00 +#define APDS_9960_REG_GSTATUS 0xAF // 手势状态 0x00 +#define APDS_9960_REG_IFORCE 0xE4 // 强制中断 0x00 +#define APDS_9960_REG_PICLEAR 0xE5 // 清除接近中断 0x00 +#define APDS_9960_REG_CICLEAR 0xE6 // 清除 ALS 中断 0x00 +#define APDS_9960_REG_AICLEAR 0xE7 // 清除手势中断 0x00 +#define APDS_9960_REG_GFIFO_U 0xFC // 手势 FIFO 数据上 0x00 +#define APDS_9960_REG_GFIFO_D 0xFD // 手势 FIFO 数据下 0x00 +#define APDS_9960_REG_GFIFO_L 0xFE // 手势 FIFO 数据左 0x00 +#define APDS_9960_REG_GFIFO_R 0xFF // 手势 FIFO 数据右 0x00 + +#define APDS_9960_CONTROL_VALUE \ + 0b00001010 // 50 mA LED, Reserved, 2x PGAIN, 4x ALS/Cain GAIN +#define APDS_9960_ENABLE_VALUE 0b00000111 +#define APDS_9930_OFFSET_VALUE 0x8f + +#define APDS_9960_TAG "APDS-9960" + +esp_err_t apds_9960_write(uint8_t command, uint8_t data) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_WRITE, + ACK_CHECK_EN); + i2c_master_write_byte(cmd, command, ACK_CHECK_EN); + i2c_master_write_byte(cmd, data, ACK_CHECK_EN); + i2c_master_stop(cmd); + esp_err_t error = + i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + if (error != ESP_OK) { + ESP_LOGW(APDS_9960_TAG, "write failed. %d", error); + } + return error; +} + +esp_err_t apds_9960_read_byte(uint8_t command, uint8_t* data) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_WRITE, + ACK_CHECK_EN); + i2c_master_write_byte(cmd, command, ACK_CHECK_EN); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_READ, + ACK_CHECK_EN); + i2c_master_read_byte(cmd, data, NACK_VAL); + i2c_master_stop(cmd); + esp_err_t error = + i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + if (error != ESP_OK) { + ESP_LOGW(APDS_9960_TAG, "write failed. %d", error); + } + return error; +} + +// read word +esp_err_t apds_9960_read_word(uint8_t command, uint16_t* data) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_WRITE, + ACK_CHECK_EN); + i2c_master_write_byte(cmd, command, ACK_CHECK_EN); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_READ, + ACK_CHECK_EN); + i2c_master_read_byte(cmd, (uint8_t*)data, ACK_VAL); + i2c_master_read_byte(cmd, (uint8_t*)data + 1, NACK_VAL); + i2c_master_stop(cmd); + esp_err_t error = + i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + if (error != ESP_OK) { + ESP_LOGW(APDS_9960_TAG, "write failed. %d", error); + } + return error; +} + +void apes_9960_fetch(void* arg) { + ESP_LOGI(APDS_9960_TAG, "apes_9960_fetch"); + esp_err_t error; + uint16_t red_raw; + uint16_t green_raw; + uint16_t blue_raw; + uint16_t clear_raw; + uint8_t proximity_raw; + char red_str[10]; + char green_str[10]; + char blue_str[10]; + char clear_str[10]; + char proximity_str[10]; + display_fill_rect(0, 2, 128, 8, 0x00); + for (;;) { + // Proximity + error = apds_9960_read_byte(APDS_9960_REG_PDATA, &proximity_raw); + if (error != ESP_OK) { + ESP_LOGW(APDS_9960_TAG, "read proximity failed. %x", error); + } else { + sprintf(proximity_str, "Prox: % 5d ", proximity_raw); + display_print8_str(8, 2, proximity_str); + ESP_LOGD(APDS_9960_TAG, "Prox: %d %x", proximity_raw); + } + // red + error = apds_9960_read_word(APDS_9960_REG_RDATAL, &red_raw); + if (error != ESP_OK) { + ESP_LOGW(APDS_9960_TAG, "read failed. %x", error); + } else { + sprintf(red_str, "R:% 5d", red_raw); + display_print8_str(0, 4, red_str); + ESP_LOGD(APDS_9960_TAG, "Red: %d", red_raw); + } + // green + error = apds_9960_read_word(APDS_9960_REG_GDATAL, &green_raw); + if (error != ESP_OK) { + ESP_LOGW(APDS_9960_TAG, "read failed. %x", error); + } else { + sprintf(green_str, "G:% 5d", green_raw); + display_print8_str(64, 4, green_str); + ESP_LOGD(APDS_9960_TAG, "Green: %d", green_raw); + } + // blue + error = apds_9960_read_word(APDS_9960_REG_BDATAL, &blue_raw); + if (error != ESP_OK) { + ESP_LOGW(APDS_9960_TAG, "read failed. %x", error); + } else { + sprintf(blue_str, "B:% 5d", blue_raw); + display_print8_str(0, 6, blue_str); + ESP_LOGD(APDS_9960_TAG, "Blue: %d", blue_raw); + } + // clear + error = apds_9960_read_word(APDS_9960_REG_CDATAL, &clear_raw); + if (error != ESP_OK) { + ESP_LOGW(APDS_9960_TAG, "read failed. %x", error); + } else { + sprintf(clear_str, "C:% 4d", clear_raw); + display_print8_str(64, 6, clear_str); + ESP_LOGD(APDS_9960_TAG, "Clear: %d", clear_raw); + } + + vTaskDelay(pdMS_TO_TICKS(1000)); + } + display_fill_rect(0, 2, 128, 8, 0x00); +} + +void apes_9960_auto_fetch() { + if (is_apds_9960_online == 0) { + return; + } + xTaskCreate(apes_9960_fetch, "APDS-9960-fetch", 2048, NULL, 10, NULL); +} + +void apes_9960_init() { + if (is_apds_9960_online == 0) { + ESP_LOGI(APDS_9960_TAG, "APDS-9960 is offline"); + return; + } + ESP_LOGI(APDS_9960_TAG, "Initializing APDS-9960"); + ESP_ERROR_CHECK( + apds_9960_write(APDS_9960_REG_CONTROL, APDS_9960_CONTROL_VALUE)); + + ESP_ERROR_CHECK( + apds_9960_write(APDS_9960_REG_ENABLE, APDS_9960_ENABLE_VALUE)); +} diff --git a/main/embedded_display.c b/main/embedded_display.c index ae343b4..a8f2e5e 100644 --- a/main/embedded_display.c +++ b/main/embedded_display.c @@ -16,7 +16,7 @@ void i2cWriteByte(uint8_t reg, uint8_t data) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); - i2c_master_write_byte(cmd, I2C_ADDRESS << 1 | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, SSD1306_ADDRESS << 1 | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, reg, true); i2c_master_write_byte(cmd, data, true); i2c_master_stop(cmd); diff --git a/main/i2c.c b/main/i2c.c index 1d316d6..741799a 100644 --- a/main/i2c.c +++ b/main/i2c.c @@ -20,13 +20,15 @@ #define PCA9555_ADDRESS 0x20 #define GX21M15_ADDRESS 0x48 #define APDS_9930_ADDRESS 0x39 -#define I2C_ADDRESS 0x3c +#define APDS_9960_ADDRESS 0x39 +#define SSD1306_ADDRESS 0x3c static const char *I2C_TAG = "APP_I2C"; static uint8_t is_temperature_online = 0; static uint8_t is_pca9555_online = 0; static uint8_t is_apds_9930_online = 0; +static uint8_t is_apds_9960_online = 0; static uint8_t is_embedded_display_online = 0; void init_i2c() { @@ -71,5 +73,6 @@ void i2c_check_slaves() { is_temperature_online = i2c_check_slave_exists(GX21M15_ADDRESS); is_pca9555_online = i2c_check_slave_exists(PCA9555_ADDRESS); is_apds_9930_online = i2c_check_slave_exists(APDS_9930_ADDRESS); - is_embedded_display_online = i2c_check_slave_exists(I2C_ADDRESS); + is_apds_9960_online = i2c_check_slave_exists(APDS_9960_ADDRESS); + is_embedded_display_online = i2c_check_slave_exists(SSD1306_ADDRESS); } \ No newline at end of file diff --git a/main/main.c b/main/main.c index 3a06fb1..e032d84 100644 --- a/main/main.c +++ b/main/main.c @@ -1,4 +1,4 @@ -#include "ambient_light.c" +#include "apds_9960.c" #include "ci_03t.c" #include "embedded_display.c" #include "esp_log.h" @@ -22,8 +22,8 @@ void app_main(void) { init_display(); display_print8_str(0, 0, "Ambient Light"); ci_03t_init(); - ambient_light_init(); - ambient_light_auto_fetch(); + apes_9960_init(); + apes_9960_auto_fetch(); auto_fetch_temperature(); pca9555_init(); ui_input_init();