IIC驅(qū)動?C語言使用面向?qū)ο髞韺?shí)現(xiàn)
來源:網(wǎng)路素材
一.簡述
使用面向?qū)ο蟮木幊趟枷敕庋bIIC驅(qū)動,將IIC的屬性和操作封裝成一個庫,在需要創(chuàng)建一個IIC設(shè)備時只需要實(shí)例化一個IIC對象即可,本文是基于STM32和HAL庫做進(jìn)一步封裝的。
底層驅(qū)動方法不重要,封裝的思想很重要。在完成對IIC驅(qū)動的封裝之后借助繼承特性實(shí)現(xiàn)AT24C64存儲器的驅(qū)動開發(fā),仍使用面向?qū)ο蟮乃枷敕庋bAT24C64驅(qū)動。
二.IIC驅(qū)動面向?qū)ο蠓庋b
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發(fā)送ACK信號
???void?(*IIC_NAck)(const?struct?IIC_Type*);???????//IIC_NAck,IIC發(fā)送NACK信號
???void?(*IIC_Send_Byte)(const?struct?IIC_Type*,uint8_t);???????//IIC_Send_Byte,入口參數(shù)為要發(fā)送的字節(jié)
???uint8_t?(*IIC_Read_Byte)(const?struct?IIC_Type*,uint8_t);?????//IIC_Send_Byte,入口參數(shù)為是否要發(fā)送ACK信號
???void?(*delay_us)(uint32_t);??????????????//us延時
}IIC_TypeDef;
iic.c源文件主要是類模板具體操作函數(shù)的實(shí)現(xiàn),具體如下:
//設(shè)置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設(shè)置為輸入模式
}
//設(shè)置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設(shè)置為輸出模式
}
//設(shè)置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);?????//設(shè)置SCL為高電平
??}
??else{
????HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_RESET);?????//設(shè)置SCL為低電平
??}
}
//設(shè)置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);?????//設(shè)置SDA為高電平
??}
??else{
????HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_RESET);?????//設(shè)置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;
????
???//根據(jù)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初始化設(shè)置
?????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初始化設(shè)置
?????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總線,準(zhǔn)備發(fā)送或接收數(shù)據(jù)?
}
//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);?//發(fā)送I2C總線結(jié)束信號
??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設(shè)置為輸入??
??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;??
}
//產(chǎn)生ACK應(yīng)答
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);
}
//產(chǎn)生NACK應(yīng)答
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,入口參數(shù)為要發(fā)送的字節(jié)
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);//拉低時鐘開始數(shù)據(jù)傳輸
?????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,入口參數(shù)為是否要發(fā)送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設(shè)置為輸入
???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);//發(fā)送nACK
??else
?????????IIC_Type_t->IIC_Ack(IIC_Type_t);?//發(fā)送ACK???
??return?receive;
}
//實(shí)例化一個IIC1外設(shè),相當(dāng)于一個結(jié)構(gòu)體變量,可以直接在其他文件中使用
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?????//需自己外部實(shí)現(xiàn)delay_us函數(shù)
};
上述就是IIC驅(qū)動的封裝,由于沒有應(yīng)用場景暫不測試其實(shí)用性,待下面ATC64的驅(qū)動縫縫扎黃寫完之后一起測試使用。
三.ATC64XX驅(qū)動封裝實(shí)現(xiàn)
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驅(qū)動
??uint8_t?(*AT24CXX_ReadOneByte)(const?struct?AT24CXX_Type*,uint16_t);??//指定地址讀取一個字節(jié)
??void?(*AT24CXX_WriteOneByte)(const?struct?AT24CXX_Type*,uint16_t,uint8_t);?//指定地址寫入一個字節(jié)
??void?(*AT24CXX_WriteLenByte)(uint16_t,uint32_t,uint8_t);?//指定地址開始寫入指定長度的數(shù)據(jù)
??uint32_t?(*AT24CXX_ReadLenByte)(uint16_t,uint8_t);???//指定地址開始讀取指定長度數(shù)據(jù)
??void?(*AT24CXX_Write)(uint16_t,uint8_t?*,uint16_t);??//指定地址開始寫入指定長度的數(shù)據(jù)
??void?(*AT24CXX_Read)(uint16_t,uint8_t?*,uint16_t);???//指定地址開始寫入指定長度的數(shù)據(jù)
??void?(*AT24CXX_Init)(const?struct?AT24CXX_Type*);?//初始化IIC
??uint8_t?(*AT24CXX_Check)(const?struct?AT24CXX_Type*);???//檢查器件
}AT24CXX_TypeDef;
extern?AT24CXX_TypeDef?AT24C_64;?????//外部聲明實(shí)例化AT24CXX對象
at24cxx.c源文件主要是類模板具體操作函數(shù)的實(shí)現(xiàn),具體如下:
//在AT24CXX指定地址讀出一個數(shù)據(jù)
//ReadAddr:開始讀數(shù)的地址??
//返回值??:讀到的數(shù)據(jù)
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);??
??//根據(jù)AT的型號發(fā)送不同的地址
??if(AT24CXX_Type_t->EEP_TYPE?>?AT24C16)
??{
????AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0);????//發(fā)送寫命令
????AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
????AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr>>8);//發(fā)送高地址?????
??}else?AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((ReadAddr/256)<<1));???//發(fā)送器件地址0XA0,寫數(shù)據(jù)?????
??AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);?
??AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr%256);???//發(fā)送低地址
??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);???????????//進(jìn)入接收模式??????
??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);//產(chǎn)生一個停止條件?????
??return?temp;
}
//在AT24CXX指定地址寫入一個數(shù)據(jù)
//WriteAddr??:寫入數(shù)據(jù)的目的地址????
//DataToWrite:要寫入的數(shù)據(jù)
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);????//發(fā)送寫命令
????AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
????AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr>>8);//發(fā)送高地址?????
??}else?AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((WriteAddr/256)<<1));???//發(fā)送器件地址0XA0,寫數(shù)據(jù)?????
??AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);?
???AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr%256);???//發(fā)送低地址
??AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);???????????????
??AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,DataToWrite);?????//發(fā)送字節(jié)??????????
??AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);????????????
???AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//產(chǎn)生一個停止條件?
?AT24CXX_Type_t->IIC.delay_us(10000);??
}
//在AT24CXX里面的指定地址開始寫入長度為Len的數(shù)據(jù)
//該函數(shù)用于寫入16bit或者32bit的數(shù)據(jù).
//WriteAddr??:開始寫入的地址??
//DataToWrite:數(shù)據(jù)數(shù)組首地址
//Len????????:要寫入數(shù)據(jù)的長度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的數(shù)據(jù)
//該函數(shù)用于讀出16bit或者32bit的數(shù)據(jù).
//ReadAddr???:開始讀出的地址?
//返回值?????:數(shù)據(jù)
//Len????????:要讀出數(shù)據(jù)的長度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里面的指定地址開始寫入指定個數(shù)的數(shù)據(jù)
//WriteAddr?:開始寫入的地址?對24c64為0~8191
//pBuffer???:數(shù)據(jù)數(shù)組首地址
//NumToWrite:要寫入數(shù)據(jù)的個數(shù)
static?void?AT24CXX_Write_t(uint16_t?WriteAddr,uint8_t?*pBuffer,uint16_t?NumToWrite)
{
??while(NumToWrite--)
??{
???AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
????WriteAddr++;
????pBuffer++;
??}
}
//在AT24CXX里面的指定地址開始讀出指定個數(shù)的數(shù)據(jù)
//ReadAddr?:開始讀出的地址?對24c64為0~8191
//pBuffer??:數(shù)據(jù)數(shù)組首地址
//NumToRead:要讀出數(shù)據(jù)的個數(shù)
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);//避免每次開機(jī)都寫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;??
}
//實(shí)例化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驅(qū)動
?.AT24CXX_ReadOneByte?=?AT24CXX_ReadOneByte_t,??//指定地址讀取一個字節(jié)
?.AT24CXX_WriteOneByte?=?AT24CXX_WriteOneByte_t,//指定地址寫入一個字節(jié)
?.AT24CXX_WriteLenByte?=?AT24CXX_WriteLenByte_t,?//指定地址開始寫入指定長度的數(shù)據(jù)
?.AT24CXX_ReadLenByte?=?AT24CXX_ReadLenByte_t,???//指定地址開始讀取指定長度數(shù)據(jù)
?.AT24CXX_Write?=?AT24CXX_Write_t,??//指定地址開始寫入指定長度的數(shù)據(jù)
?.AT24CXX_Read?=?AT24CXX_Read_t,???//指定地址開始讀取指定長度的數(shù)據(jù)
?.AT24CXX_Init?=?AT24CXX_Init_t,?//初始化IIC
?.AT24CXX_Check?=?AT24CXX_Check_t???//檢查器件
};
簡單分析:可以看出AT24CXX類中包含了IIC類的成員對象,這是一種包含關(guān)系,因?yàn)闆]有屬性上的一致性因此談不上繼承。
之所以將IIC的類對象作為AT24CXX類的成員是因?yàn)锳T24CXX的實(shí)現(xiàn)需要調(diào)用IIC的成員方法,IIC相當(dāng)于AT24CXX更下層的驅(qū)動,因此采用包含關(guān)系更合適。
因此我們在使用AT24CXX的時候只需要實(shí)例化AT24CXX類對象就行了,因?yàn)镮IC包含在AT24CXX類中間,因此不需要實(shí)例化IIC類對象,對外提供了較好的封裝接口。下面我們看具體的調(diào)用方法。
四.主函數(shù)main調(diào)用測試
在main函數(shù)中直接使用AT24C_64來完成所有操作,下面結(jié)合代碼來看:
#include?"at24cxx.h"????//為了確定AT24C_64的成員方法和引用操作對象AT24C_64
int?main(void)
{
??/************省略其他初始化工作****************/
??//第一步:調(diào)用對象初始化方法來初始化AT24C64
??AT24C_64.AT24CXX_Init(&AT24C_64);
??//第二步:調(diào)用對象檢測方法來檢測AT24C64 ??????????
??if(AT24C_64.AT24CXX_Check(&AT24C_64)?==?0)
??{
????printf("AT24C64檢測成功\r\n");
??}
??else{
????printf("AT24C64檢測失敗\r\n");
??}
??return?0;
}
可以看出所有的操作都是通過AT24C_64對象調(diào)用完成的,在我們初始化好AT24C_64對象之后就可以放心大膽的調(diào)用其成員方法,這樣封裝的好處就是一個設(shè)備對外只提供一個對象接口,簡潔明了。
五.總結(jié)
本文詳細(xì)介紹了面向?qū)ο蠓椒▽?shí)現(xiàn)IIC驅(qū)動封裝以及AT24CXX存儲器的封裝,最終對外僅提供一個操作對象接口,大大提高了代碼的復(fù)用性以及封裝性。
版權(quán)聲明:本文來源網(wǎng)絡(luò),免費(fèi)傳達(dá)知識,版權(quán)歸原作者所有。如涉及作品版權(quán)問題,請聯(lián)系我進(jìn)行刪除。
???????????????? ?END ????????????????
關(guān)注我的微信公眾號,回復(fù)“加群”按規(guī)則加入技術(shù)交流群。
點(diǎn)擊“閱讀原文”查看更多分享,歡迎點(diǎn)分享、收藏、點(diǎn)贊、在看。
