STM32 IIC读写AT24C02(一)

接口/总线/驱动

1117人已加入

描述

要用IIC读写AT24C02,首先要了解IIC是什么。

I²C(Inter-Integrated Circuit)字面上的意思是集成电路之间,它其实是I²C Bus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。I²C的正确读法为“I平方C”("I-squared-C"),而“I二C”("I-two-C")则是另一种错误但被广泛使用的读法。自2006年10月1日起,使用I²C协议已经不需要支付专利费,但制造商仍然需要付费以获取I²C从属设备地址。

I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。

为了避免总线信号的混乱,要求各设备连接到总线的输出端时必须是漏极开路(OD)输出或集电极开路(OC)输出。设备上的串行数据线SDA接口电路应该是双向的,输出电路用于向总线上发送数据,输入电路用于接收总线上的数据。

通过以上介绍,现在开始编写IIC的GPIO口初始化,SCL、SDA分别对应PB8、PB9引脚。IIC的速度最快400Khz,并且可以兼容0~100KHz的IIC总线系统,所以引脚输出速度只要配置为2M,这个速度还是远远超过IIC的速度,这里就要在引脚电平变换时加入稍微的延时让速度符合IIC协议的要求。

void IIC_Init()
{
  RCC- >AHB1ENR    =    1< < 1;           //开端口B时钟

  GPIOB- >MODER    &=~    (0x03< < 16);    
  GPIOB- >MODER    &=~    (0x03< < 18);    
  GPIOB- >MODER    |=    (0x01< < 16);    //通用输出模式
  GPIOB- >MODER    |=    (0x01< < 18);    //通用输出模式
  GPIOB- >OTYPER   &=~    (1< < 8);       //开漏输出
  GPIOB- >OTYPER   &=~    (1< < 9);       //开漏输出
  GPIOB- >OSPEEDR  &=~    (0x03< < 16);   //输出速度2Mhz
  GPIOB- >OSPEEDR  &=~    (0x03< < 18);   //输出速度2Mhz
  GPIOB- >PUPDR    &=~    (0x03< < 16);   //无上下拉
  GPIOB- >PUPDR    &=~    (0x03< < 18);   //无上下拉
  GPIOB- >ODR      |=    (0x01< < 8);     //初始输出为1
  GPIOB- >ODR      |=    (0x01< < 9);     //初始输出为1
}

初始化完GPIO,接着根据IIC协议编写代码。

IIC总线

IIC总线

IIC总线

从时序图可以看出起始和停止信号时SCL都要拉高,起始时,SDA由高拉低,停止时SDA由低拉高。收发数据时,SCL处于低电平期间允许改变数据,高电平期间数据有效。所以在每个操作结束后可以把SCL拉低,防止误操作。为了兼容AT24C02的写周期5ms,在停止时,需要再延时5ms。

收发多个数据时,要多一个应答位,应答时继续收发数据,非应答时不再收发。SDA高电平时为非应答,低电平时为应答信号。

void IIC_Start()
{
  IIC_SCL_H();
  IIC_SDA_H();
  IIC_Delayus(5);
  IIC_SDA_L();
  IIC_Delayus(5);
  IIC_SCL_L();        
  IIC_Delayus(5);
}


void IIC_Stop()
{
  IIC_SCL_H();
  IIC_SDA_L();
  IIC_Delayus(5);
  IIC_SDA_H();      
  IIC_Delayms(5);      //兼容AT24C02的写周期
}


void IIC_SendByte(u8 dat)
{
  u8 i = 0;

  for(i = 0;i< 8;i++)
  {
    IIC_SCL_L();
    IIC_Delayus(5);
    if(dat & 0x80)
      IIC_SDA_H();  
    else
      IIC_SDA_L();
    IIC_Delayus(5);
    dat < <= 1;
    IIC_SCL_H();
    IIC_Delayus(5);
  }
  IIC_SCL_L();        
  IIC_Delayus(5);  
}


u8 IIC_ReadByte()
{
  u8 i = 0,temp = 0;

  IIC_SCL_L();        //拉低scl,准备发数据
  IIC_SDA_H();        //主机输出高,切断输出通道,使引脚配置变为输入
  IIC_Delay_us(5);

  for(i = 0;i< 8;i++)
  {
    temp < <= 1;          //空出最后一位,准备接收
    IIC_SCL_L();
    IIC_Delayus(5);
    IIC_SCL_H();
    IIC_Delayus(5);
    if(GPIOB- >IDR & (1< < 9))
      temp |= 1;

    IIC_Delayus(5);
  }
  IIC_SCL_L();        
  IIC_Delayus(5);  

  return temp;
}


u8 IIC_CheckAck()
{
  u8 ack = 0;

  IIC_SCL_L();        //这两行可以忽略,因为发送完后,总是拉低SCL
  IIC_SDA_H();        //主机释放SDA总线,同时切断引脚输出回路
  IIC_Delayus(5);
  IIC_SCL_H();
  IIC_Delayus(5);
  if(GPIOB- >IDR & (1< < 9))
    ack = 1;
  else 
    ack = 0;
  IIC_Delayus(5);  
  IIC_SCL_L();        
  IIC_Delayus(5);  

  return ack;
}


void IIC_AcktoSlave()
{
  IIC_SCL_L();        //拉低电平,让数据改变
  IIC_Delayus(5);
  IIC_SDA_L();
  IIC_Delayus(5);

  IIC_SCL_H();        
  IIC_Delayus(5);  

  IIC_SCL_L();      
  IIC_Delayus(5);
}


void IIC_NoAcktoSlave()
{
  IIC_SCL_L();        
  IIC_Delayus(5);
  IIC_SDA_H();
  IIC_Delayus(5);

  IIC_SCL_H();        
  IIC_Delayus(5);  

  IIC_SCL_L();      
  IIC_Delayus(5);
}

这样IIIC读写AT24C02的协议层就编写完成了。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分