日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

GPIO口模拟I2C操作

發(fā)布時(shí)間:2024/4/24 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 GPIO口模拟I2C操作 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

/*
? ?? ???作者:天空
? ?? ???日期:2014.5.12
? ?? ???功能:利用GPIO口模擬I2C總線,對(duì)傳感器寄存器讀取數(shù)據(jù)
? ?? ???注意:如果需要移植些文件到其他設(shè)備上,需要更改的函數(shù)地方
? ?? ???1、利用GPIO口模擬的數(shù)據(jù)線SDA和時(shí)鐘線SCL,注意需要更改GPIO口
? ?? ???2、從設(shè)備地址。不同的從設(shè)備,地址不一樣,注意修改。(在I2C寫寄存器和讀寄存器的函數(shù)中,如果是寫,在讀的地址上加1.)
? ?? ???經(jīng)驗(yàn):利用GPIO口模擬I2C總線時(shí),需要注意的是,在應(yīng)答信號(hào)和讀數(shù)據(jù)的時(shí)候,一定要將SDA數(shù)據(jù)線配置為輸入。
*/
#define SCL P0_5//定義P0.5口為時(shí)鐘線
#define SDA P0_4//定義P0.4口為數(shù)據(jù)線

typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned short ushort;

/*延時(shí)函數(shù)*/
void Delay(void)
{
}

/*I2C總線實(shí)始化,將P0.4和P0.5配置為輸出口,并且拉高*/
/*
? ?? ???I2C總線的開(kāi)始時(shí)序:
? ?? ???1、將數(shù)據(jù)線SDA和時(shí)鐘線SCL全部拉高
*/
void I2C_Init(void)
{
? ? P0SEL &= ~0x30;//將P0.4和P0.5配置為GPIO口
? ? P0DIR |= 0x30;//將P0.4和P0.5配置為輸出

? ? P0 |= 0x30;//將P0.4和P0.5設(shè)置為高電平
}

/*I2C總線的開(kāi)始信號(hào)*/
/*
? ?? ???I2C總線的開(kāi)始時(shí)序:
? ?? ???1、將SDA數(shù)據(jù)線拉高
? ?? ???2、將SCL時(shí)鐘線拉高,延時(shí)一段時(shí)間
? ?? ???3、在SCL為高電平時(shí),拉低SDA,延時(shí)一段時(shí)間
? ?? ???總結(jié):就是在SCL為高電平時(shí),在SDA上給一個(gè)下降沿,表示開(kāi)始信號(hào)。
*/
void I2C_Start(void)
{
? ? SDA = 1;
? ? SCL = 1;
? ? Delay();
? ? SDA = 0;
? ? Delay();
}

/*I2C總線的停止信號(hào)*/
/*
? ?? ???I2C總線的停止時(shí)序:
? ?? ???1、將SDA數(shù)據(jù)線拉低
? ?? ???2、將SCL數(shù)據(jù)線拉高,延時(shí)一段時(shí)間
? ?? ???3、在SCL為高電平時(shí),將SDA數(shù)據(jù)線拉高,延時(shí)一段時(shí)間
? ?? ???總結(jié):在SCL為高電平時(shí),在SDA上給一下上升沿,表示停止信號(hào)。
*/
void I2C_Stop(void)
{
? ? SDA = 0;
? ? SCL = 1;
? ? Delay();
? ? SDA = 1;
? ? Delay();
}


/*I2C總線的應(yīng)答信號(hào)*/
/*
? ?? ???I2C總線應(yīng)答時(shí)序:
? ?? ???1、首先是需要將模擬數(shù)據(jù)線的SDA口配置為輸入口。
? ?? ???2、將時(shí)鐘線SCL拉高,延時(shí)一段時(shí)間
? ?? ???3、等待從設(shè)備應(yīng)答,從設(shè)備應(yīng)答時(shí),SDA上會(huì)產(chǎn)生一個(gè)高電平,主設(shè)備的GPIO口檢測(cè)到高電平,則表示應(yīng)答成功。
? ?? ???4、如果檢測(cè)到應(yīng)答信號(hào),則拉SCL時(shí)鐘線拉低。延時(shí)一段時(shí)間。
? ?? ???5、將模擬SDA口的GPIO口配置為輸出。
*/
void I2C_Ack(void)
{
? ? P0DIR &= ~0x10;//注意這里,數(shù)據(jù)線應(yīng)該設(shè)置為輸入
? ? uint i = 0;

? ? SCL = 1;
? ? Delay();
? ? //等待應(yīng)答
? ? while((SDA == 1)&&(i<255))
? ?? ?i++;

? ? SCL = 0;
? ? Delay();
? ? P0DIR |= 0x10;//將數(shù)據(jù)線SDA設(shè)置為輸出
}

