<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          IIC驅(qū)動?C語言使用面向?qū)ο髞韺?shí)現(xiàn)

          共 13896字,需瀏覽 28分鐘

           ·

          2022-05-27 16:55

          ????關(guān)注、星標(biāo)公眾號,直達(dá)精彩內(nèi)容

          來源:網(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)贊、在看。

          瀏覽 62
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  翔田千里无码AV在线观看 | 欧美日韩国产中文在线 | 天天干夜夜干 | 毛片中文字幕 | 色天堂影院 |