zhuls 发表于 2025-5-18 19:11:52

21cnsound 发表于 2025-5-18 18:05
建议检查、排查“无法预知的错误”,遇到问题就躲避不是学习的一个端正态度。

并且,玩儿单片机的乐趣就 ...

说的是,奈何菜鸟功力不足,能想到的问题都查了个遍,什么上下拉电阻、改延时、加滤波、、,(手边就一个28元的玩具级的逻辑分析仪{:yun:})还是抓不住这个随机的错误,为止卡了快1个月了。。
才想到要拆分总线,拆了之后可以是可以,但总觉得代码不够意思,一组IIc一套代码,啰嗦极了。。

zhuls 发表于 2025-5-18 19:14:41

DebugLab 发表于 2025-5-18 17:46
从机较多要减小上拉电阻,如4.7K改2.2K,时钟频率不要超过400K

是的,上拉改过1K8的,,总线串电阻、并100P电容都试过,速率一度改为250K左右,一样会随机出现{:ciya:}

zhuls 发表于 2025-5-18 19:16:19

DebugLab 发表于 2025-5-18 18:00
实验箱例程“AI8051U-DEMO-CODE-V1.2”的“84-USB录放音声卡-TLV320AIC23B-内部36.864M-外接32768Hz晶振 ...

谢谢!我的代码分拆后,各驱各的没有题。

ercircle 发表于 2025-5-18 19:58:17

这个需求扔给Ai,代码已经写的大差不差了,是这个意思不:

#ifndef I2C_MANAGER_H
#define I2C_MANAGER_H

#include <stdint.h>
#include <stdbool.h>

// I2C引脚操作函数指针类型定义
typedef void (*I2CPinSetFunc)(bool state);
typedef bool (*I2CPinGetFunc)(void);
typedef void (*I2CDelayFunc)(uint32_t us);

// I2C设备配置结构体
typedef struct {
    I2CPinSetFunc sda_set;   // SDA引脚设置函数
    I2CPinGetFunc sda_get;   // SDA引脚读取函数
    I2CPinSetFunc scl_set;   // SCL引脚设置函数
    I2CDelayFunc delay_us;   // 延时函数
    uint32_t delay_base;       // 基础延时参数
} I2CDeviceConfig;

// I2C设备句柄
typedef struct {
    I2CDeviceConfig* config;   // 设备配置
    uint8_t device_addr;       // 设备地址
} I2CDeviceHandle;

// 初始化I2C设备配置
void I2C_InitDeviceConfig(I2CDeviceConfig* config,
                         I2CPinSetFunc sda_set, I2CPinGetFunc sda_get,
                         I2CPinSetFunc scl_set, I2CDelayFunc delay_us,
                         uint32_t delay_base);

// 初始化I2C设备句柄
void I2C_InitDeviceHandle(I2CDeviceHandle* handle,
                         I2CDeviceConfig* config, uint8_t device_addr);

// I2C起始信号
void I2C_Start(I2CDeviceHandle* handle);

// I2C停止信号
void I2C_Stop(I2CDeviceHandle* handle);

// 发送一个字节
bool I2C_WriteByte(I2CDeviceHandle* handle, uint8_t data);

// 读取一个字节
uint8_t I2C_ReadByte(I2CDeviceHandle* handle, bool ack);

// 延时函数
void I2C_Delay(I2CDeviceHandle* handle, uint32_t factor);

#endif // I2C_MANAGER_H    #include "i2c_manager.h"
#include "STC8H.h"// 根据实际芯片型号调整头文件

// 初始化I2C设备配置
void I2C_InitDeviceConfig(I2CDeviceConfig* config,
                         I2CPinSetFunc sda_set, I2CPinGetFunc sda_get,
                         I2CPinSetFunc scl_set, I2CDelayFunc delay_us,
                         uint32_t delay_base) {
    config->sda_set = sda_set;
    config->sda_get = sda_get;
    config->scl_set = scl_set;
    config->delay_us = delay_us;
    config->delay_base = delay_base;
}

// 初始化I2C设备句柄
void I2C_InitDeviceHandle(I2CDeviceHandle* handle,
                         I2CDeviceConfig* config, uint8_t device_addr) {
    handle->config = config;
    handle->device_addr = device_addr;
}

