建议检查、排查“无法预知的错误”,遇到问题就躲避不是学习的一个端正态度。
并且,玩儿单片机的乐趣就 ...
说的是,奈何菜鸟功力不足,能想到的问题都查了个遍,什么上下拉电阻、改延时、加滤波、、,(手边就一个28元的玩具级的逻辑分析仪{:yun:})还是抓不住这个随机的错误,为止卡了快1个月了。。
才想到要拆分总线,拆了之后可以是可以,但总觉得代码不够意思,一组IIc一套代码,啰嗦极了。。 DebugLab 发表于 2025-5-18 17:46
从机较多要减小上拉电阻,如4.7K改2.2K,时钟频率不要超过400K
是的,上拉改过1K8的,,总线串电阻、并100P电容都试过,速率一度改为250K左右,一样会随机出现{:ciya:} DebugLab 发表于 2025-5-18 18:00
实验箱例程“AI8051U-DEMO-CODE-V1.2”的“84-USB录放音声卡-TLV320AIC23B-内部36.864M-外接32768Hz晶振 ...
谢谢!我的代码分拆后,各驱各的没有题。 这个需求扔给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) {
// 主循环
}
}
zhuls 发表于 2025-5-18 19:11
说的是,奈何菜鸟功力不足,能想到的问题都查了个遍,什么上下拉电阻、改延时、加滤波、、,(手边就一个 ...
电路图和代码发上来,让大家一起帮忙找茬 一个思路是把用到的引脚传入软件IIC的函数里面,,但是由于51单片机的GPIO的寄存器不能直接通过指针访问,,所以你还得写几个驱动GPIO的函数,而且用这个函数驱动的话,非常影响性能,,如果追求通讯速率的话,可以用宏定义替换这些GPIO驱动函数。但是这样的话,如果需要修改引脚的话只能重新烧程序。。不过只对一块主板的话也不是不行。。 本身可以挂一起,减小上拉电阻 zhuls 发表于 2025-5-18 19:14
是的,上拉改过1K8的,,总线串电阻、并100P电容都试过,速率一度改为250K左右,一样会随机出现 ...
要不要换个思路?不用管随机出现错误的原因,而是想办法识别对错,然后建立重发机制。
页:
1
[2]