/*I2C總線寫數(shù)據(jù)函數(shù),將要寫的數(shù)據(jù)傳遞給形參I2CBuf*/
/*
? ?? ???I2C寫數(shù)據(jù)時(shí)序:
? ?? ???注意:由于I2C屬于串行總線,所以數(shù)據(jù)都是一位一位的傳輸
? ?? ???1、將SCL時(shí)鐘線拉高,準(zhǔn)備傳輸數(shù)據(jù),延時(shí)一段時(shí)間
? ?? ???2、將I2CBuf的最高位傳輸?shù)絊DA數(shù)據(jù)線上
? ?? ???3、拉低SCL時(shí)鐘線,延時(shí)一段時(shí)間
? ?? ???小結(jié):當(dāng)SCL有一個(gè)上升沿時(shí),傳輸數(shù)據(jù)。
? ?? ???以上三步表示傳輸完一位數(shù)據(jù)。然后將I2CBuf左移一位,再重復(fù)以上三步。
? ?? ???最后,將SCL位低,延時(shí)一段時(shí)間,再將SDA位高,延時(shí)一段時(shí)間。此操作是為了釋放時(shí)鐘線SCL和數(shù)據(jù)線SDA.
*/
void I2C_Write(uint I2CBuf)
{
? ? uint iwi;
? ? for(iwi = 0; iwi < 8; iwi++)
? ? {
? ?? ???SCL = 0;
? ?? ???Delay();
? ?? ???if(I2CBuf & 0x80)
? ?? ?? ? SDA = 1;
? ?? ???else?
? ?? ?? ? SDA = 0;
? ?? ???SCL = 1;
? ?? ???Delay();
? ?? ???I2CBuf = I2CBuf << 1;

? ? }

? ? SCL = 0;
? ? Delay();
? ? SDA = 1;
? ? Delay();


}

/*I2C總線讀數(shù)據(jù)函數(shù),該函數(shù)具有返回值I2CBuf*/
/*
? ?? ???I2C讀數(shù)據(jù)函數(shù)的時(shí)序:
? ?? ???注意:首先需要將模擬SDA數(shù)據(jù)線的GPIO口配置為輸入
? ?? ???1、將時(shí)鐘線SCL拉高,延時(shí)一段時(shí)間
? ?? ???2、讀取數(shù)據(jù)線SDA上的電平,然后寫入I2CBuf的最低位。
? ?? ???3、拉低SCL時(shí)鐘線,延時(shí)一段時(shí)間
? ?? ???小結(jié):當(dāng)SCL有一個(gè)下降沿時(shí),讀取數(shù)據(jù)。
? ?? ???以上三步表示讀取一位數(shù)據(jù),讀一個(gè)字節(jié),需要重復(fù)以上操作步驟8次。
*/
uint I2C_Read(void)
{
? ? uint iri;
? ? uint I2CBuf = 0;

? ? P0DIR &= ~0x10;//注意這里,需要將SDA配置為輸入。
? ? Delay();

? ? for(iri = 0; iri < 8; iri++)
? ? {
? ?? ???I2CBuf = I2CBuf << 1;//此步不可少
? ?? ???SCL = 1;
? ?? ???Delay();
? ?? ???if(SDA == 1)
? ?? ?? ? I2CBuf |= 0x01;
? ?? ???else
? ?? ?? ? I2CBuf &= 0xfe;
? ?? ???SCL = 0;
? ?? ???Delay();
? ? }

? ? P0DIR |= 0X10;//將SDA配置為輸出
? ? return I2CBuf;//將讀到的數(shù)據(jù)存入I2CBuf中,然后返回給主調(diào)函數(shù)

}