// I2C延时函数
void I2C_Delay(I2CDeviceHandle* handle, uint32_t factor) {
    handle->config->delay_us(handle->config->delay_base * factor);
}

// I2C起始信号
void I2C_Start(I2CDeviceHandle* handle) {
    handle->config->sda_set(1);
    handle->config->scl_set(1);
    I2C_Delay(handle, 4);
    handle->config->sda_set(0);
    I2C_Delay(handle, 4);
    handle->config->scl_set(0);
}

// I2C停止信号
void I2C_Stop(I2CDeviceHandle* handle) {
    handle->config->sda_set(0);
    handle->config->scl_set(1);
    I2C_Delay(handle, 4);
    handle->config->sda_set(1);
    I2C_Delay(handle, 4);
}

// 发送一个字节
bool I2C_WriteByte(I2CDeviceHandle* handle, uint8_t data) {
    uint8_t i;
    bool ack;
   
    for (i = 0; i < 8; i++) {
      handle->config->sda_set((data & 0x80) != 0);
      data <<= 1;
      I2C_Delay(handle, 2);
      handle->config->scl_set(1);
      I2C_Delay(handle, 4);
      handle->config->scl_set(0);
      I2C_Delay(handle, 2);
    }
   
    // 接收ACK
    handle->config->sda_set(1);
    I2C_Delay(handle, 2);
    handle->config->scl_set(1);
    I2C_Delay(handle, 2);
    ack = handle->config->sda_get();
    handle->config->scl_set(0);
    I2C_Delay(handle, 2);
   
    return !ack; // 返回ACK状态,0表示成功
}

// 读取一个字节
uint8_t I2C_ReadByte(I2CDeviceHandle* handle, bool ack) {
    uint8_t i, data = 0;
   
    handle->config->sda_set(1);
   
    for (i = 0; i < 8; i++) {
      data <<= 1;
      I2C_Delay(handle, 2);
      handle->config->scl_set(1);
      I2C_Delay(handle, 2);
      if (handle->config->sda_get()) {
            data |= 0x01;
      }
      handle->config->scl_set(0);
    }
   
    // 发送ACK/NACK
    handle->config->sda_set(!ack);
    I2C_Delay(handle, 2);
    handle->config->scl_set(1);
    I2C_Delay(handle, 4);
    handle->config->scl_set(0);
    I2C_Delay(handle, 2);
   
    return data;
}    #include "i2c_manager.h"
#include "STC8H.h"// 根据实际芯片型号调整头文件

// 引脚操作函数实现
// 24c08 (P37:SDA, P36:SCL)
static void I2C_24C08_SDA_Set(bool state) { P37 = state; }
static bool I2C_24C08_SDA_Get(void) { return P37; }
static void I2C_24C08_SCL_Set(bool state) { P36 = state; }

// RX8025T (P15:SDA, P14:SCL)
static void I2C_RX8025T_SDA_Set(bool state) { P15 = state; }
static bool I2C_RX8025T_SDA_Get(void) { return P15; }
static void I2C_RX8025T_SCL_Set(bool state) { P14 = state; }

// SC7A20 (P22:SDA, P21:SCL)
static void I2C_SC7A20_SDA_Set(bool state) { P22 = state; }
static bool I2C_SC7A20_SDA_Get(void) { return P22; }
static void I2C_SC7A20_SCL_Set(bool state) { P21 = state; }

// 延时函数
static void I2C_Delay_Us(uint32_t us) {
    // 根据实际系统时钟实现延时
    // 这里简化处理,实际应用中需要根据系统时钟频率进行精确延时
    while(us--);
}

// 设备配置和句柄
static I2CDeviceConfig i2c_24c08_config;
static I2CDeviceConfig i2c_rx8025t_config;
static I2CDeviceConfig i2c_sc7a20_config;

static I2CDeviceHandle i2c_24c08_handle;
static I2CDeviceHandle i2c_rx8025t_handle;
static I2CDeviceHandle i2c_sc7a20_handle;

// 引脚初始化
void Init_GPIO(void) {
    // 配置为开漏输出
    P3M1 |= 0xC0;// P36,P37开漏
    P3M0 &= 0x3F;
   
    P1M1 |= 0x30;// P14,P15开漏
    P1M0 &= 0xCF;
   
    P2M1 |= 0x06;// P21,P22开漏
    P2M0 &= 0xF9;
}

