zhuls 发表于 2025-5-18 14:56:56

求组,GPIO的分组(不知合不合适这样叫?)

有个项目,主控STC8H,要用到3个IIC设备,分别是24c08、RX8025t、SC7A20h。
其中:
24c08的SDA=P37,SCL=P36;
RX8025T的SDA=P15,SCL=P14;
SC7A20的SDA=P22,SCL=P21;
在不想复用SDA和SCL的情景下,如何通过结构体来切换不同设备的IIC接口,并配置不同的延时参数,从而共享标准IIC的代码?
目的要让代码简洁可靠,而不要为每一个I2C设备都准备一套代码?
如果后期还有类似的设备,比如BMP180,DTH11,==,也要方便扩展?

请大神们伸手拉菜鸟一把。{:baoquan:}

DebugLab 发表于 2025-5-18 15:12:41

使用硬件I2C

如多个I2C设备不想接一起,可以接到不同的IO,分时复用,I2C脚位切换寄存器如下:


I2C底层驱动程序可以复用:
void I2C_Start(void)
{
        I2C_Busy=1;
        I2CMSCR=0x81;
        while(I2C_Busy);
}

void I2C_SendData(unsigned char dat)
{
        I2CTXD=dat;
        I2C_Busy=1;
        I2CMSCR=0x82;
        while(I2C_Busy);
}

void I2C_RecvACK(void)
{
        I2C_Busy=1;
        I2CMSCR=0x83;
        while(I2C_Busy);
}

//unsigned char I2C_RecvData(void)
//{
//        I2C_Busy=1;
//        I2CMSCR=0x84;
//        while(I2C_Busy);
//        return I2CRXD;
//}

//void I2C_SendACK(void)
//{
//        I2CMSST=0x00;
//        I2C_Busy=1;
//        I2CMSCR=0x85;
//        while(I2C_Busy);
//}

//void I2C_SendNAK(void)
//{
//        I2CMSST=0x01;
//        I2C_Busy=1;
//        I2CMSCR=0x85;
//        while(I2C_Busy);
//}

void I2C_Stop(void)
{
        I2C_Busy=1;
        I2CMSCR=0x86;
        while(I2C_Busy);
}

zhuls 发表于 2025-5-18 16:43:26

DebugLab 发表于 2025-5-18 15:12
使用硬件I2C

如多个I2C设备不想接一起,可以接到不同的IO,分时复用,I2C脚位切换寄存器如下:


硬件切换是个方法,可惜因为IO被 限死,布局原因,调不到一块了。{:weixiao:}
最好是能能软件模拟IIC,IO可以任意调整。

神农鼎 发表于 2025-5-18 17:34:51

I2C 总线可以挂多个不同的从器件啊/从器件地址不同

zhuls 发表于 2025-5-18 17:43:35

神农鼎 发表于 2025-5-18 17:34
I2C 总线可以挂多个不同的从器件啊/从器件地址不同

理论上是这样的,也试过把所有的I2C设备挂在同一BUS上,但一些突发数据在传输过程中,总会出现无法预知的错误{:weiqu:}

DebugLab 发表于 2025-5-18 17:46:35

zhuls 发表于 2025-5-18 17:43
理论上是这样的,也试过把所有的I2C设备挂在同一BUS上,但一些突发数据在传输过程中,总会出现无法预知的 ...

从机较多要减小上拉电阻,如4.7K改2.2K,时钟频率不要超过400K

DebugLab 发表于 2025-5-18 18:00:17

zhuls 发表于 2025-5-18 16:43
硬件切换是个方法,可惜因为IO被 限死,布局原因,调不到一块了。
最好是能能软件模拟IIC,IO可以任意调 ...

实验箱例程“AI8051U-DEMO-CODE-V1.2”的“84-USB录放音声卡-TLV320AIC23B-内部36.864M-外接32768Hz晶振”中有软件模拟I2C:
sbit        P_AIC23_SCL = P5^1;                //2024-7-21
sbit        P_AIC23_SDA = P5^0;


/****************************/

void        AIC23_Delay(void)
{
        u16        dly;
        dly = 10;                //取1对应SCL H为0.5us,L为1.5us,读写仍正常.为了可靠,取8
        while(--dly)        ;
}


/****************************/
void AIC23_Start(void)               //start the I2C, SDA High-to-low when SCL is high
{
        P_AIC23_SDA = 1;        //SDA = 1;
        AIC23_Delay();
        P_AIC23_SCL = 1;        //SCL = 1;
        AIC23_Delay();
        AIC23_Delay();
        AIC23_Delay();
        AIC23_Delay();
        P_AIC23_SDA = 0;        //SDA = 0;
        AIC23_Delay();
        AIC23_Delay();
        AIC23_Delay();
        P_AIC23_SCL = 0;        //SCL = 0;
        AIC23_Delay();
}


void AIC23_Stop(void)                                        //STOP the I2C, SDA Low-to-high when SCL is high
{
        P_AIC23_SCL = 0;        //SCL = 0;
        AIC23_Delay();
        P_AIC23_SDA = 0;        //SDA = 0;
        AIC23_Delay();
        P_AIC23_SCL = 1;        //SCL = 1;
        AIC23_Delay();
        AIC23_Delay();
        AIC23_Delay();
        P_AIC23_SDA = 1;        //SDA = 1;
        AIC23_Delay();
}

u8 AIC23_Check_ACK(void)         //Check ACK, If status=0: right, if status=1:error
{
        u8        status;
        P_AIC23_SDA = 1;        //SDA = 1;
        AIC23_Delay();
        P_AIC23_SCL = 1;        //SCL = 1;
        AIC23_Delay();
        status = 0;
        if(P_AIC23_SDA)        status = 1;
        P_AIC23_SCL = 0;        //SCL = 0;
        AIC23_Delay();
        return        status;
}

/****************************/
void AIC23_WriteAbyte(u8 dat)                //write a byte to I2C
{
        u8 i;
        for(i=0; i<8; i++)
        {
                if(dat & 0x80)        P_AIC23_SDA = 1;        //SDA = 1;
                else                        P_AIC23_SDA = 0;        //SDA = 0;
                AIC23_Delay();
                P_AIC23_SCL = 1;        //SCL = 1;
                dat <<= 1;
                AIC23_Delay();
                P_AIC23_SCL = 0;        //SCL = 0;
                AIC23_Delay();
        }
}

/****************************/
u8        AIC23_RegWrite(u8 RegAddr, u8 dat)        //返回0: 正确, >0: 错误
{
        u8        status;

        status = 1;
        AIC23_Start();
        AIC23_WriteAbyte(AIC23_WR);                //device address + WR
        if(AIC23_Check_ACK() == 0)
        {
                AIC23_WriteAbyte(RegAddr);        //register address
                if(AIC23_Check_ACK() == 0)
                {
                        AIC23_WriteAbyte(dat);        //data
                        if(AIC23_Check_ACK() == 0)        //data
                                        status = 0;
                }
        }
        AIC23_Stop();
        return        status;
}

21cnsound 发表于 2025-5-18 18:05:53

zhuls 发表于 2025-5-18 17:43
理论上是这样的,也试过把所有的I2C设备挂在同一BUS上,但一些突发数据在传输过程中,总会出现无法预知的 ...

建议检查、排查“无法预知的错误”,遇到问题就躲避不是学习的一个端正态度。{:touxiao:}

并且,玩儿单片机的乐趣就在排障,代码一写就OK说实话就真没意思了。

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:}
页: [1] 2
查看完整版本: 求组,GPIO的分组(不知合不合适这样叫?)