From 38a41744b9edf5d156b281a6cedfae12554d8391 Mon Sep 17 00:00:00 2001 From: qiuxin Date: Mon, 26 May 2025 15:40:47 +0800 Subject: [PATCH] =?UTF-8?q?TCA6416=E9=A9=B1=E5=8A=A8=E6=B5=8B=E8=AF=95OK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/Src/freertos.c | 254 +++++++++++++++++---- Core/Src/gpio.c | 20 +- MDK-ARM/controller_pcba.uvoptx | 32 ++- User/application/inc/TCA6416.h | 56 ++++- User/application/inc/tca6416_status.h | 12 + User/application/src/TCA6416.c | 304 +++++++++++++++++++++++--- User/application/src/tcpserverc.c | 31 +-- 7 files changed, 597 insertions(+), 112 deletions(-) create mode 100644 User/application/inc/tca6416_status.h diff --git a/Core/Src/freertos.c b/Core/Src/freertos.c index 6c1f90e..9116183 100644 --- a/Core/Src/freertos.c +++ b/Core/Src/freertos.c @@ -90,10 +90,21 @@ volatile uint32_t rts_pin_speed = 0; // RTS引脚速度 volatile uint32_t rts_pin_alternate = 0; // RTS引脚复用功能 // 添加全局变量用于存储TCA6416引脚状态 -static volatile uint8_t tca6416_port0_status = 0; // 第一个TCA6416的Port0状态 -static volatile uint8_t tca6416_port1_status = 0; // 第一个TCA6416的Port1状态 -static volatile uint8_t tca6416_port2_status = 0; // 第二个TCA6416的Port0状态 -static volatile uint8_t tca6416_port3_status = 0; // 第二个TCA6416的Port1状态 +volatile uint8_t tca6416_port0_status = 0; // 第一个TCA6416的Port0状态 +volatile uint8_t tca6416_port1_status = 0; // 第一个TCA6416的Port1状态 +volatile uint8_t tca6416_port2_status = 0; // 第二个TCA6416的Port0状态 +volatile uint8_t tca6416_port3_status = 0; // 第二个TCA6416的Port1状态 + +// 添加TCA6416测试相关的调试变量 +volatile uint8_t tca6416_test_step = 0; // 当前测试步骤 +volatile uint8_t tca6416_init_result = 0xFF; // 初始化结果 +volatile uint8_t tca6416_write_data = 0; // 写入的数据 +volatile uint8_t tca6416_read_data = 0; // 读取的数据 +volatile uint8_t tca6416_error_count = 0; // 错误计数 +volatile uint8_t tca6416_test_pattern = 0; // 测试模式 +volatile uint8_t tca6416_port0_dir = 0; // Port0方向寄存器值 +volatile uint8_t tca6416_port1_dir = 0; // Port1方向寄存器值 +volatile uint8_t tca6416_i2c_ack_status = 0; // I2C应答状态 /* USER CODE END Variables */ @@ -112,6 +123,7 @@ extern struct tcp_pcb *server_pcb_control; extern void tcp_abort(struct tcp_pcb *pcb); void start_usart6_test_task(void const *argument); // 添加USART6测试任务函数声明 void start_tca6416_task(void const *argument); // 添加TCA6416任务函数声明 +void test_tca6416_task(void const *argument); // 添加TCA6416测试任务函数声明 /* USER CODE END FunctionPrototypes */ void start_tcp_task(void const *argument); @@ -207,9 +219,12 @@ void MX_FREERTOS_Init(void) usart6_test_taskHandle = osThreadCreate(osThread(usart6_test_task), NULL); /* TCA6416任务 */ - osThreadDef(tca6416_task, start_tca6416_task, osPriorityNormal, 0, 128); - tca6416_taskHandle = osThreadCreate(osThread(tca6416_task), NULL); + //osThreadDef(tca6416_task, start_tca6416_task, osPriorityNormal, 0, 128); + // tca6416_taskHandle = osThreadCreate(osThread(tca6416_task), NULL); + /* TCA6416测试任务 */ + osThreadDef(tca6416_task, test_tca6416_task, osPriorityNormal, 0, 128); + tca6416_taskHandle = osThreadCreate(osThread(tca6416_task), NULL); /* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ /* USER CODE END RTOS_THREADS */ @@ -569,10 +584,7 @@ void start_usart6_dma_test_task(void const *argument) void start_tca6416_task(void const *argument) { /* USER CODE BEGIN start_tca6416_task */ - uint8_t port0_data = 0; - uint8_t port1_data = 0; - uint8_t port2_data = 0; - uint8_t port3_data = 0; + uint8_t port0_data, port1_data; // 初始化第一个TCA6416 if(TCA6416_Init() != 0) @@ -580,52 +592,216 @@ void start_tca6416_task(void const *argument) Error_Handler(); } - // 配置第一个TCA6416端口方向 - // Port0: 全输入 - TCA6416_SetPortDirection(0, 0xFF); // 0xFF = 11111111b - // Port1: 全输入 - TCA6416_SetPortDirection(1, 0xFF); // 0xFF = 11111111b + // 初始化第二个TCA6416 + if(TCA6416_Init2() != 0) + { + Error_Handler(); + } - // 初始化第二个TCA6416 (使用SCL_PIN2和SDA_PIN2) - // 注意:这里需要修改TCA6416_Init函数以支持第二个芯片 - // 暂时使用相同的初始化函数,但实际使用时需要修改 + // 设置两个芯片的所有端口为输入 + if(TCA6416_SetPortDirection(0, 0xFF) != 0) Error_Handler(); + if(TCA6416_SetPortDirection(1, 0xFF) != 0) Error_Handler(); + if(TCA6416_SetPortDirection2(0, 0xFF) != 0) Error_Handler(); + if(TCA6416_SetPortDirection2(1, 0xFF) != 0) Error_Handler(); - // 配置第二个TCA6416端口方向 - // Port0: 全输入 - TCA6416_SetPortDirection(0, 0xFF); // 0xFF = 11111111b - // Port1: 全输入 - TCA6416_SetPortDirection(1, 0xFF); // 0xFF = 11111111b - - /* Infinite loop */ for(;;) { - // 读取第一个TCA6416的输入端口状态 + // 读取第一个芯片的输入状态 if(TCA6416_ReadPort(0, &port0_data) == 0) { tca6416_port0_status = port0_data; } - if(TCA6416_ReadPort(1, &port1_data) == 0) { tca6416_port1_status = port1_data; } - // 读取第二个TCA6416的输入端口状态 - // 注意:这里需要修改TCA6416_ReadPort函数以支持第二个芯片 - // 暂时使用相同的读取函数,但实际使用时需要修改 - if(TCA6416_ReadPort(0, &port2_data) == 0) + // 读取第二个芯片的输入状态 + if(TCA6416_ReadPort2(0, &port0_data) == 0) { - tca6416_port2_status = port2_data; + tca6416_port2_status = port0_data; + } + if(TCA6416_ReadPort2(1, &port1_data) == 0) + { + tca6416_port3_status = port1_data; } - if(TCA6416_ReadPort(1, &port3_data) == 0) - { - tca6416_port3_status = port3_data; - } - - // 任务延时 - vTaskDelay(10); // 10ms延时 + osDelay(100); // 100ms读取一次 } /* USER CODE END start_tca6416_task */ } +void test_tca6416_task(void const *argument) +{ + /* USER CODE BEGIN test_tca6416_task */ + uint8_t ret = 0; + uint8_t test_patterns[] = {0x00, 0xFF, 0xAA, 0x55, 0x0F, 0xF0, 0x5A, 0xA5}; + uint8_t pattern_index = 0; + uint8_t addr_scan_result[8] = {0}; // 存储地址扫描结果 + + // 等待系统稳定 + osDelay(100); + + // 步骤0: I2C地址扫描 + tca6416_test_step = 0; + for(uint8_t addr = 0x20; addr <= 0x27; addr++) + { + I2C_Start(); + ret = I2C_SendByte(addr << 1); + I2C_Stop(); + addr_scan_result[addr - 0x20] = ret; // 0=ACK, 1=NACK + osDelay(10); + } + + // 步骤1: 初始化TCA6416 + tca6416_test_step = 1; + tca6416_init_result = TCA6416_Init(); + + if(tca6416_init_result != 0) + { + // 初始化失败,停留在此步骤 + tca6416_error_count++; + while(1) + { + osDelay(1000); + } + } + + // 初始化成功,继续测试 + osDelay(50); + + for(;;) + { + // 步骤2: 设置Port0为输出,Port1为输入 + tca6416_test_step = 2; + tca6416_port0_dir = 0x00; // 0=输出 + tca6416_port1_dir = 0xFF; // 1=输入 + + ret = TCA6416_SetPortDirection(0, tca6416_port0_dir); + if(ret != 0) + { + tca6416_error_count++; + tca6416_i2c_ack_status = ret; + } + osDelay(10); + + ret = TCA6416_SetPortDirection(1, tca6416_port1_dir); + if(ret != 0) + { + tca6416_error_count++; + tca6416_i2c_ack_status = ret; + } + osDelay(10); + + // 步骤3: 写入测试模式到Port0 + tca6416_test_step = 3; + tca6416_test_pattern = test_patterns[pattern_index]; + tca6416_write_data = tca6416_test_pattern; + + ret = TCA6416_WritePort(0, tca6416_write_data); + if(ret != 0) + { + tca6416_error_count++; + tca6416_i2c_ack_status = ret; + } + osDelay(10); + + // 步骤4: 读取Port0的值(验证写入) + tca6416_test_step = 4; + ret = TCA6416_ReadPort(0, &tca6416_read_data); + if(ret != 0) + { + tca6416_error_count++; + tca6416_i2c_ack_status = ret; + } + else + { + // 更新状态变量 + tca6416_port0_status = tca6416_read_data; + } + osDelay(10); + + // 步骤5: 读取Port1的输入状态 + tca6416_test_step = 5; + ret = TCA6416_ReadPort(1, &tca6416_read_data); + if(ret != 0) + { + tca6416_error_count++; + tca6416_i2c_ack_status = ret; + } + else + { + // 更新状态变量 + tca6416_port1_status = tca6416_read_data; + } + osDelay(10); + + // 步骤6: 测试单个引脚操作 + tca6416_test_step = 6; + for(uint8_t pin = 0; pin < 8; pin++) + { + // 设置单个引脚为高 + ret = TCA6416_WritePin(0, pin, 1); + if(ret != 0) + { + tca6416_error_count++; + tca6416_i2c_ack_status = ret; + } + osDelay(5); + + // 读取验证 + uint8_t pin_state = 0; + ret = TCA6416_ReadPin(0, pin, &pin_state); + if(ret != 0) + { + tca6416_error_count++; + tca6416_i2c_ack_status = ret; + } + osDelay(5); + + // 设置单个引脚为低 + ret = TCA6416_WritePin(0, pin, 0); + if(ret != 0) + { + tca6416_error_count++; + tca6416_i2c_ack_status = ret; + } + osDelay(5); + } + + // 步骤7: 测试极性反转功能 + tca6416_test_step = 7; + ret = TCA6416_SetPortPolarity(0, 0xFF); // 反转所有位 + if(ret != 0) + { + tca6416_error_count++; + tca6416_i2c_ack_status = ret; + } + osDelay(10); + + // 读取并验证极性反转效果 + ret = TCA6416_ReadPort(0, &tca6416_read_data); + if(ret != 0) + { + tca6416_error_count++; + tca6416_i2c_ack_status = ret; + } + osDelay(10); + + // 恢复正常极性 + ret = TCA6416_SetPortPolarity(0, 0x00); + if(ret != 0) + { + tca6416_error_count++; + tca6416_i2c_ack_status = ret; + } + osDelay(10); + + // 切换到下一个测试模式 + pattern_index = (pattern_index + 1) % (sizeof(test_patterns) / sizeof(test_patterns[0])); + + // 延时后继续下一轮测试 + osDelay(500); + } + /* USER CODE END test_tca6416_task */ +} \ No newline at end of file diff --git a/Core/Src/gpio.c b/Core/Src/gpio.c index 0ff8448..8c5dcf6 100644 --- a/Core/Src/gpio.c +++ b/Core/Src/gpio.c @@ -93,11 +93,11 @@ void MX_GPIO_Init(void) HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /*Configure GPIO pins : PEPin PEPin PEPin PEPin */ - GPIO_InitStruct.Pin = LED3_Y_Pin|LED2_R_Pin|LED2_G_Pin|LED2_Y_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; - HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); + // GPIO_InitStruct.Pin = LED3_Y_Pin|LED2_R_Pin|LED2_G_Pin|LED2_Y_Pin; + // GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + // GPIO_InitStruct.Pull = GPIO_PULLUP; + // GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; + // HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); /*Configure GPIO pin : PtPin */ GPIO_InitStruct.Pin = EC11_KEY_Pin; @@ -172,11 +172,11 @@ void MX_GPIO_Init(void) HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /*Configure GPIO pins : PBPin PBPin */ - GPIO_InitStruct.Pin = DAC1_CS_Pin|DAC2_CS_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + // GPIO_InitStruct.Pin = DAC1_CS_Pin|DAC2_CS_Pin; + // GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + // GPIO_InitStruct.Pull = GPIO_PULLUP; + // GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + // HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /*Configure GPIO pin : PtPin */ GPIO_InitStruct.Pin = ADC_CS_Pin; diff --git a/MDK-ARM/controller_pcba.uvoptx b/MDK-ARM/controller_pcba.uvoptx index 45ca4c9..1d09d64 100644 --- a/MDK-ARM/controller_pcba.uvoptx +++ b/MDK-ARM/controller_pcba.uvoptx @@ -265,6 +265,36 @@ 1 uart6_stop_bits + + 23 + 1 + tca6416_init_result + + + 24 + 1 + tca6416_write_data + + + 25 + 1 + tca6416_read_data + + + 26 + 1 + tca6416_error_count + + + 27 + 1 + tca6416_test_pattern + + + 28 + 1 + tca6416_i2c_ack_status + 0 @@ -1880,7 +1910,7 @@ User/board - 1 + 0 0 0 0 diff --git a/User/application/inc/TCA6416.h b/User/application/inc/TCA6416.h index cfa71a7..3b1d03f 100644 --- a/User/application/inc/TCA6416.h +++ b/User/application/inc/TCA6416.h @@ -1,7 +1,7 @@ #ifndef __TCA6416_H #define __TCA6416_H -#include "stm32f4xx_hal.h" // 只包含基本的 HAL 头文件 +#include "main.h" #include /* GPIO定义 */ @@ -9,13 +9,14 @@ #define TCA6416_SCL_PORT GPIOE #define TCA6416_SDA_PIN GPIO_PIN_3 #define TCA6416_SDA_PORT GPIOE -#define TCA6416_SCL_PIN2 GPIO_PIN_5 -#define TCA6416_SCL_PORT2 GPIOE -#define TCA6416_SDA_PIN2 GPIO_PIN_4 -#define TCA6416_SDA_PORT2 GPIOE +#define TCA6416_SCL_PIN2 GPIO_PIN_5 +#define TCA6416_SCL_PORT2 GPIOE +#define TCA6416_SDA_PIN2 GPIO_PIN_4 +#define TCA6416_SDA_PORT2 GPIOE /* TCA6416 I2C地址 */ -#define TCA6416_ADDR 0x20 // 基础地址 (A0=A1=A2=GND) +#define TCA6416_ADDR 0x20 // 第一个芯片地址 (A0=A1=A2=GND) +#define TCA6416_ADDR2 0x21 // 第二个芯片地址 (A0=1, A1=A2=GND) /* 寄存器地址定义 */ #define TCA6416_INPUT_PORT0 0x00 // 输入端口0 @@ -28,32 +29,69 @@ #define TCA6416_POL_INV_PORT1 0x05 // 极性反转端口1 /* 软件I2C延时定义 */ -#define I2C_DELAY() HAL_Delay(1) // 可以根据实际需要调整延时 +#define I2C_DELAY() HAL_Delay(5) // 增加延时时间到5ms -/* 软件I2C基本操作函数 */ +/* 第一个芯片的软件I2C基本操作函数 */ #define SCL_HIGH() HAL_GPIO_WritePin(TCA6416_SCL_PORT, TCA6416_SCL_PIN, GPIO_PIN_SET) #define SCL_LOW() HAL_GPIO_WritePin(TCA6416_SCL_PORT, TCA6416_SCL_PIN, GPIO_PIN_RESET) #define SDA_HIGH() HAL_GPIO_WritePin(TCA6416_SDA_PORT, TCA6416_SDA_PIN, GPIO_PIN_SET) #define SDA_LOW() HAL_GPIO_WritePin(TCA6416_SDA_PORT, TCA6416_SDA_PIN, GPIO_PIN_RESET) #define SDA_READ() HAL_GPIO_ReadPin(TCA6416_SDA_PORT, TCA6416_SDA_PIN) +/* SDA输入/输出模式切换宏 */ +#define SDA_INPUT_MODE() do { \ + GPIO_InitTypeDef GPIO_InitStruct = {0}; \ + GPIO_InitStruct.Pin = TCA6416_SDA_PIN; \ + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; \ + GPIO_InitStruct.Pull = GPIO_NOPULL; \ + HAL_GPIO_Init(TCA6416_SDA_PORT, &GPIO_InitStruct); \ +} while(0) + +#define SDA_OUTPUT_MODE() do { \ + GPIO_InitTypeDef GPIO_InitStruct = {0}; \ + GPIO_InitStruct.Pin = TCA6416_SDA_PIN; \ + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; \ + GPIO_InitStruct.Pull = GPIO_NOPULL; \ + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; \ + HAL_GPIO_Init(TCA6416_SDA_PORT, &GPIO_InitStruct); \ +} while(0) + +/* 第二个芯片的软件I2C基本操作函数 */ +#define SCL_HIGH2() HAL_GPIO_WritePin(TCA6416_SCL_PORT2, TCA6416_SCL_PIN2, GPIO_PIN_SET) +#define SCL_LOW2() HAL_GPIO_WritePin(TCA6416_SCL_PORT2, TCA6416_SCL_PIN2, GPIO_PIN_RESET) +#define SDA_HIGH2() HAL_GPIO_WritePin(TCA6416_SDA_PORT2, TCA6416_SDA_PIN2, GPIO_PIN_SET) +#define SDA_LOW2() HAL_GPIO_WritePin(TCA6416_SDA_PORT2, TCA6416_SDA_PIN2, GPIO_PIN_RESET) +#define SDA_READ2() HAL_GPIO_ReadPin(TCA6416_SDA_PORT2, TCA6416_SDA_PIN2) + /* 函数声明 */ void TCA6416_GPIO_Init(void); uint8_t TCA6416_Init(void); +uint8_t TCA6416_Init2(void); // 第二个芯片的初始化函数 uint8_t TCA6416_WritePort(uint8_t port, uint8_t data); +uint8_t TCA6416_WritePort2(uint8_t port, uint8_t data); // 第二个芯片的写端口函数 uint8_t TCA6416_ReadPort(uint8_t port, uint8_t *data); +uint8_t TCA6416_ReadPort2(uint8_t port, uint8_t *data); // 第二个芯片的读端口函数 uint8_t TCA6416_SetPortDirection(uint8_t port, uint8_t direction); +uint8_t TCA6416_SetPortDirection2(uint8_t port, uint8_t direction); // 第二个芯片的设置方向函数 uint8_t TCA6416_SetPortPolarity(uint8_t port, uint8_t polarity); +uint8_t TCA6416_SetPortPolarity2(uint8_t port, uint8_t polarity); // 第二个芯片的设置极性函数 uint8_t TCA6416_WritePin(uint8_t port, uint8_t pin, uint8_t state); uint8_t TCA6416_ReadPin(uint8_t port, uint8_t pin, uint8_t *state); /* 软件I2C底层函数 */ void I2C_Start(void); +void I2C_Start2(void); // 第二个芯片的I2C起始信号 void I2C_Stop(void); +void I2C_Stop2(void); // 第二个芯片的I2C停止信号 void I2C_Ack(void); +void I2C_Ack2(void); // 第二个芯片的I2C应答 void I2C_NAck(void); +void I2C_NAck2(void); // 第二个芯片的I2C非应答 uint8_t I2C_WaitAck(void); -void I2C_SendByte(uint8_t byte); +uint8_t I2C_WaitAck2(void); // 第二个芯片的等待应答 +uint8_t I2C_SendByte(uint8_t byte); // 修正返回值类型 +void I2C_SendByte2(uint8_t byte); // 第二个芯片的发送字节 uint8_t I2C_ReadByte(void); +uint8_t I2C_ReadByte2(void); // 第二个芯片的读取字节 #endif /* __TCA6416_H */ diff --git a/User/application/inc/tca6416_status.h b/User/application/inc/tca6416_status.h new file mode 100644 index 0000000..19c1533 --- /dev/null +++ b/User/application/inc/tca6416_status.h @@ -0,0 +1,12 @@ +#ifndef __TCA6416_STATUS_H +#define __TCA6416_STATUS_H + +#include + +// 声明TCA6416状态变量 +extern volatile uint8_t tca6416_port0_status; // 第一个TCA6416的Port0状态 +extern volatile uint8_t tca6416_port1_status; // 第一个TCA6416的Port1状态 +extern volatile uint8_t tca6416_port2_status; // 第二个TCA6416的Port0状态 +extern volatile uint8_t tca6416_port3_status; // 第二个TCA6416的Port1状态 + +#endif /* __TCA6416_STATUS_H */ \ No newline at end of file diff --git a/User/application/src/TCA6416.c b/User/application/src/TCA6416.c index d6f9dfe..b65a238 100644 --- a/User/application/src/TCA6416.c +++ b/User/application/src/TCA6416.c @@ -1,4 +1,6 @@ +#include "main.h" #include "TCA6416.h" +#include "stm32f4xx_hal.h" // 更新HAL库头文件路径 /** * @brief 初始化TCA6416的GPIO @@ -10,16 +12,22 @@ void TCA6416_GPIO_Init(void) // 使能GPIOE时钟 __HAL_RCC_GPIOE_CLK_ENABLE(); - // 配置SCL和SDA引脚 + // 配置第一个芯片的SCL和SDA引脚为开漏输出 GPIO_InitStruct.Pin = TCA6416_SCL_PIN | TCA6416_SDA_PIN; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; // 开漏输出 + GPIO_InitStruct.Pull = GPIO_NOPULL; // 无内部上拉,依赖外部上拉 + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(TCA6416_SCL_PORT, &GPIO_InitStruct); - // 初始状态设为高电平 + // 配置第二个芯片的SCL和SDA引脚为开漏输出 + GPIO_InitStruct.Pin = TCA6416_SCL_PIN2 | TCA6416_SDA_PIN2; + HAL_GPIO_Init(TCA6416_SCL_PORT2, &GPIO_InitStruct); + + // 初始状态设为高电平(实际由外部上拉电阻拉高) SCL_HIGH(); SDA_HIGH(); + SCL_HIGH2(); + SDA_HIGH2(); } /** @@ -27,12 +35,13 @@ void TCA6416_GPIO_Init(void) */ void I2C_Start(void) { + SDA_OUTPUT_MODE(); // 确保SDA为输出模式 SDA_HIGH(); SCL_HIGH(); I2C_DELAY(); - SDA_LOW(); + SDA_LOW(); // SDA下降沿(SCL为高) I2C_DELAY(); - SCL_LOW(); + SCL_LOW(); // 拉低SCL } /** @@ -40,12 +49,13 @@ void I2C_Start(void) */ void I2C_Stop(void) { + SDA_OUTPUT_MODE(); // 确保SDA为输出模式 SCL_LOW(); SDA_LOW(); I2C_DELAY(); SCL_HIGH(); I2C_DELAY(); - SDA_HIGH(); + SDA_HIGH(); // SDA上升沿(SCL为高) I2C_DELAY(); } @@ -85,6 +95,7 @@ uint8_t I2C_WaitAck(void) SCL_LOW(); SDA_HIGH(); + SDA_INPUT_MODE(); I2C_DELAY(); SCL_HIGH(); I2C_DELAY(); @@ -92,6 +103,7 @@ uint8_t I2C_WaitAck(void) ack = SDA_READ() ? 1 : 0; SCL_LOW(); + SDA_OUTPUT_MODE(); return ack; } @@ -99,13 +111,13 @@ uint8_t I2C_WaitAck(void) * @brief 软件I2C发送一个字节 * @param byte: 要发送的字节 */ -void I2C_SendByte(uint8_t byte) +uint8_t I2C_SendByte(uint8_t byte) { uint8_t i; - for(i = 0; i < 8; i++) { SCL_LOW(); + I2C_DELAY(); if(byte & 0x80) SDA_HIGH(); else @@ -116,6 +128,16 @@ void I2C_SendByte(uint8_t byte) I2C_DELAY(); } SCL_LOW(); + // 释放SDA,准备接收ACK + SDA_HIGH(); + SDA_INPUT_MODE(); + I2C_DELAY(); + SCL_HIGH(); + I2C_DELAY(); + uint8_t ack = SDA_READ() ? 1 : 0; // 0=ACK, 1=NACK + SCL_LOW(); + SDA_OUTPUT_MODE(); + return ack; } /** @@ -149,6 +171,7 @@ uint8_t TCA6416_Init(void) { // 初始化GPIO TCA6416_GPIO_Init(); + HAL_Delay(50); // 默认将所有引脚设置为输入 if(TCA6416_SetPortDirection(0, 0xFF) != 0) return 1; @@ -176,14 +199,11 @@ uint8_t TCA6416_WritePort(uint8_t port, uint8_t data) uint8_t reg_addr = (port == 0) ? TCA6416_OUTPUT_PORT0 : TCA6416_OUTPUT_PORT1; I2C_Start(); - I2C_SendByte(TCA6416_ADDR << 1); // 写地址 - if(I2C_WaitAck()) { I2C_Stop(); return 1; } + if(I2C_SendByte(TCA6416_ADDR << 1)) { I2C_Stop(); return 1; } // 直接使用返回值 - I2C_SendByte(reg_addr); // 寄存器地址 - if(I2C_WaitAck()) { I2C_Stop(); return 1; } + if(I2C_SendByte(reg_addr)) { I2C_Stop(); return 1; } // 直接使用返回值 - I2C_SendByte(data); // 数据 - if(I2C_WaitAck()) { I2C_Stop(); return 1; } + if(I2C_SendByte(data)) { I2C_Stop(); return 1; } // 直接使用返回值 I2C_Stop(); return 0; @@ -200,15 +220,12 @@ uint8_t TCA6416_ReadPort(uint8_t port, uint8_t *data) uint8_t reg_addr = (port == 0) ? TCA6416_INPUT_PORT0 : TCA6416_INPUT_PORT1; I2C_Start(); - I2C_SendByte(TCA6416_ADDR << 1); // 写地址 - if(I2C_WaitAck()) { I2C_Stop(); return 1; } + if(I2C_SendByte(TCA6416_ADDR << 1)) { I2C_Stop(); return 1; } // 直接使用返回值 - I2C_SendByte(reg_addr); // 寄存器地址 - if(I2C_WaitAck()) { I2C_Stop(); return 1; } + if(I2C_SendByte(reg_addr)) { I2C_Stop(); return 1; } // 直接使用返回值 I2C_Start(); - I2C_SendByte((TCA6416_ADDR << 1) | 0x01); // 读地址 - if(I2C_WaitAck()) { I2C_Stop(); return 1; } + if(I2C_SendByte((TCA6416_ADDR << 1) | 0x01)) { I2C_Stop(); return 1; } // 直接使用返回值 *data = I2C_ReadByte(); // 读取数据 I2C_NAck(); @@ -228,14 +245,11 @@ uint8_t TCA6416_SetPortDirection(uint8_t port, uint8_t direction) uint8_t reg_addr = (port == 0) ? TCA6416_CONFIG_PORT0 : TCA6416_CONFIG_PORT1; I2C_Start(); - I2C_SendByte(TCA6416_ADDR << 1); // 写地址 - if(I2C_WaitAck()) { I2C_Stop(); return 1; } + if(I2C_SendByte(TCA6416_ADDR << 1)) { I2C_Stop(); return 1; } // 直接使用返回值 - I2C_SendByte(reg_addr); // 寄存器地址 - if(I2C_WaitAck()) { I2C_Stop(); return 1; } + if(I2C_SendByte(reg_addr)) { I2C_Stop(); return 1; } // 直接使用返回值 - I2C_SendByte(direction); // 方向设置 - if(I2C_WaitAck()) { I2C_Stop(); return 1; } + if(I2C_SendByte(direction)) { I2C_Stop(); return 1; } // 直接使用返回值 I2C_Stop(); return 0; @@ -252,14 +266,11 @@ uint8_t TCA6416_SetPortPolarity(uint8_t port, uint8_t polarity) uint8_t reg_addr = (port == 0) ? TCA6416_POL_INV_PORT0 : TCA6416_POL_INV_PORT1; I2C_Start(); - I2C_SendByte(TCA6416_ADDR << 1); // 写地址 - if(I2C_WaitAck()) { I2C_Stop(); return 1; } + if(I2C_SendByte(TCA6416_ADDR << 1)) { I2C_Stop(); return 1; } // 直接使用返回值 - I2C_SendByte(reg_addr); // 寄存器地址 - if(I2C_WaitAck()) { I2C_Stop(); return 1; } + if(I2C_SendByte(reg_addr)) { I2C_Stop(); return 1; } // 直接使用返回值 - I2C_SendByte(polarity); // 极性设置 - if(I2C_WaitAck()) { I2C_Stop(); return 1; } + if(I2C_SendByte(polarity)) { I2C_Stop(); return 1; } // 直接使用返回值 I2C_Stop(); return 0; @@ -306,3 +317,228 @@ uint8_t TCA6416_ReadPin(uint8_t port, uint8_t pin, uint8_t *state) *state = (port_data >> pin) & 0x01; return 0; } + +/* 第二个芯片的I2C操作函数 */ +void I2C_Start2(void) +{ + SDA_HIGH2(); + SCL_HIGH2(); + I2C_DELAY(); + SDA_LOW2(); + I2C_DELAY(); + SCL_LOW2(); +} + +void I2C_Stop2(void) +{ + SCL_LOW2(); + SDA_LOW2(); + I2C_DELAY(); + SCL_HIGH2(); + I2C_DELAY(); + SDA_HIGH2(); + I2C_DELAY(); +} + +void I2C_Ack2(void) +{ + SCL_LOW2(); + SDA_LOW2(); + I2C_DELAY(); + SCL_HIGH2(); + I2C_DELAY(); + SCL_LOW2(); +} + +void I2C_NAck2(void) +{ + SCL_LOW2(); + SDA_HIGH2(); + I2C_DELAY(); + SCL_HIGH2(); + I2C_DELAY(); + SCL_LOW2(); +} + +uint8_t I2C_WaitAck2(void) +{ + uint8_t ack; + + SCL_LOW2(); + SDA_HIGH2(); + I2C_DELAY(); + SCL_HIGH2(); + I2C_DELAY(); + + ack = SDA_READ2() ? 1 : 0; + + SCL_LOW2(); + return ack; +} + +void I2C_SendByte2(uint8_t byte) +{ + uint8_t i; + + for(i = 0; i < 8; i++) + { + SCL_LOW2(); + if(byte & 0x80) + SDA_HIGH2(); + else + SDA_LOW2(); + byte <<= 1; + I2C_DELAY(); + SCL_HIGH2(); + I2C_DELAY(); + } + SCL_LOW2(); +} + +uint8_t I2C_ReadByte2(void) +{ + uint8_t i, byte = 0; + + SDA_HIGH2(); + for(i = 0; i < 8; i++) + { + SCL_LOW2(); + I2C_DELAY(); + SCL_HIGH2(); + byte <<= 1; + if(SDA_READ2()) + byte |= 0x01; + I2C_DELAY(); + } + SCL_LOW2(); + return byte; +} + +/** + * @brief 初始化第二个TCA6416 + * @retval 0:成功 1:失败 + */ +uint8_t TCA6416_Init2(void) +{ + // 初始化GPIO + TCA6416_GPIO_Init(); + + // 增加延时以确保设备稳定 + HAL_Delay(10); + + // 默认将所有引脚设置为输入 + if(TCA6416_SetPortDirection2(0, 0xFF) != 0) return 1; + if(TCA6416_SetPortDirection2(1, 0xFF) != 0) return 1; + + // 设置默认输出值为0 + if(TCA6416_WritePort2(0, 0x00) != 0) return 1; + if(TCA6416_WritePort2(1, 0x00) != 0) return 1; + + // 设置默认极性(非反转) + if(TCA6416_SetPortPolarity2(0, 0x00) != 0) return 1; + if(TCA6416_SetPortPolarity2(1, 0x00) != 0) return 1; + + return 0; +} + +/** + * @brief 向第二个TCA6416的端口写入数据 + * @param port: 端口号(0或1) + * @param data: 要写入的数据 + * @retval 0:成功 1:失败 + */ +uint8_t TCA6416_WritePort2(uint8_t port, uint8_t data) +{ + uint8_t reg_addr = (port == 0) ? TCA6416_OUTPUT_PORT0 : TCA6416_OUTPUT_PORT1; + + I2C_Start2(); + I2C_SendByte2(TCA6416_ADDR2 << 1); // 写地址 + if(I2C_WaitAck2()) { I2C_Stop2(); return 1; } + + I2C_SendByte2(reg_addr); // 寄存器地址 + if(I2C_WaitAck2()) { I2C_Stop2(); return 1; } + + I2C_SendByte2(data); // 数据 + if(I2C_WaitAck2()) { I2C_Stop2(); return 1; } + + I2C_Stop2(); + return 0; +} + +/** + * @brief 从第二个TCA6416的端口读取数据 + * @param port: 端口号(0或1) + * @param data: 存储读取数据的指针 + * @retval 0:成功 1:失败 + */ +uint8_t TCA6416_ReadPort2(uint8_t port, uint8_t *data) +{ + uint8_t reg_addr = (port == 0) ? TCA6416_INPUT_PORT0 : TCA6416_INPUT_PORT1; + + I2C_Start2(); + I2C_SendByte2(TCA6416_ADDR2 << 1); // 写地址 + if(I2C_WaitAck2()) { I2C_Stop2(); return 1; } + + I2C_SendByte2(reg_addr); // 寄存器地址 + if(I2C_WaitAck2()) { I2C_Stop2(); return 1; } + + I2C_Start2(); + I2C_SendByte2((TCA6416_ADDR2 << 1) | 0x01); // 读地址 + if(I2C_WaitAck2()) { I2C_Stop2(); return 1; } + + *data = I2C_ReadByte2(); // 读取数据 + I2C_NAck2(); + + I2C_Stop2(); + return 0; +} + +/** + * @brief 设置第二个TCA6416的端口方向 + * @param port: 端口号(0或1) + * @param direction: 0 = 输出, 1 = 输入 + * @retval 0:成功 1:失败 + */ +uint8_t TCA6416_SetPortDirection2(uint8_t port, uint8_t direction) +{ + uint8_t reg_addr = (port == 0) ? TCA6416_CONFIG_PORT0 : TCA6416_CONFIG_PORT1; + + I2C_Start2(); + I2C_SendByte2(TCA6416_ADDR2 << 1); // 写地址 + if(I2C_WaitAck2()) { I2C_Stop2(); return 1; } + + I2C_SendByte2(reg_addr); // 寄存器地址 + if(I2C_WaitAck2()) { I2C_Stop2(); return 1; } + + I2C_SendByte2(direction); // 方向设置 + if(I2C_WaitAck2()) { I2C_Stop2(); return 1; } + + I2C_Stop2(); + return 0; +} + +/** + * @brief 设置第二个TCA6416的端口极性 + * @param port: 端口号(0或1) + * @param polarity: 0 = 非反转, 1 = 反转 + * @retval 0:成功 1:失败 + */ +uint8_t TCA6416_SetPortPolarity2(uint8_t port, uint8_t polarity) +{ + uint8_t reg_addr = (port == 0) ? TCA6416_POL_INV_PORT0 : TCA6416_POL_INV_PORT1; + + I2C_Start2(); + I2C_SendByte2(TCA6416_ADDR2 << 1); // 写地址 + if(I2C_WaitAck2()) { I2C_Stop2(); return 1; } + + I2C_SendByte2(reg_addr); // 寄存器地址 + if(I2C_WaitAck2()) { I2C_Stop2(); return 1; } + + I2C_SendByte2(polarity); // 极性设置 + if(I2C_WaitAck2()) { I2C_Stop2(); return 1; } + + I2C_Stop2(); + return 0; +} + + diff --git a/User/application/src/tcpserverc.c b/User/application/src/tcpserverc.c index 62b64d5..4ef10d4 100644 --- a/User/application/src/tcpserverc.c +++ b/User/application/src/tcpserverc.c @@ -15,7 +15,8 @@ #include "communication_protocol.h" #include "user_gpio.h" #include "tim.h" -#include "ad7124.h" +#include "ad7124.h" +#include "tca6416_status.h" // 添加TCA6416状态头文件 // 添加test_adc_read_data变量定义 uint8_t test_adc_read_data[74] = {0}; // 74字节的测试数据缓冲区 @@ -95,12 +96,6 @@ uint8_t adc_set_data[22] = { 0x0D,0xF0,// 比例阀2输出高字节, 比例阀2输出低字节 }; -// 添加外部声明 -extern volatile uint8_t tca6416_port0_status; -extern volatile uint8_t tca6416_port1_status; -extern volatile uint8_t tca6416_port2_status; -extern volatile uint8_t tca6416_port3_status; - // 校验和函数 uint8_t calc_checksum(const uint8_t *data, uint8_t start, uint8_t end) { uint8_t checksum = 0; @@ -405,29 +400,27 @@ uint16_t handle_type_87(const uint8_t *body, uint16_t body_len, uint8_t *tx) tx[8] = reply_type; // 填充TCA6416引脚状态到第9-10字节 - tx[9] = tca6416_port0_status; // 第一个TCA6416的Port0状态 - tx[10] = tca6416_port1_status; // 第一个TCA6416的Port1状态 - tx[11] = tca6416_port2_status; // 第二个TCA6416的Port0状态 - tx[12] = tca6416_port3_status; // 第二个TCA6416的Port1状态 + tx[9] = tca6416_port2_status; // 第二个TCA6416的Port0状态 + tx[10] = tca6416_port3_status; // 第二个TCA6416的Port1状态 - // 填充AD7124原始数据到tx[13]~tx[77],每通道4字节,MSB格式 + // 填充AD7124原始数据到tx[11]~tx[75],每通道4字节,MSB格式 extern ad7124_analog_t ad7124_analog[AD7124_CHANNEL_EN_MAX]; for (int ch = 0; ch < AD7124_CHANNEL_EN_MAX; ++ch) { int32_t data = ad7124_analog[ch].data; - tx[13 + ch * 4 + 0] = (data >> 24) & 0xFF; - tx[13 + ch * 4 + 1] = (data >> 16) & 0xFF; - tx[13 + ch * 4 + 2] = (data >> 8) & 0xFF; - tx[13 + ch * 4 + 3] = (data) & 0xFF; + tx[11 + ch * 4 + 0] = (data >> 24) & 0xFF; + tx[11 + ch * 4 + 1] = (data >> 16) & 0xFF; + tx[11 + ch * 4 + 2] = (data >> 8) & 0xFF; + tx[11 + ch * 4 + 3] = (data) & 0xFF; } - // 其余tx[77]~tx[83]可按需要填充(如比例阀等),此处保持原样或补零 - for (int i = 13 + AD7124_CHANNEL_EN_MAX * 4; i < 83; ++i) { + // 其余tx[75]~tx[81]可按需要填充(如比例阀等),此处保持原样或补零 + for (int i = 11 + AD7124_CHANNEL_EN_MAX * 4; i < 81; ++i) { tx[i] = 0; } // 校验和 uint16_t checksum = 0; - for (int i = 4; i < 84; ++i) // 4~83(源地址+目标地址+类型+74字节) + for (int i = 4; i < 82; ++i) // 4~81(源地址+目标地址+类型+72字节) { checksum += tx[i]; }