
使用面向對象的編程思想封裝IIC驅動,將IIC的屬性和操作封裝成一個庫,在需要創建一個IIC設備時只需要實例化一個IIC對象即可,本文是基于STM32和HAL庫做進一步封裝的。
底層驅動方法不重要,封裝的思想很重要。在完成對IIC驅動的封裝之后借助繼承特性實現AT24C64存儲器的驅動開發,仍使用面向對象的思想封裝AT24C64驅動。
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)?????
{
???uint8_t?i,receive?=?0;
???SDA_IN(IIC_Type_t);//SDA設置為輸入
???for(i=0;i<8;i++?)
???{
??????IIC_SCL(IIC_Type_t,0);?
??????IIC_Type_t->delay_us(2);
??????IIC_SCL(IIC_Type_t,1);
??????receive<<=1;
??????if(READ_SDA(IIC_Type_t))receive++;???
??????IIC_Type_t->delay_us(1);
???}??????
??if?(!ack)
?????????IIC_Type_t->IIC_NAck(IIC_Type_t);//發送nACK
??else
?????????IIC_Type_t->IIC_Ack(IIC_Type_t);?//發送ACK???
??return?receive;
}
//實例化一個IIC1外設,相當于一個結構體變量,可以直接在其他文件中使用
IIC_TypeDef IIC1?=?{
??.GPIOx_SCL?=?GPIOA,???//GPIO組為GPIOA
??.GPIOx_SDA?=?GPIOA,???//GPIO組為GPIOA
??.GPIO_SCL?=?GPIO_PIN_5,???//GPIO為PIN5
??.GPIO_SDA?=?GPIO_PIN_6,??//GPIO為PIN6
??.IIC_Init?=?IIC_Init_t,
??.IIC_Start?=?IIC_Start_t,
??.IIC_Stop?=?IIC_Stop_t,
??.IIC_Wait_Ack?=?IIC_Wait_Ack_t,
??.IIC_Ack?=?IIC_Ack_t,
??.IIC_NAck?=?IIC_NAck_t,
??.IIC_Send_Byte?=?IIC_Send_Byte_t,
??.IIC_Read_Byte?=?IIC_Read_Byte_t,
??.delay_us?=?delay_us?????//需自己外部實現delay_us函數
};at24cxx.h頭文件主要是類模板的定義,具體如下:
//?以下是共定義個具體容量存儲器的容量
#define?AT24C01??127
#define?AT24C02??255
#define?AT24C04??511
#define?AT24C08??1023
#define?AT24C16??2047
#define?AT24C32??4095
#define?AT24C64???8191?????????//8KBytes
#define?AT24C128 16383
#define?AT24C256 32767??
//定義AT24CXX類
typedef?struct?AT24CXX_Type
{
??//屬性
??u32 EEP_TYPE;???????????//存儲器類型(存儲器容量)
??//操作
??IIC_TypeDef IIC;???????//IIC驅動
??uint8_t?(*AT24CXX_ReadOneByte)(const?struct AT24CXX_Type*,uint16_t);??//指定地址讀取一個字節
??void?(*AT24CXX_WriteOneByte)(const?struct AT24CXX_Type*,uint16_t,uint8_t);?//指定地址寫入一個字節
??void?(*AT24CXX_WriteLenByte)(uint16_t,uint32_t,uint8_t);?//指定地址開始寫入指定長度的數據
??uint32_t?(*AT24CXX_ReadLenByte)(uint16_t,uint8_t);???//指定地址開始讀取指定長度數據
??void?(*AT24CXX_Write)(uint16_t,uint8_t?*,uint16_t);??//指定地址開始寫入指定長度的數據
??void?(*AT24CXX_Read)(uint16_t,uint8_t?*,uint16_t);???//指定地址開始寫入指定長度的數據
??void?(*AT24CXX_Init)(const?struct AT24CXX_Type*);?//初始化IIC
??uint8_t?(*AT24CXX_Check)(const?struct AT24CXX_Type*);???//檢查器件
}AT24CXX_TypeDef;
extern?AT24CXX_TypeDef AT24C_64;?????//外部聲明實例化AT24CXX對象at24cxx.c源文件主要是類模板具體操作函數的實現,具體如下:
//在AT24CXX指定地址讀出一個數據
//ReadAddr:開始讀數的地址??
//返回值??:讀到的數據
static?uint8_t?AT24CXX_ReadOneByte_t(const?struct AT24CXX_Type*?AT24CXX_Type_t,uint16_t?ReadAddr)
{??????
??uint8_t?temp=0;??????????????????????????
??AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);??
??//根據AT的型號發送不同的地址
??if(AT24CXX_Type_t->EEP_TYPE?>?AT24C16)
??{
????AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0);????//發送寫命令
????AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
????AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr>>8);//發送高地址?????
??}else?AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((ReadAddr/256)<<1));???//發送器件地址0XA0,寫數據
??AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);?
??AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr%256);???//發送低地址
??AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);?????
??AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);????????
??AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA1);???????????//進入接收模式??????
??AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);??
??temp=AT24CXX_Type_t->IIC.IIC_Read_Byte(&AT24CXX_Type_t->IIC,0);?????
??AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//產生一個停止條件?????
??return?temp;
}
//在AT24CXX指定地址寫入一個數據
//WriteAddr??:寫入數據的目的地址????
//DataToWrite:要寫入的數據
static?void?AT24CXX_WriteOneByte_t(const?struct AT24CXX_Type*?AT24CXX_Type_t,uint16_t?WriteAddr,uint8_t?DataToWrite)
{????????????????????????????????
???AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);???
??if(AT24CXX_Type_t->EEP_TYPE?>?AT24C16)
??{
????AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0);????//發送寫命令
????AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
????AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr>>8);//發送高地址?????
??}else?AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((WriteAddr/256)<<1));???//發送器件地址0XA0,寫數據?????
??AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);?
???AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr%256);???//發送低地址
??AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);???????????????
??AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,DataToWrite);?????//發送字節??????????
??AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);????????????
???AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//產生一個停止條件?
?AT24CXX_Type_t->IIC.delay_us(10000);??
}
//在AT24CXX里面的指定地址開始寫入長度為Len的數據
//該函數用于寫入16bit或者32bit的數據.
//WriteAddr??:開始寫入的地址??
//DataToWrite:數據數組首地址
//Len????????:要寫入數據的長度2,4
static?void?AT24CXX_WriteLenByte_t(uint16_t?WriteAddr,uint32_t?DataToWrite,uint8_t?Len)
{???
??uint8_t?t;
??for(t=0;t??{
????AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
??}????????????????
}
//在AT24CXX里面的指定地址開始讀出長度為Len的數據
//該函數用于讀出16bit或者32bit的數據.
//ReadAddr???:開始讀出的地址?
//返回值?????:數據
//Len????????:要讀出數據的長度2,4
static?uint32_t?AT24CXX_ReadLenByte_t(uint16_t?ReadAddr,uint8_t?Len)
{???
??uint8_t?t;
??uint32_t?temp=0;
??for(t=0;t??{
????temp<<=8;
?????temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);??????????
??}
??return?temp;????????????????
}
//在AT24CXX里面的指定地址開始寫入指定個數的數據
//WriteAddr?:開始寫入的地址?對24c64為0~8191
//pBuffer???:數據數組首地址
//NumToWrite:要寫入數據的個數
static?void?AT24CXX_Write_t(uint16_t?WriteAddr,uint8_t?*pBuffer,uint16_t?NumToWrite)
{
??while(NumToWrite--)
??{
???AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
????WriteAddr++;
????pBuffer++;
??}
}
//在AT24CXX里面的指定地址開始讀出指定個數的數據
//ReadAddr?:開始讀出的地址?對24c64為0~8191
//pBuffer??:數據數組首地址
//NumToRead:要讀出數據的個數
static?void?AT24CXX_Read_t(uint16_t?ReadAddr,uint8_t?*pBuffer,uint16_t?NumToRead)
{
??while(NumToRead)
??{
????*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);?
????NumToRead--;
??}
}?
//初始化IIC接口
static?void?AT24CXX_Init_t(const?struct AT24CXX_Type*?AT24CXX_Type_t)
{
??AT24CXX_Type_t->IIC.IIC_Init(&AT24CXX_Type_t->IIC);//IIC初始化
}
//檢查器件,返回0表示檢測成功,返回1表示檢測失敗
static?uint8_t?AT24CXX_Check_t(const?struct AT24CXX_Type*?AT24CXX_Type_t)???
{
?uint8_t?temp;
??temp?=?AT24CXX_Type_t->AT24CXX_ReadOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE);//避免每次開機都寫AT24CXX??????
??if(temp?==?0X33)return?0;?????
??else//排除第一次初始化的情況
??{
??????AT24CXX_Type_t->AT24CXX_WriteOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE,0X33);
???????temp?=?AT24CXX_Type_t->AT24CXX_ReadOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE);
??????if(temp==0X33)return?0;
??}
??return?1;??
}
//實例化AT24CXX對象
AT24CXX_TypeDef AT24C_64={
?.EEP_TYPE?=?AT24C64,???????????//存儲器類型(存儲器容量)
?//操作
?.IIC={
??.GPIOx_SCL?=?GPIOA,
??.GPIOx_SDA?=?GPIOA,
??.GPIO_SCL?=?GPIO_PIN_5,
??.GPIO_SDA?=?GPIO_PIN_6,
??.IIC_Init?=?IIC_Init_t,
??.IIC_Start?=?IIC_Start_t,
??.IIC_Stop?=?IIC_Stop_t,
??.IIC_Wait_Ack?=?IIC_Wait_Ack_t,
??.IIC_Ack?=?IIC_Ack_t,
??.IIC_NAck?=?IIC_NAck_t,
??.IIC_Send_Byte?=?IIC_Send_Byte_t,
??.IIC_Read_Byte?=?IIC_Read_Byte_t,
??.delay_us?=?delay_us
?},???????????????????//IIC驅動
?.AT24CXX_ReadOneByte?=?AT24CXX_ReadOneByte_t,??//指定地址讀取一個字節
?.AT24CXX_WriteOneByte?=?AT24CXX_WriteOneByte_t,//指定地址寫入一個字節
?.AT24CXX_WriteLenByte?=?AT24CXX_WriteLenByte_t,?//指定地址開始寫入指定長度的數據
?.AT24CXX_ReadLenByte?=?AT24CXX_ReadLenByte_t,???//指定地址開始讀取指定長度數據
?.AT24CXX_Write?=?AT24CXX_Write_t,??//指定地址開始寫入指定長度的數據
?.AT24CXX_Read?=?AT24CXX_Read_t,???//指定地址開始讀取指定長度的數據
?.AT24CXX_Init?=?AT24CXX_Init_t,?//初始化IIC
?.AT24CXX_Check?=?AT24CXX_Check_t???//檢查器件
}; 之所以將IIC的類對象作為AT24CXX類的成員是因為AT24CXX的實現需要調用IIC的成員方法,IIC相當于AT24CXX更下層的驅動,因此采用包含關系更合適。
因此我們在使用AT24CXX的時候只需要實例化AT24CXX類對象就行了,因為IIC包含在AT24CXX類中間,因此不需要實例化IIC類對象,對外提供了較好的封裝接口。下面我們看具體的調用方法。
在main函數中直接使用AT24C_64來完成所有操作,下面結合代碼來看:
#include?"at24cxx.h"????//為了確定AT24C_64的成員方法和引用操作對象AT24C_64
int?main(void)
{
??/************省略其他初始化工作****************/
??//第一步:調用對象初始化方法來初始化AT24C64
??AT24C_64.AT24CXX_Init(&AT24C_64);
??//第二步:調用對象檢測方法來檢測AT24C64 ??????????
??if(AT24C_64.AT24CXX_Check(&AT24C_64)?==?0)
??{
????printf("AT24C64檢測成功\r\n");
??}
??else{
????printf("AT24C64檢測失敗\r\n");
??}
??return?0;
}本文詳細介紹了面向對象方法實現IIC驅動封裝以及AT24CXX存儲器的封裝,最終對外僅提供一個操作對象接口,大大提高了代碼的復用性以及封裝性。
文章來源于網絡,版權歸原作者所有,如有侵權,請聯系刪除。


覺得文章不錯,點擊“分享”、“贊”、“在看” 唄!