以下例程链接:从机例程
主机例程:主机例程
从机部分
void I2cGpioIsr(void)
{
uint32_t temp;
// 处理SCL的上下沿中断
if(__HAL_GPIO_EXTI_GET_IT(SW_SLAVE_SCL_PIN) != RESET)//检测scl触发的中断
{
__HAL_GPIO_EXTI_CLEAR_IT(SW_SLAVE_SCL_PIN);
// 更新通信起始时间
StartMs = HAL_GetTick();
// SCL的下降沿事件处理,此时需要更新要传输的数据
SCL_FLAG_IF = (SW_SLAVE_SCL_PRT->IDR & SW_SLAVE_SCL_PIN);
if(SCL_FLAG_IF == (uint32_t)GPIO_PIN_RESET)
{
switch(State)
{
case I2C_STA_START: // 起始信号的下降沿,初始化相关参数并转到接收比特数据状态
SclFallCnt = 0;
RxIdx = 0;
TxIdx = 0;
Flag = 0; // 默认地址不匹配
RxBuf[RxIdx] = 0;
Rw = I2C_WRITE; // 第1字节为设备地址,一定是写入
State = I2C_STA_DATA;
break;
case I2C_STA_DATA:
SclFallCnt++;
if(8 > SclFallCnt)
{
// 如果是主机读取数据,则在SCL低电平时更新比特数据
if(Rw == I2C_READ)
{
if(TxBuf[TxIdx] & (1 << (7 - SclFallCnt)))
{
SET_SDA_PIN();
}
else
{
CLR_SDA_PIN();
}
}
}
else if(8 == SclFallCnt)
{
if(Rw == I2C_WRITE)
{
// 从第一个地址字节中获取读写标志位,并判断地址是否匹配
if(RxIdx == 0)
{
if((RxBuf[0] & 0xFE) == SW_SLAVE_ADDR)
{
Flag = 1; // 地址匹配
Rw = RxBuf[0] & 0x01;
}
}
if( Flag)
{
// 如果是主机写入数据,且地址匹配,则接收完8比特数据后,需要发送ACK信号进行应答
SET_SDA_DIR(temp, GPIO_DIR_OUT);
CLR_SDA_PIN();
}
}
else
{
// 如果是主机读取数据,需要将SDA设置成输入以便判断应答标志位状态
SET_SDA_DIR(temp, GPIO_DIR_IN);
// 如果是主机读取数据,准备发送下一个字节的数据
TxIdx++;
}
// 接收或发送完8比特数据后,准备发送或接收应答信号
State = I2C_STA_ACK;
}
break;
case I2C_STA_ACK:
SclFallCnt = 0;
if( Rw == I2C_WRITE)
{
// 如果是主机写入数据,且ACK发送完毕,则SDA设置成输入,继续接收数据
SET_SDA_DIR(temp, GPIO_DIR_IN);
RxIdx++;
RxBuf[ RxIdx] = 0;
}
else
{
// 如果是主机读取数据,且ACK接收完毕,则SDA设置成输出,继续发送数据
SET_SDA_DIR(temp, GPIO_DIR_OUT);
if( TxBuf[ TxIdx] & 0x80)
{
SET_SDA_PIN();
}
else
{
CLR_SDA_PIN();
}
}
State = I2C_STA_DATA;
break;
case I2C_STA_NACK: // 如果收到了NACK,则后面将是STOP或者ReSTART信号,需要将SDA设置成输入
SclFallCnt = 0;
SET_SDA_DIR(temp, GPIO_DIR_IN);
break;
}
}
// SCL的上升沿事件处理,此时需要采集数据,而且在数据阶段,SCL高电平时数据必须保持不变
else
{
switch( State)
{
case I2C_STA_DATA: // 数据阶段,如果是主机写入数据,则采集比特数据
if((I2C_WRITE == Rw) && (8 > SclFallCnt))
{
SDA_FLAG_IF = SW_SLAVE_SDA_PRT->IDR & SW_SLAVE_SDA_PIN;
if(SDA_FLAG_IF == 0x80)
{
RxBuf[ RxIdx] |= (1 << (7 - SclFallCnt));
}
}
break;
case I2C_STA_ACK: // 应答阶段,如果是主机读取数据,则判断ACK/NACK信号,默认状态是ACK
SDA_FLAG_IF = (SW_SLAVE_SDA_PRT->IDR & SW_SLAVE_SDA_PIN);
if(( Rw == I2C_READ) && SDA_FLAG_IF)
{
State = I2C_STA_NACK;
}
break;
}
}
}
else if(__HAL_GPIO_EXTI_GET_IT(SW_SLAVE_SDA_PIN) != RESET)//检测是不是sda触发的中断
{
__HAL_GPIO_EXTI_CLEAR_IT(SW_SLAVE_SDA_PIN);
//SDA的下降沿事件
SDA_FLAG_IF = (SW_SLAVE_SDA_PRT->IDR & SW_SLAVE_SDA_PIN);
if( SDA_FLAG_IF == (uint32_t)GPIO_PIN_RESET)
{
// SCL为高电平时,SDA从高变低,说明是起始信号
SCL_FLAG_IF = SW_SLAVE_SCL_PRT->IDR & SW_SLAVE_SCL_PIN;
if(SCL_FLAG_IF)
{
State = I2C_STA_START;
}
}
else//SDA的上升沿事件
{
// SCL为高电平时,SDA从低变高,说明是停止信号,一次I2C通信结束,直接将状态设置成空闲
SCL_FLAG_IF = SW_SLAVE_SCL_PRT->IDR & SW_SLAVE_SCL_PIN;
if(SCL_FLAG_IF)
{
State = I2C_STA_IDLE;
}
}
}
}
主机部分
while(1)
{
key=KEY_Scan(0);
if(key==KEY1_PRES)//KEY1按下,写入24C02
{
// LCD_Fill(0,170,239,319,WHITE);//清除半屏
// LCD_ShowString(30,170,200,16,16,"Start Write 24C02....");
IIC_Start();
IIC_Send_Byte(0X6E); //发送器件地址0XA0,写数据
IIC_Wait_Ack();
IIC_Send_Byte(0X10); //发送低地址
IIC_Wait_Ack();
IIC_Send_Byte(0XAA); //发送字节
IIC_Wait_Ack();
IIC_Stop();//产生一个停止条件
delay_ms(10);
// AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE);
LCD_ShowString(30,170,200,16,16,"very OKOK!!");//提示传送完成
}
if(key==KEY0_PRES)//KEY0按下,读取字符串并显示
{
// LCD_ShowString(30,170,200,16,16,"Start Read 24C02.... ");
// AT24CXX_Read(0,datatemp,SIZE);
// LCD_ShowString(30,170,200,16,16,"The Data Readed Is: ");//提示传送完成
// LCD_ShowString(30,190,200,16,16,datatemp);//显示读到的字符串
u8 temp=0;
IIC_Start();
IIC_Send_Byte(0X6E); //发送器件地址0XA0,写数据
IIC_Wait_Ack();
IIC_Send_Byte(0X1); //发送低地址
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(0X6F); //进入接收模式
IIC_Wait_Ack();
temp=IIC_Read_Byte(0);
IIC_Stop();//产生一个停止条件
delay_ms(10);
IntToHexString(temp, hexString);
LCD_ShowString(30,170,200,16,16,"The Data Readed Is: ");//提示传送完成
LCD_ShowString(30,190,200,16,16,hexString);//显示读到的字符串
// IIC_SDA=1;
// IIC_SCL=0;
}
i++;
delay_ms(10);
if(i==20)
{
LED0=!LED0;//提示系统正在运行
i=0;
}
}
使用硬件iic从机和硬件iic主机连接,可以正常连接,但出现了三次烧板子的情况,两次烧主机,一次烧从机,未找到烧板子原因
硬件iic,F4参考该资源,烧录就可以使用