ARM · 2024年 10月 27日·148 次浏览 0

(九)Proteus仿真STM32单片机硬件I2C和模拟I2C读写PCF8563时钟

1,启用I2C1,如下图,PB8 PB9自动变成I2C模式

2,实现I2C读写驱动函数

//i2c 写
int VI2C_STD_Writebytes(uchar device,uchar reg,uchar *buff,uchar len)
{
	return HAL_I2C_Mem_Write(&hi2c1, device, reg, 1,buff, len, 100);
}
//i2c 读
int VI2C_STD_Readbytes(uchar device,uchar reg,uchar *buff,uchar len)
{
	
	return HAL_I2C_Mem_Read(&hi2c1, device, reg, 1,buff, len, 100);
}

3,protues不支持stm32硬件I2C,下面是模拟I2C驱动,注意将PB8配置为推挽输出,PB9配置为开漏输出并上拉使能实现双向读写

#define VI2C_SCL_0() HAL_GPIO_WritePin(I2C_SCL_GPIO_Port, I2C_SCL_Pin, GPIO_PIN_RESET)
#define VI2C_SCL_1() HAL_GPIO_WritePin(I2C_SCL_GPIO_Port, I2C_SCL_Pin, GPIO_PIN_SET)
#define VI2C_SDA_0() HAL_GPIO_WritePin(I2C_SDA_GPIO_Port, I2C_SDA_Pin, GPIO_PIN_RESET)
#define VI2C_SDA_1() HAL_GPIO_WritePin(I2C_SDA_GPIO_Port, I2C_SDA_Pin, GPIO_PIN_SET)
void i2c_delay()
{
	__IO unsigned int cnts=10;
	while(cnts--);
}

void VI2C_Start()
{
    VI2C_SDA_1();
    i2c_delay();
    VI2C_SCL_1();
    i2c_delay();
    VI2C_SDA_0(); 
    i2c_delay();
		
}
void VI2C_Stop(void)
{
    VI2C_SDA_0();
    i2c_delay();
    VI2C_SCL_1();
    i2c_delay();
    VI2C_SDA_1();
    i2c_delay();
}
uchar VI2C_ReadACK(void)
{
   uchar ret=1;
    VI2C_SCL_1();
    i2c_delay();
    if(VI2C_READ_SDA()==0)
      ret=0;
	VI2C_SCL_0();
	i2c_delay();
    return ret;
}
uchar  VI2C_WriteData(uchar data)
{	
  uchar i;
  for(i=0;i<8;i++)
  {
	VI2C_SCL_0();
	i2c_delay();
	if(data&0x80)
	    VI2C_SDA_1();
    else
      VI2C_SDA_0();
	i2c_delay();
	VI2C_SCL_1();
	i2c_delay();
    data=data<<1;
  }
	VI2C_SCL_0();
	i2c_delay();
	VI2C_SDA_1();
  return VI2C_ReadACK();
}
uchar VI2C_WriteAdd(uchar add,uchar w)
{
  uchar data;
  if(w)
  {
    data=add;
  }
  else
  {
    data=(add|0x01);
  }
  return VI2C_WriteData(data);
}

uchar VI2C_ReadData(uchar *data,uchar ack)
{
    uchar ret , i;
    VI2C_SCL_0();
    i2c_delay();
    for(i=0;i<8;i++)
    {
        ret=ret<<1;
	VI2C_SCL_1();
        i2c_delay();
        if(VI2C_READ_SDA())
          ret=ret|1;
        else
          ret=ret&0xfe;
	VI2C_SCL_0();
	i2c_delay();
    }
    if(ack)
        VI2C_SDA_0();
    else
        VI2C_SDA_1();
    i2c_delay();
    VI2C_SCL_1();
    i2c_delay();
    VI2C_SCL_0();
    i2c_delay();
    VI2C_SDA_1();
    *data=ret; 
    return 0;
}

uchar VI2C_STD_Writebytes(uchar add,uchar cmd,uchar *data, uchar len)
{
    unsigned char i,err=0;
    VI2C_Start();
    if(VI2C_WriteAdd(add,1))
    {
      err|=2;//no ack
      goto end;
    }
    if(VI2C_WriteData(cmd))
    {
      err|=4;//no ack
      goto end;
    }
    for(i=0;i<len;i++)
    {
        if(VI2C_WriteData(data[i]))
        {
          err|=4;//no ack
          goto end;
        }
    }
end:
    VI2C_Stop();
    return err;
}

uchar VI2C_STD_Readbytes(uchar add,uchar cmd,uchar *data, uchar len)
{
    unsigned char i,err=0;
    VI2C_Start();
    if(VI2C_WriteAdd(add,1))
    {
      err|=2;//no ack
      goto end;
    }
    if(VI2C_WriteData(cmd))
    {
      err|=4;//no ack
      goto end;
    }
    VI2C_Start();
    if(VI2C_WriteAdd(add,0))
    {
      err|=2;//no ack
      goto end;
    }
    for(i=0;i<len;i++)
    {
        if(VI2C_ReadData(data+i,1))
        {
          err|=4;//no ack
          goto end;
        }
    }
end:
    VI2C_Stop();
    return err;
}

4,PCF8563时钟读写驱动

typedef struct 
{
  uchar sec;
  uchar min;
  uchar hour;
  uchar day;
  uchar week;
  uchar month;
  uchar year;
}Struct_CLOCK;
#define TB_PCF8563_ADDR       0XA2 
Struct_CLOCK systemclock={0x10,0x30,0X13,0X01,0X02,0X10,0X24};//2024-10-1 13:30:10
void PCF8563_Init(void)
{
  uchar I2cwdtbuf[16];
  I2cwdtbuf[0] = 0x00;
  I2cwdtbuf[1] = 0x00; 
  I2cwdtbuf[13] = 0xFF;    //CLK out 1HZ
  I2cwdtbuf[14] = 0x00;   
  I2cwdtbuf[15] = 0x00;      
  
  VI2C_STD_Writebytes(TB_PCF8563_ADDR,0,I2cwdtbuf,2);  
  VI2C_STD_Writebytes(TB_PCF8563_ADDR,13,(I2cwdtbuf+13),1);    
  VI2C_STD_Writebytes(TB_PCF8563_ADDR,14,(I2cwdtbuf+14),2);   
}
void PCF8563_Read(void)
{
  if(VI2C_STD_Readbytes(TB_PCF8563_ADDR,0X02,(uchar *)&systemclock,7)==0)
  {
    systemclock.sec  &= 0X7F;
    systemclock.min  &= 0X7F;
    systemclock.hour  &= 0X3F;
    systemclock.day  &= 0X3F;
    systemclock.week  &= 0X07;
    systemclock.month &= 0X1F;
    //systemclock.year  &= 0XFF;
  }
}
void ZPCF8563_Write()
{
  if(VI2C_STD_Writebytes(TB_PCF8563_ADDR,0X02,(uchar *)&systemclock,7)==0)
  {
  }
}

git源码:https://gitee.com/armfun/stm32_proteus