如何实现IIC驱动封装以及AT24CXX存储器的封装

发布者:Enchanted2021最新更新时间:2024-02-22 来源: elecfans关键字:AT24CXX  存储器 手机看文章 扫描二维码
随时随地手机看文章

简述


IIC(Inter-Integrated Circuit)其实是IICBus简称,它是一种串行通信总线,使用多主从架构,在STM32开发中经常见到。



关于IIC可以参考之前发的一篇文章:《通信协议 IIC 与 SPI 最全对比》来了解。


使用面向对象的编程思想封装IIC驱动,将IIC的属性和操作封装成一个库,在需要创建一个IIC设备时只需要实例化一个IIC对象即可,本文是基于STM32和HAL库做进一步封装的。


底层驱动方法不重要,封装的思想很重要。在完成对IIC驱动的封装之后借助继承特性实现AT24C64存储器的驱动开发,仍使用面向对象的思想封装AT24C64驱动。


IIC驱动面向对象封装

iic.h头文件主要是类模板的定义,具体如下:


//定义IIC类

typedef struct IIC_Type

{

//属性

   GPIO_TypeDef  *GPIOx_SCL;  //GPIO_SCL所属的GPIO组(如:GPIOA)

   GPIO_TypeDef  *GPIOx_SDA;  //GPIO_SDA所属的GPIO组(如:GPIOA)

uint32_t GPIO_SCL;     //GPIO_SCL的IO引脚(如:GPIO_PIN_0)

uint32_t GPIO_SDA;     //GPIO_SDA的IO引脚(如:GPIO_PIN_0)

//操作

void (*IIC_Init)(const struct IIC_Type*);        //IIC_Init

void (*IIC_Start)(const struct IIC_Type*);       //IIC_Start

void (*IIC_Stop)(const struct IIC_Type*);        //IIC_Stop

uint8_t (*IIC_Wait_Ack)(const struct IIC_Type*);    //IIC_Wait_ack,返回wait失败或是成功

void (*IIC_Ack)(const struct IIC_Type*);       //IIC_Ack,IIC发送ACK信号

void (*IIC_NAck)(const struct IIC_Type*);       //IIC_NAck,IIC发送NACK信号

void (*IIC_Send_Byte)(const struct IIC_Type*,uint8_t);       //IIC_Send_Byte,入口参数为要发送的字节

uint8_t (*IIC_Read_Byte)(const struct IIC_Type*,uint8_t);     //IIC_Send_Byte,入口参数为是否要发送ACK信号

void (*delay_us)(uint32_t);              //us延时

}IIC_TypeDef;

  iic.c源文件主要是类模板具体操作函数的实现,具体如下:

//设置SDA为输入模式

static void SDA_IN(const struct IIC_Type* IIC_Type_t)

{

  uint8_t io_num = 0;  //定义io Num号

switch(IIC_Type_t->GPIO_SDA)

  {

case GPIO_PIN_0:

    io_num = 0;

break;

case GPIO_PIN_1:

    io_num = 1;

break; 

case GPIO_PIN_2:

    io_num = 2;

break; 

case GPIO_PIN_3:

    io_num = 3;

break;

case GPIO_PIN_4:

    io_num = 4;

break; 

case GPIO_PIN_5:

    io_num = 5;

break; 

case GPIO_PIN_6:

    io_num = 6;

break; 

case GPIO_PIN_7:

    io_num = 7;

break;

case GPIO_PIN_8:

    io_num = 8;

break; 

case GPIO_PIN_9:

    io_num = 9;

break;

case GPIO_PIN_10:

    io_num = 10;

break;

case GPIO_PIN_11:

    io_num = 11;

break; 

case GPIO_PIN_12:

    io_num = 12;

break;

case GPIO_PIN_13:

    io_num = 13;

break;

case GPIO_PIN_14:

    io_num = 14;

break; 

case GPIO_PIN_15:

    io_num = 15;

break;

  }

  IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零

  IIC_Type_t->GPIOx_SDA->MODER|=0<<(io_num*2);   //将GPIOx_SDA->GPIO_SDA设置为输入模式

}


//设置SDA为输出模式

static void SDA_OUT(const struct IIC_Type* IIC_Type_t)

