硬件I2C改软件I2C,有没有佬帮孩子看看
上面这个文件的代码用stc32f芯片是可以用的
下面这个文件是自己改写软件i2c的,好像有点问题
有没有佬帮我看看,是哪里出问题了{:4_201:}
在嵌入式系统中,I2C通信协议因其简单性和高效性而被广泛应用。硬件I2C和软件I2C是两种常见的实现方式。硬件I2C依赖于芯片内部的I2C控制器,而软件I2C则通过GPIO引脚模拟I2C协议。本文将针对您提供的代码,分析硬件I2C改软件I2C过程中可能出现的问题,并提供解决方案。
1. 硬件I2C与软件I2C的区别
硬件I2C:
依赖于芯片内部的I2C控制器,具有较高的通信速率和稳定性。
配置简单,通常只需设置相关寄存器即可。
占用较少的CPU资源。
软件I2C:
通过GPIO引脚模拟I2C协议,灵活性高,适用于没有硬件I2C控制器的芯片。
需要手动控制时钟(SCL)和数据(SDA)线的电平变化。
占用较多的CPU资源,通信速率较低。
2. 代码分析
2.1 硬件I2C代码
您提供的硬件I2C代码在STC32F芯片上可以正常运行,说明硬件配置和通信逻辑是正确的。以下是硬件I2C代码的关键部分:
c
void I2CInit() {
// 初始化I2C控制器
I2CCR1 = 0x00;
I2CCR2 = 0x00;
I2CFREQR = 0x01;
I2COARL = 0x00;
I2COARH = 0x00;
I2CCCRL = 0x0A;
I2CCCRH = 0x00;
I2CTRISER = 0x03;
I2CCR1 |= 0x01;
}
void I2CWrite(uint8t addr, uint8t data) {
// 发送起始条件
I2CCR2 |= 0x01;
while (!(I2CSR1 & 0x01));
// 发送设备地址
I2CDR = addr;
while (!(I2CSR1 & 0x02));
// 发送数据
I2CDR = data;
while (!(I2CSR1 & 0x04));
// 发送停止条件
I2CCR2 |= 0x02;
}
2.2 软件I2C代码
您改写的软件I2C代码可能存在以下问题:
c
void I2CInit() {
// 初始化GPIO引脚为输出模式
GPIOInitTypeDef GPIOInitStruct;
GPIOInitStruct.Pin = GPIOPIN6 | GPIOPIN7;
GPIOInitStruct.Mode = GPIOMODEOUTPUTPP;
GPIOInitStruct.Pull = GPIONOPULL;
GPIOInitStruct.Speed = GPIOSPEEDFREQLOW;
HALGPIOInit(GPIOB, &GPIOInitStruct);
}
void I2CStart() {
// 发送起始条件
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINSET);
HALGPIOWritePin(GPIOB, GPIOPIN7, GPIOPINSET);
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINRESET);
HALGPIOWritePin(GPIOB, GPIOPIN7, GPIOPINRESET);
}
void I2CWrite(uint8t addr, uint8t data) {
// 发送设备地址
for (int i = 0; i < 8; i++) {
HALGPIOWritePin(GPIOB, GPIOPIN7, (addr & (0x80 >> i)) ? GPIOPINSET : GPIOPINRESET);
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINSET);
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINRESET);
}
// 发送数据
for (int i = 0; i < 8; i++) {
HALGPIOWritePin(GPIOB, GPIOPIN7, (data & (0x80 >> i)) ? GPIOPINSET : GPIOPINRESET);
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINSET);
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINRESET);
}
}
3. 问题分析
3.1 起始条件
在硬件I2C中,起始条件由I2C控制器自动生成。而在软件I2C中,需要手动控制SCL和SDA线的电平变化。您代码中的起始条件可能存在问题:
c
void I2CStart() {
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINSET);
HALGPIOWritePin(GPIOB, GPIOPIN7, GPIOPINSET);
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINRESET);
HALGPIOWritePin(GPIOB, GPIOPIN7, GPIOPINRESET);
}
正确的起始条件应该是:
1. SDA线从高电平变为低电平。
2. SCL线保持高电平。
因此,起始条件应修改为:
c
void I2CStart() {
HALGPIOWritePin(GPIOB, GPIOPIN7, GPIOPINSET);
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINSET);
HALGPIOWritePin(GPIOB, GPIOPIN7, GPIOPINRESET);
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINRESET);
}
3.2 数据发送
在硬件I2C中,数据发送由I2C控制器自动完成。而在软件I2C中,需要手动控制SCL和SDA线的电平变化。您代码中的数据发送部分可能存在问题:
c
for (int i = 0; i < 8; i++) {
HALGPIOWritePin(GPIOB, GPIOPIN7, (addr & (0x80 >> i)) ? GPIOPINSET : GPIOPINRESET);
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINSET);
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINRESET);
}
正确的数据发送流程应该是:
1. SCL线保持低电平。
2. SDA线根据数据位设置电平。
3. SCL线从低电平变为高电平,再变为低电平。
因此,数据发送应修改为:
c
for (int i = 0; i < 8; i++) {
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINRESET);
HALGPIOWritePin(GPIOB, GPIOPIN7, (addr & (0x80 >> i)) ? GPIOPINSET : GPIOPINRESET);
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINSET);
HALGPIOWritePin(GPIOB, GPIOPIN6, GPIOPINRESET);
}
4. 总结
在将硬件I2C改为软件I2C时,需要注意以下几点:
1. 起始条件和停止条件的正确实现。
2. 数据发送时SCL和SDA线的电平变化顺序。
3. 确保GPIO引脚的初始化和配置正确。
通过以上分析和修改,您的软件I2C代码应该能够正常运行。如果问题仍然存在,建议使用逻辑分析仪或示波器检查SCL和SDA线的波形,进一步排查问题。
希望本文对您有所帮助,祝您顺利解决问题!
[本文内容由国芯人工智能辅助生成,仅供参考] 软件I2C可以参考AI8051U实验箱例程74:
https://www.stcaimcu.com/data/download/DemoCode/AI8051U-DEMO-CODE-V1.2.zip
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;
}
不单STC官方的例程很多,网上的I2C例程也很多 看起来没有大问题,注意开始停止要适当多延时些,IIC总线协议规范,看一下从机应答是否正常 拿逻辑分析仪,正常和异常的波形一抓,一对比,就知道错在哪了 上逻辑 分析仪看看数据喽
页:
[1]