From fa066408e2d3663169dfd8f37b6f510e53bc6db8 Mon Sep 17 00:00:00 2001 From: Misaki Date: Sun, 24 Aug 2025 19:11:42 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E6=B5=8B=E8=AF=95=E4=BA=86IO=E6=8B=93?= =?UTF-8?q?=E5=B1=95=E8=8A=AF=E7=89=87TCA9554PWR=EF=BC=8C=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=BB=93=E6=9E=9C=E6=AD=A3=E5=B8=B8=EF=BC=8C=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Lib/EXIO/TCA9554PWR.c | 94 ++++++++++++++ Lib/EXIO/TCA9554PWR.h | 44 +++++++ Lib/README.md | 3 +- main/Bionic_sphere.c | 6 +- main/CMakeLists.txt | 4 + test/EXIO_Test/TCA9554PWR_Test.c | 215 +++++++++++++++++++++++++++++++ test/EXIO_Test/TCA9554PWR_Test.h | 22 ++++ test/driver_test/drivers_test.c | 9 ++ test/driver_test/drivers_test.h | 3 + 项目开发日志.md | 28 ++++ 10 files changed, 426 insertions(+), 2 deletions(-) create mode 100644 Lib/EXIO/TCA9554PWR.c create mode 100644 Lib/EXIO/TCA9554PWR.h create mode 100644 test/EXIO_Test/TCA9554PWR_Test.c create mode 100644 test/EXIO_Test/TCA9554PWR_Test.h diff --git a/Lib/EXIO/TCA9554PWR.c b/Lib/EXIO/TCA9554PWR.c new file mode 100644 index 0000000..c3397f8 --- /dev/null +++ b/Lib/EXIO/TCA9554PWR.c @@ -0,0 +1,94 @@ +#include "TCA9554PWR.h" +/***************************************************** Operation register REG ****************************************************/ +uint8_t Read_REG(uint8_t REG) // Read the value of the TCA9554PWR register REG +{ + uint8_t bitsStatus = 0; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (TCA9554_ADDRESS << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, REG, true); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (TCA9554_ADDRESS << 1) | I2C_MASTER_READ, true); + i2c_master_read_byte(cmd, &bitsStatus, I2C_MASTER_NACK); + i2c_master_stop(cmd); + i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + return bitsStatus; +} +void Write_REG(uint8_t REG,uint8_t Data) // Write Data to the REG register of the TCA9554PWR +{ + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (TCA9554_ADDRESS << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, REG, true); + i2c_master_write_byte(cmd, Data, true); + i2c_master_stop(cmd); + i2c_master_cmd_begin(I2C_MASTER_NUM,cmd,I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); +} +/********************************************************** Set EXIO mode **********************************************************/ +void Mode_EXIO(uint8_t Pin,uint8_t State) // Set the mode of the TCA9554PWR Pin. The default is Output mode (output mode or input mode). State: 0= Output mode 1= input mode +{ + uint8_t bitsStatus = Read_REG(TCA9554_CONFIG_REG); + uint8_t Data = (0x01 << (Pin-1)) | bitsStatus; + Write_REG(TCA9554_CONFIG_REG,Data); +} +void Mode_EXIOS(uint8_t PinState) // Set the mode of the 7 pins from the TCA9554PWR with PinState +{ + Write_REG(TCA9554_CONFIG_REG,PinState); +} + +/********************************************************** Read EXIO status **********************************************************/ +uint8_t Read_EXIO(uint8_t Pin) // Read the level of the TCA9554PWR Pin +{ + uint8_t inputBits =Read_REG(TCA9554_INPUT_REG); + uint8_t bitStatus = (inputBits >> (Pin-1)) & 0x01; + return bitStatus; +} +uint8_t Read_EXIOS(void) // Read the level of all pins of TCA9554PWR +{ + uint8_t inputBits = Read_REG(TCA9554_INPUT_REG); + return inputBits; +} + +/********************************************************** Set the EXIO output status **********************************************************/ +void Set_EXIO(uint8_t Pin,bool State) // Sets the level state of the Pin without affecting the other pins(PIN:1~8) +{ + uint8_t Data = 0; + uint8_t bitsStatus = Read_REG(TCA9554_OUTPUT_REG); + if(Pin < 9 && Pin > 0){ + if(State) + Data = (0x01 << (Pin-1)) | bitsStatus; + else + Data = (~(0x01 << (Pin-1)) & bitsStatus); + Write_REG(TCA9554_OUTPUT_REG,Data); + } + else + printf("Parameter error, please enter the correct parameter!\r\n"); + +} +void Set_EXIOS(uint8_t PinState) // Set 7 pins to the PinState state such as :PinState=0x23, 0010 0011 state (the highest bit is not used) +{ + Write_REG(TCA9554_OUTPUT_REG,PinState); +} + +/********************************************************** Flip EXIO state **********************************************************/ +void Set_Toggle(uint8_t Pin) // Flip the level of the TCA9554PWR Pin +{ + uint8_t bitsStatus = Read_EXIO(Pin); + Set_EXIO(Pin,(bool)!bitsStatus); +} + + +/********************************************************* TCA9554PWR Initializes the device ***********************************************************/ +void TCA9554PWR_Init(uint8_t PinState) // Set the seven pins to PinState state, for example :PinState=0x23, 0010 0011 State (the highest bit is not used) (Output mode or input mode) 0= Output mode 1= Input mode. The default value is output mode +{ + // i2c_master_init(); + Mode_EXIOS(PinState); +} + +esp_err_t EXIO_Init(void) +{ + TCA9554PWR_Init(0x00); + return ESP_OK; +} diff --git a/Lib/EXIO/TCA9554PWR.h b/Lib/EXIO/TCA9554PWR.h new file mode 100644 index 0000000..44121c8 --- /dev/null +++ b/Lib/EXIO/TCA9554PWR.h @@ -0,0 +1,44 @@ +#pragma once + + +#include +#include "I2C_Driver.h" +#define TCA9554_EXIO1 0x01 +#define TCA9554_EXIO2 0x02 +#define TCA9554_EXIO3 0x03 +#define TCA9554_EXIO4 0x04 +#define TCA9554_EXIO5 0x05 +#define TCA9554_EXIO6 0x06 +#define TCA9554_EXIO7 0x07 +#define TCA9554_EXIO8 0x08 + + +/****************************************************** The macro defines the TCA9554PWR information ******************************************************/ + +#define TCA9554_ADDRESS 0x20 // TCA9554PWR I2C address +// TCA9554PWR寄存器地址 +#define TCA9554_INPUT_REG 0x00 // Input register,input level +#define TCA9554_OUTPUT_REG 0x01 // Output register, high and low level output +#define TCA9554_Polarity_REG 0x02 // The Polarity Inversion register (register 2) allows polarity inversion of pins defined as inputs by the Configuration register. +#define TCA9554_CONFIG_REG 0x03 // Configuration register, mode configuration + + +// esp_err_t i2c_master_init(void); // Example Initialize I2C to host mode +/***************************************************** Operation register REG ****************************************************/ +uint8_t Read_REG(uint8_t REG); // Read the value of the TCA9554PWR register REG +void Write_REG(uint8_t REG,uint8_t Data); // Write Data to the REG register of the TCA9554PWR +/********************************************************** Set EXIO mode **********************************************************/ +void Mode_EXIO(uint8_t Pin,uint8_t State); // Set the mode of the TCA9554PWR Pin. The default is Output mode (output mode or input mode). State: 0= Output mode 1= input mode +void Mode_EXIOS(uint8_t PinState); // Set the mode of the 7 pins from the TCA9554PWR with PinState +/********************************************************** Read EXIO status **********************************************************/ +uint8_t Read_EXIO(uint8_t Pin); // Read the level of the TCA9554PWR Pin +uint8_t Read_EXIOS(void); // Read the level of all pins of TCA9554PWR, the default read input level state, want to get the current IO output state, pass the parameter TCA9554_OUTPUT_REG, such as Read_EXIOS(TCA9554_OUTPUT_REG); +/********************************************************** Set the EXIO output status **********************************************************/ +void Set_EXIO(uint8_t Pin,bool State); // Sets the level state of the Pin without affecting the other pins +void Set_EXIOS(uint8_t PinState); // Set 7 pins to the PinState state such as :PinState=0x23, 0010 0011 state (the highest bit is not used) +/********************************************************** Flip EXIO state **********************************************************/ +void Set_Toggle(uint8_t Pin); // Flip the level of the TCA9554PWR Pin +/********************************************************* TCA9554PWR Initializes the device ***********************************************************/ +void TCA9554PWR_Init(uint8_t PinState); // Set the seven pins to PinState state, for example :PinState=0x23, 0010 0011 State (the highest bit is not used) (Output mode or input mode) 0= Output mode 1= Input mode. The default value is output mode + +esp_err_t EXIO_Init(void); diff --git a/Lib/README.md b/Lib/README.md index c0c1e50..c54dde1 100644 --- a/Lib/README.md +++ b/Lib/README.md @@ -1,4 +1,5 @@ ### 本目录为各种外设驱动库,部分驱动库之间存在依赖关系,会在下面有所说明 #### 1. QMI8658依赖I2C_Driver -#### 2. PCF85063依赖I2C_Driver \ No newline at end of file +#### 2. PCF85063依赖I2C_Driver +#### 3. TCA9554PWR依赖I2C_Driver \ No newline at end of file diff --git a/main/Bionic_sphere.c b/main/Bionic_sphere.c index 9f81be0..a951975 100644 --- a/main/Bionic_sphere.c +++ b/main/Bionic_sphere.c @@ -9,10 +9,14 @@ void app_main(void) { // imu_test(); // imu测试 + // battery_test(); // wireless_test(); // sd_card_module_test(); - pcf85063_test(); + + // pcf85063_test(); + + exio_text(); } diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index af97089..5af1332 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,19 +1,23 @@ idf_component_register(SRCS "Bionic_sphere.c" "../test/driver_test/drivers_test.c" # 测试用例 + "../test/EXIO_Test/TCA9554PWR_Test.c" # 测试用例 "../Lib/I2C_Driver/I2C_Driver.c" # IIC底层驱动库 "../Lib/QMI8658/QMI8658.c" # IMU驱动库 "../Lib/BAT_Driver/BAT_Driver.c" # 电池adc驱动库 "../Lib/Wireless/Wireless.c" # 无线通信驱动库 "../Lib/SD_Card/SD_MMC.c" # SD卡驱动库 "../Lib/PCF85063/PCF85063.c" # RTC驱动库 + "../Lib/EXIO/TCA9554PWR.c" # IO拓展库 INCLUDE_DIRS "." "../test/driver_test" + "../test/EXIO_Test" "../Lib/I2C_Driver" "../Lib/QMI8658" "../Lib/BAT_Driver" "../Lib/Wireless" "../Lib/SD_Card" "../Lib/PCF85063" + "../Lib/EXIO" PRIV_REQUIRES # 私有依赖 driver bt diff --git a/test/EXIO_Test/TCA9554PWR_Test.c b/test/EXIO_Test/TCA9554PWR_Test.c new file mode 100644 index 0000000..169b46d --- /dev/null +++ b/test/EXIO_Test/TCA9554PWR_Test.c @@ -0,0 +1,215 @@ +// +// Created by misaki on 2025/8/24. +// + + +#include "TCA9554PWR_Test.h" +#include "TCA9554PWR.h" +#include "I2C_Driver.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "TCA9554PWR_TEST"; + +/*------------------------------------------------- + * 宏:延时时间,方便肉眼观察 + *------------------------------------------------*/ +#define DELAY_MS(ms) vTaskDelay(pdMS_TO_TICKS(ms)) + +/*------------------------------------------------- + * 内部辅助函数:打印 8bit 数据为二进制格式 + *------------------------------------------------*/ +static void print_bin8(uint8_t val) +{ + for (int i = 7; i >= 0; i--) { + printf("%c", (val & (1 << i)) ? '1' : '0'); + } +} + +/*------------------------------------------------- + * 测试 1:输出寄存器读写测试 + * 步骤: + * 1. 先写入 0xAA(10101010) + * 2. 立即读回,比对是否一致 + *------------------------------------------------*/ +static esp_err_t test_output_reg_rw(void) +{ + ESP_LOGI(TAG, ">> 测试1:输出寄存器读写测试"); + + /* 1. 写入数据 */ + Write_REG(TCA9554_OUTPUT_REG, 0xAA); + DELAY_MS(10); /* 确保芯片完成写操作 */ + + /* 2. 读回数据 */ + uint8_t read_back = Read_REG(TCA9554_OUTPUT_REG); + ESP_LOGI(TAG, "写入 0xAA,读回 0x%02X", read_back); + + if (read_back != 0xAA) { + ESP_LOGE(TAG, "测试1 失败:数据不一致"); + return ESP_FAIL; + } + + ESP_LOGI(TAG, "测试1 通过"); + return ESP_OK; +} + +/*------------------------------------------------- + * 测试 2:配置寄存器读写测试 + * 步骤: + * 1. 将 8 个 IO 全部设为输入(写 0xFF) + * 2. 读回,应为 0xFF + * 3. 再全部设为输出(写 0x00) + * 4. 读回,应为 0x00 + *------------------------------------------------*/ +static esp_err_t test_config_reg_rw(void) +{ + ESP_LOGI(TAG, ">> 测试2:配置寄存器读写测试"); + + /* 1. 全部设为输入 */ + Write_REG(TCA9554_CONFIG_REG, 0xFF); + DELAY_MS(10); + uint8_t read_back = Read_REG(TCA9554_CONFIG_REG); + ESP_LOGI(TAG, "写入 0xFF(全输入),读回 0x%02X", read_back); + if (read_back != 0xFF) { + ESP_LOGE(TAG, "测试2 失败:全输入模式设置错误"); + return ESP_FAIL; + } + + /* 2. 全部设为输出 */ + Write_REG(TCA9554_CONFIG_REG, 0x00); + DELAY_MS(10); + read_back = Read_REG(TCA9554_CONFIG_REG); + ESP_LOGI(TAG, "写入 0x00(全输出),读回 0x%02X", read_back); + if (read_back != 0x00) { + ESP_LOGE(TAG, "测试2 失败:全输出模式设置错误"); + return ESP_FAIL; + } + + ESP_LOGI(TAG, "测试2 通过"); + return ESP_OK; +} + +/*------------------------------------------------- + * 测试 3:单管脚输出翻转测试 + * 步骤: + * 1. 先把 IO1 设为输出 + * 2. 先置高,延时 500ms + * 3. 再置低,延时 500ms + * 4. 再调用 Toggle 两次,肉眼可见两次翻转 + *------------------------------------------------*/ +static esp_err_t test_single_pin_toggle(void) +{ + ESP_LOGI(TAG, ">> 测试3:单管脚输出翻转测试"); + + /* 1. 设置 IO1 为输出模式 */ + Mode_EXIO(TCA9554_EXIO1, 0); /* 0 = 输出 */ + DELAY_MS(10); + + /* 2. 置高 */ + Set_EXIO(TCA9554_EXIO1, 1); + ESP_LOGI(TAG, "IO1 置高,请观察电平"); + DELAY_MS(500); + + /* 3. 置低 */ + Set_EXIO(TCA9554_EXIO1, 0); + ESP_LOGI(TAG, "IO1 置低,请观察电平"); + DELAY_MS(500); + + /* 4. 两次翻转 */ + Set_Toggle(TCA9554_EXIO1); + ESP_LOGI(TAG, "IO1 Toggle 1"); + DELAY_MS(500); + + Set_Toggle(TCA9554_EXIO1); + ESP_LOGI(TAG, "IO1 Toggle 2"); + DELAY_MS(500); + + ESP_LOGI(TAG, "测试3 完成(请确认 LED/万用表现象)"); + return ESP_OK; +} + +/*------------------------------------------------- + * 测试 4:8 位整体输出测试 + * 步骤: + * 1. 8 个 IO 全部设为输出 + * 2. 依次输出 0x55、0xAA、0xFF、0x00 + * 3. 每次输出后打印日志 + *------------------------------------------------*/ +static esp_err_t test_all_pin_output(void) +{ + ESP_LOGI(TAG, ">> 测试4:8位整体输出测试"); + + /* 1. 全部设为输出 */ + Mode_EXIOS(0x00); /* 0x00 = 全输出 */ + DELAY_MS(10); + + const uint8_t pattern[4] = {0x55, 0xAA, 0xFF, 0x00}; + for (int i = 0; i < 4; i++) { + Set_EXIOS(pattern[i]); + ESP_LOGI(TAG, "输出 0x%02X (二进制: ", pattern[i]); + print_bin8(pattern[i]); + printf(")\n"); + DELAY_MS(1000); + } + + ESP_LOGI(TAG, "测试4 完成"); + return ESP_OK; +} + +/*------------------------------------------------- + * 测试 5:输入读取测试 + * 步骤: + * 1. 将 IO2 设为输入 + * 2. 提示用户把 IO2 拉高 + * 3. 等待 3 秒,期间循环读取 IO2 电平 + * 4. 再提示用户把 IO2 拉低 + * 5. 再次循环读取 3 秒 + *------------------------------------------------*/ +static esp_err_t test_single_pin_input(void) +{ + ESP_LOGI(TAG, ">> 测试5:输入读取测试(需要人工干预)"); + + /* 1. 设置 IO2 为输入 */ + Mode_EXIO(TCA9554_EXIO2, 1); /* 1 = 输入 */ + DELAY_MS(10); + + ESP_LOGI(TAG, "请把 IO2 拉高,3 秒内将持续读取..."); + for (int i = 0; i < 30; i++) { + uint8_t level = Read_EXIO(TCA9554_EXIO2); + ESP_LOGI(TAG, "IO2 当前电平 = %u", level); + DELAY_MS(100); + } + + ESP_LOGI(TAG, "请把 IO2 拉低,3 秒内将持续读取..."); + for (int i = 0; i < 30; i++) { + uint8_t level = Read_EXIO(TCA9554_EXIO2); + ESP_LOGI(TAG, "IO2 当前电平 = %u", level); + DELAY_MS(100); + } + + ESP_LOGI(TAG, "测试5 完成"); + return ESP_OK; +} + +/*------------------------------------------------- + * 综合测试入口 + *------------------------------------------------*/ +esp_err_t EXIO_Test(void) +{ + ESP_LOGI(TAG, "====== TCA9554PWR 综合测试开始 ======"); + + /* 1. 初始化 I2C 与 TCA9554 */ + I2C_Init(); /* I2C 驱动初始化 */ + EXIO_Init(); /* TCA9554 芯片初始化 */ + + /* 2. 依次运行各项测试 */ + if (test_output_reg_rw() != ESP_OK) return ESP_FAIL; + if (test_config_reg_rw() != ESP_OK) return ESP_FAIL; + if (test_single_pin_toggle()!= ESP_OK) return ESP_FAIL; + if (test_all_pin_output() != ESP_OK) return ESP_FAIL; + if (test_single_pin_input()!= ESP_OK) return ESP_FAIL; + + ESP_LOGI(TAG, "====== 所有测试通过!======"); + return ESP_OK; +} \ No newline at end of file diff --git a/test/EXIO_Test/TCA9554PWR_Test.h b/test/EXIO_Test/TCA9554PWR_Test.h new file mode 100644 index 0000000..f94a7e7 --- /dev/null +++ b/test/EXIO_Test/TCA9554PWR_Test.h @@ -0,0 +1,22 @@ +// +// Created by misaki on 2025/8/24. +// + +#pragma once + +#include +#include "esp_err.h" + +/** + * @brief TCA9554PWR 芯片功能综合测试入口 + * 该函数会依次执行: + * 1. 初始化 I2C 及 TCA9554 + * 2. 输出寄存器读写测试 + * 3. 配置寄存器读写测试 + * 4. 单管脚输出翻转测试 + * 5. 8 位整体输出测试 + * 6. 输入读取测试(需要把待测脚短暂拉高/拉低) + * @return ESP_OK 全部测试通过 + * ESP_FAIL 任一测试失败 + */ +esp_err_t EXIO_Test(void); \ No newline at end of file diff --git a/test/driver_test/drivers_test.c b/test/driver_test/drivers_test.c index 4d78b98..025faad 100644 --- a/test/driver_test/drivers_test.c +++ b/test/driver_test/drivers_test.c @@ -192,4 +192,13 @@ void pcf85063_test(void) vTaskDelay(pdMS_TO_TICKS(1000)); // 每秒读一次 } +} + + +#include "TCA9554PWR_Test.h" +void exio_text(void) +{ + if (EXIO_Test() == ESP_FAIL) { + ESP_LOGE("EXIO_TEST", "EXIO_Test() failed"); + } } \ No newline at end of file diff --git a/test/driver_test/drivers_test.h b/test/driver_test/drivers_test.h index c81f8c8..a746774 100644 --- a/test/driver_test/drivers_test.h +++ b/test/driver_test/drivers_test.h @@ -20,5 +20,8 @@ void sd_card_module_test(void); // RTC测试 void pcf85063_test(void); +// IO拓展测试 +void exio_text(void); + #endif //BIONIC_SPHERE_DRIVERS_TEST_H \ No newline at end of file diff --git a/项目开发日志.md b/项目开发日志.md index 5e4f1cd..339ca44 100644 --- a/项目开发日志.md +++ b/项目开发日志.md @@ -106,4 +106,32 @@ 驱动位置位于:Lib/PCF85063 ``` +- [x] 7. 测试了IO拓展芯片TCA9554PWR,测试结果正常,测试通过 + ```shell + I (356) TCA9554PWR_TEST: ====== TCA9554PWR 综合测试开始 ====== + I (366) I2C: I2C initialized successfully + I (366) TCA9554PWR_TEST: >> 测试1:输出寄存器读写测试 + I (386) TCA9554PWR_TEST: 写入 0xAA,读回 0xAA + I (386) TCA9554PWR_TEST: 测试1 通过 + I (386) TCA9554PWR_TEST: >> 测试2:配置寄存器读写测试 + I (396) TCA9554PWR_TEST: 写入 0xFF(全输入),读回 0xFF + I (406) TCA9554PWR_TEST: 写入 0x00(全输出),读回 0x00 + I (406) TCA9554PWR_TEST: 测试2 通过 + I (406) TCA9554PWR_TEST: >> 测试3:单管脚输出翻转测试 + I (426) TCA9554PWR_TEST: IO1 置高,请观察电平 + I (926) TCA9554PWR_TEST: IO1 置低,请观察电平 + I (1426) TCA9554PWR_TEST: IO1 Toggle 1 + I (1926) TCA9554PWR_TEST: IO1 Toggle 2 + I (2426) TCA9554PWR_TEST: 测试3 完成(请确认 LED/万用表现象) + I (2426) TCA9554PWR_TEST: >> 测试4:8位整体输出测试 + I (2436) TCA9554PWR_TEST: 输出 0x55 (二进制: + 01010101) + I (3436) TCA9554PWR_TEST: 输出 0xAA (二进制: + 10101010) + I (4436) TCA9554PWR_TEST: 输出 0xFF (二进制: + 11111111) + I (5436) TCA9554PWR_TEST: 输出 0x00 (二进制: + 00000000) + ``` +