{

  uint8_t io_num = 0;  //定义io Num号

switch(IIC_Type_t->GPIO_SDA)

  {

case GPIO_PIN_0:

    io_num = 0;

break;

case GPIO_PIN_1:

    io_num = 1;

break; 

case GPIO_PIN_2:

    io_num = 2;

break; 

case GPIO_PIN_3:

    io_num = 3;

break;

case GPIO_PIN_4:

    io_num = 4;

break; 

case GPIO_PIN_5:

    io_num = 5;

break; 

case GPIO_PIN_6:

    io_num = 6;

break; 

case GPIO_PIN_7:

    io_num = 7;

break;

case GPIO_PIN_8:

    io_num = 8;

break; 

case GPIO_PIN_9:

    io_num = 9;

break;

case GPIO_PIN_10:

    io_num = 10;

break;

case GPIO_PIN_11:

    io_num = 11;

break; 

case GPIO_PIN_12:

    io_num = 12;

break;

case GPIO_PIN_13:

    io_num = 13;

break;

case GPIO_PIN_14:

    io_num = 14;

break; 

case GPIO_PIN_15:

    io_num = 15;

break;

  }

  IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零

  IIC_Type_t->GPIOx_SDA->MODER|=1<<(io_num*2);   //将GPIOx_SDA->GPIO_SDA设置为输出模式

}

//设置SCL电平

static void IIC_SCL(const struct IIC_Type* IIC_Type_t,int n)

{

if(n == 1)

  {

    HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_SET);     //设置SCL为高电平

  }

else{

    HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_RESET);     //设置SCL为低电平

  }

}

//设置SDA电平

static void IIC_SDA(const struct IIC_Type* IIC_Type_t,int n)

{

if(n == 1)

  {

    HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_SET);     //设置SDA为高电平

  }

else{

    HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_RESET);     //设置SDA为低电平

  }

}

//读取SDA电平

static uint8_t READ_SDA(const struct IIC_Type* IIC_Type_t)

{

return HAL_GPIO_ReadPin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA);  //读取SDA电平

}

//IIC初始化

static void IIC_Init_t(const struct IIC_Type* IIC_Type_t)

{

      GPIO_InitTypeDef GPIO_Initure;


//根据GPIO组初始化GPIO时钟

if(IIC_Type_t->GPIOx_SCL == GPIOA || IIC_Type_t->GPIOx_SDA == GPIOA)

   {

     __HAL_RCC_GPIOA_CLK_ENABLE();   //使能GPIOA时钟

   }

if(IIC_Type_t->GPIOx_SCL == GPIOB || IIC_Type_t->GPIOx_SDA == GPIOB)

   {

     __HAL_RCC_GPIOB_CLK_ENABLE();   //使能GPIOB时钟

   }

if(IIC_Type_t->GPIOx_SCL == GPIOC || IIC_Type_t->GPIOx_SDA == GPIOC)

   {

     __HAL_RCC_GPIOC_CLK_ENABLE();   //使能GPIOC时钟

   }

if(IIC_Type_t->GPIOx_SCL == GPIOD || IIC_Type_t->GPIOx_SDA == GPIOD)

   {

     __HAL_RCC_GPIOD_CLK_ENABLE();   //使能GPIOD时钟

   }

if(IIC_Type_t->GPIOx_SCL == GPIOE || IIC_Type_t->GPIOx_SDA == GPIOE)

   {

     __HAL_RCC_GPIOE_CLK_ENABLE();   //使能GPIOE时钟

   } 

if(IIC_Type_t->GPIOx_SCL == GPIOH || IIC_Type_t->GPIOx_SDA == GPIOH)

   {

     __HAL_RCC_GPIOH_CLK_ENABLE();   //使能GPIOH时钟

   }     


//GPIO_SCL初始化设置

     GPIO_Initure.Pin=IIC_Type_t->GPIO_SCL;

     GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出

     GPIO_Initure.Pull=GPIO_PULLUP;          //上拉

     GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;    //快速

     HAL_GPIO_Init(IIC_Type_t->GPIOx_SCL,&GPIO_Initure);

//GPIO_SDA初始化设置

     GPIO_Initure.Pin=IIC_Type_t->GPIO_SDA;

     GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出

     GPIO_Initure.Pull=GPIO_PULLUP;          //上拉

     GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;    //快速

     HAL_GPIO_Init(IIC_Type_t->GPIOx_SDA,&GPIO_Initure);


//SCL与SDA的初始化均为高电平

      IIC_SCL(IIC_Type_t,1);

       IIC_SDA(IIC_Type_t,1);

}