// I2C设备初始化
void Init_I2C_Devices(void) {
    // 初始化24c08配置
    I2C_InitDeviceConfig(&i2c_24c08_config,
                     I2C_24C08_SDA_Set, I2C_24C08_SDA_Get,
                     I2C_24C08_SCL_Set, I2C_Delay_Us, 5);
                     
    // 初始化RX8025T配置
    I2C_InitDeviceConfig(&i2c_rx8025t_config,
                     I2C_RX8025T_SDA_Set, I2C_RX8025T_SDA_Get,
                     I2C_RX8025T_SCL_Set, I2C_Delay_Us, 10);
                     
    // 初始化SC7A20配置
    I2C_InitDeviceConfig(&i2c_sc7a20_config,
                     I2C_SC7A20_SDA_Set, I2C_SC7A20_SDA_Get,
                     I2C_SC7A20_SCL_Set, I2C_Delay_Us, 8);
   
    // 初始化设备句柄
    I2C_InitDeviceHandle(&i2c_24c08_handle, &i2c_24c08_config, 0xA0);
    I2C_InitDeviceHandle(&i2c_rx8025t_handle, &i2c_rx8025t_config, 0xDE);
    I2C_InitDeviceHandle(&i2c_sc7a20_handle, &i2c_sc7a20_config, 0x30);
}

// 24c08读写示例
void EEPROM_WriteByte(uint8_t addr, uint8_t data) {
    I2C_Start(&i2c_24c08_handle);
    I2C_WriteByte(&i2c_24c08_handle, i2c_24c08_handle.device_addr);
    I2C_WriteByte(&i2c_24c08_handle, addr);
    I2C_WriteByte(&i2c_24c08_handle, data);
    I2C_Stop(&i2c_24c08_handle);
}

uint8_t EEPROM_ReadByte(uint8_t addr) {
    uint8_t data;
   
    I2C_Start(&i2c_24c08_handle);
    I2C_WriteByte(&i2c_24c08_handle, i2c_24c08_handle.device_addr);
    I2C_WriteByte(&i2c_24c08_handle, addr);
   
    I2C_Start(&i2c_24c08_handle);
    I2C_WriteByte(&i2c_24c08_handle, i2c_24c08_handle.device_addr | 0x01);
    data = I2C_ReadByte(&i2c_24c08_handle, false);
    I2C_Stop(&i2c_24c08_handle);
   
    return data;
}

// 主函数
void main(void) {
    Init_GPIO();
    Init_I2C_Devices();
   
    // 示例:向24c08写入数据并读取
    EEPROM_WriteByte(0x00, 0x55);
   
    while(1) {
      // 主循环
    }
}   

21cnsound 发表于 2025-5-19 08:42:43

zhuls 发表于 2025-5-18 19:11
说的是,奈何菜鸟功力不足,能想到的问题都查了个遍,什么上下拉电阻、改延时、加滤波、、,(手边就一个 ...

电路图和代码发上来,让大家一起帮忙找茬

_奶咖君_ 发表于 2025-5-19 10:44:33

一个思路是把用到的引脚传入软件IIC的函数里面,,但是由于51单片机的GPIO的寄存器不能直接通过指针访问,,所以你还得写几个驱动GPIO的函数,而且用这个函数驱动的话,非常影响性能,,如果追求通讯速率的话,可以用宏定义替换这些GPIO驱动函数。但是这样的话,如果需要修改引脚的话只能重新烧程序。。不过只对一块主板的话也不是不行。。

Ayb_ice 发表于 2025-5-19 11:17:18

本身可以挂一起,减小上拉电阻

ggqqss 发表于 2025-5-28 11:04:20

zhuls 发表于 2025-5-18 19:14
是的,上拉改过1K8的,,总线串电阻、并100P电容都试过,速率一度改为250K左右,一样会随机出现 ...

要不要换个思路?不用管随机出现错误的原因,而是想办法识别对错,然后建立重发机制。
页: 1 [2]
查看完整版本: 求组,GPIO的分组(不知合不合适这样叫?)