/*
I2C總線寫寄存器函數(shù),將寄存器地址傳給形參RegAdd,將要寫入的數(shù)據(jù)傳遞給RegValue。
注意:地址和數(shù)據(jù)最好都采用十六進(jìn)制
*/

/*
? ?? ???I2C寫寄存器函數(shù)的時(shí)序:
? ?? ???1、主設(shè)備先發(fā)出一個(gè)開(kāi)始信號(hào)
? ?? ???2、然后寫入從設(shè)備地址。每一個(gè)從設(shè)備的地址是唯一的。
? ?? ???3、主設(shè)備接收應(yīng)答信號(hào)
? ?? ???4、主設(shè)備向從設(shè)備寫入寄存器的地址
? ?? ???5、主設(shè)備接收應(yīng)答信號(hào)
? ?? ???6、主設(shè)備向從設(shè)備寫入數(shù)據(jù)
? ?? ???7、主設(shè)備接收應(yīng)答信號(hào)
? ?? ???8、主設(shè)備發(fā)出停止信號(hào)
*/
void I2C_WriteReg(uint RegAdd, uint RegValue)
{
? ? I2C_Start();
? ? I2C_Write(0xd0);//0xd0是從設(shè)置的地址,不同的設(shè)備,地址不同。所以移植些函數(shù)時(shí),需要更改此處。
? ? I2C_Ack();
? ? I2C_Write(RegAdd);//先寫地址,此地址為需要寫入數(shù)據(jù)的寄存器地址
? ? I2C_Ack();
? ? I2C_Write(RegValue);//寫入數(shù)據(jù)
? ? I2C_Ack();
? ? I2C_Stop();
}

/*I2C總線讀寄存器函數(shù),將需要讀取數(shù)據(jù)的寄存器的地址傳遞給形參RegAdd,此函數(shù)有返回值*/

/*
? ?? ???I2C讀寄存器函數(shù)的時(shí)序:
? ?? ???1、主設(shè)備發(fā)出開(kāi)始信號(hào)
? ?? ???2、寫入從設(shè)備地址
? ?? ???3、主設(shè)備接收從設(shè)備發(fā)來(lái)的應(yīng)答信號(hào)
? ?? ???4、寫入寄存器地址
? ?? ???5、主設(shè)備接收應(yīng)答信號(hào)
? ?? ???6、主設(shè)備再次發(fā)出開(kāi)始信號(hào)
? ?? ???7、主設(shè)備向從設(shè)備寫入(從設(shè)備的地址+1),此時(shí)加1表示要從寄存器中讀數(shù)據(jù)
? ?? ???8、從設(shè)備給出應(yīng)答信號(hào)
? ?? ???9、從從設(shè)備的寄存器中讀出數(shù)據(jù)傳給變量
? ?? ???10、主設(shè)備發(fā)出停止信號(hào)
? ?? ???11、返回讀出的數(shù)據(jù)
*/
uint I2C_ReadReg(uint RegAdd)
{
? ? uchar date;
? ? I2C_Start();
? ? I2C_Write(0xd0);//先寫入從設(shè)備的地址。表示要向從設(shè)備中寫地址和數(shù)據(jù)
? ? I2C_Ack();
? ? I2C_Write(RegAdd);//寫入寄存器的地址,數(shù)據(jù)將從些地址中讀出
? ? I2C_Ack();
? ? I2C_Start();
? ? I2C_Write(0xd1);//從設(shè)備的地址加1,表示要讀從設(shè)備中寄存器的數(shù)據(jù)
? ? I2C_Ack();
? ? date = I2C_Read();//從地址RegAdd中讀出數(shù)據(jù)
? ? I2C_Stop();
? ? return date;//將讀出的數(shù)據(jù)存入date中,然后返回給主調(diào)函數(shù)。
}
?

總結(jié)

以上是生活随笔為你收集整理的GPIO口模拟I2C操作的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。