//IIC Start

static void IIC_Start_t(const struct IIC_Type* IIC_Type_t)

{

  SDA_OUT(IIC_Type_t);      //sda线输出

  IIC_SDA(IIC_Type_t,1);      

  IIC_SCL(IIC_Type_t,1);

  IIC_Type_t->delay_us(4);

   IIC_SDA(IIC_Type_t,0);  //START:when CLK is high,DATA change form high to low 

  IIC_Type_t->delay_us(4);

  IIC_SCL(IIC_Type_t,0);  //钳住I2C总线,准备发送或接收数据 

}

//IIC Stop

static void IIC_Stop_t(const struct IIC_Type* IIC_Type_t)

{

  SDA_OUT(IIC_Type_t); //sda线输出

  IIC_SCL(IIC_Type_t,0);

  IIC_SDA(IIC_Type_t,0); //STOP:when CLK is high DATA change form low to high

   IIC_Type_t->delay_us(4);

  IIC_SCL(IIC_Type_t,1); 

  IIC_SDA(IIC_Type_t,1); //发送I2C总线结束信号

  IIC_Type_t->delay_us(4); 

}

//IIC_Wait_ack 返回HAL_OK表示wait成功,返回HAL_ERROR表示wait失败

static uint8_t IIC_Wait_Ack_t(const struct IIC_Type* IIC_Type_t)   //IIC_Wait_ack,返回wait失败或是成功

{

  uint8_t ucErrTime = 0;

  SDA_IN(IIC_Type_t);      //SDA设置为输入  

  IIC_SDA(IIC_Type_t,1);IIC_Type_t->delay_us(1);   

  IIC_SCL(IIC_Type_t,1);IIC_Type_t->delay_us(1);

while(READ_SDA(IIC_Type_t))

  {

    ucErrTime++;

if(ucErrTime>250)

    {

      IIC_Type_t->IIC_Stop(IIC_Type_t);

return HAL_ERROR;

    }

  }

  IIC_SCL(IIC_Type_t,0);//时钟输出0     

return HAL_OK;  

}

//产生ACK应答

static void IIC_Ack_t(const struct IIC_Type* IIC_Type_t)      

{

  IIC_SCL(IIC_Type_t,0);

  SDA_OUT(IIC_Type_t);

  IIC_SDA(IIC_Type_t,0);

  IIC_Type_t->delay_us(2);  

  IIC_SCL(IIC_Type_t,1);

  IIC_Type_t->delay_us(2);  

  IIC_SCL(IIC_Type_t,0);

}

//产生NACK应答

static void IIC_NAck_t(const struct IIC_Type* IIC_Type_t)      

{

  IIC_SCL(IIC_Type_t,0);

  SDA_OUT(IIC_Type_t);

  IIC_SDA(IIC_Type_t,1);

  IIC_Type_t->delay_us(2);  

  IIC_SCL(IIC_Type_t,1);

  IIC_Type_t->delay_us(2);  

  IIC_SCL(IIC_Type_t,0);

}

//IIC_Send_Byte,入口参数为要发送的字节

static void IIC_Send_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t txd)     

{

     uint8_t t = 0;   

     SDA_OUT(IIC_Type_t);      

     IIC_SCL(IIC_Type_t,0);//拉低时钟开始数据传输

for(t=0;t<8;t++)

     {              

          IIC_SDA(IIC_Type_t,(txd&0x80)>>7);

          txd <<= 1;    

       IIC_Type_t->delay_us(2);     //对TEA5767这三个延时都是必须的

       IIC_SCL(IIC_Type_t,1);

       IIC_Type_t->delay_us(2);  

       IIC_SCL(IIC_Type_t,0); 

       IIC_Type_t->delay_us(2);  

     }  

}

//IIC_Send_Byte,入口参数为是否要发送ACK信号

static uint8_t IIC_Read_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t ack)     

[1] [2] [3]
关键字:AT24CXX  存储器 引用地址:如何实现IIC驱动封装以及AT24CXX存储器的封装

上一篇:定时器中断是什么意思,定时器中断的工作原理
下一篇:BC20-NBIOT模块通过MQTT协议连接华为云服务器调试

小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved