小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

51入門系列教程| 協(xié)議協(xié)議(IIC篇)

 Zmflc 2016-04-29

從這一貼開始,和大家一起聊聊有關(guān)通訊協(xié)議,通訊協(xié)議是指單片機(jī)和外部設(shè)備進(jìn)行數(shù)據(jù)交互的基本準(zhǔn)則.先說(shuō)說(shuō)物理連接吧!

地球上的通訊端口,從根本上來(lái)講只有兩種:一種是串行接口,即指數(shù)據(jù)按照高地位的一定順序,一位一位分時(shí)進(jìn)行傳輸;一種是并行接口,即指所有數(shù)據(jù),一次性同時(shí)進(jìn)行傳輸;由此可以看來(lái),并行接口理論上的速度會(huì)比串行接口快.為了簡(jiǎn)化單片機(jī)(主)和外部設(shè)備(從)的物理連接復(fù)雜度,一般情況下會(huì)使用串行接口.而單片機(jī)內(nèi)部的總線,一般就是并行的結(jié)構(gòu).俺們這里主要聊聊串行通信,再說(shuō)協(xié)議,這個(gè)是非常重要的通信手段.

舉個(gè)栗子,咱(主機(jī))和女神(從機(jī))聊天,首先得確認(rèn)兩個(gè)原則性的東西:第一,相同的語(yǔ)言.咱說(shuō)國(guó)語(yǔ),女神說(shuō)那美克星語(yǔ),直接后果就是雙方完全不能溝通.類比下來(lái),就是通訊中的信號(hào)協(xié)議,必須遵循一定的信號(hào)發(fā)送接收的格式.還記得韓梅梅和李雷嗎?

韓:hi,lilei,how are you

李:fine,thank you,and you?

韓:I’m fine too,goodbye

李:goodbye

韓用英語(yǔ)先喊名字打招呼,李聽到喊自己名字且聽懂后,才會(huì)有下面的交流.這就是一次完整的通信過(guò)程,以hi開始,以goodbye結(jié)束.

第二,相同的語(yǔ)速.雖然咱和女神都說(shuō)國(guó)語(yǔ).但是咱每秒說(shuō)10個(gè)字,女神每秒只能聽見并理解5個(gè)字,這樣下來(lái),明顯也無(wú)法正常溝通.不信你試試飛快地讀“西安”一詞,會(huì)不會(huì)有人理解成“先”一字呢?呵呵,速度快了,意思完全就不通了

拋開上面兩點(diǎn),接下來(lái)就是一些細(xì)節(jié)內(nèi)容了,譬如,咱向女神闡述長(zhǎng)達(dá)1分鐘的故事.女神在這1分鐘內(nèi),會(huì)隔一段時(shí)間回復(fù)一個(gè)“嗯”,來(lái)表示正在聆聽,并且做好準(zhǔn)備繼續(xù)聆聽.咱才能繼續(xù)講下去哈

反過(guò)來(lái)女神講事情給咱也是一樣,咱也得時(shí)不時(shí)回復(fù)一個(gè)“嗯”.好讓女神繼續(xù)講下去,如果換個(gè)場(chǎng)景,咱一個(gè)人(主機(jī))給多個(gè)人(多從機(jī))吹水.也基本上就是上面的過(guò)程,個(gè)人認(rèn)為一個(gè)串行通信比較重要的方面也就這么些了,下面來(lái)看看今天咱聊的具體對(duì)象IIC.

IIC,有些寫成I2C,簡(jiǎn)單讀成i方c,全稱Inter-Integrated Circuit,是由飛利浦在上世紀(jì)80年代設(shè)計(jì)推廣的一種通信總線協(xié)議,呃,現(xiàn)在應(yīng)該叫恩智浦(NXP)了.它只需要兩個(gè)IO口即可構(gòu)成,一根是SCL時(shí)鐘線,有些也標(biāo)為SCK之類,說(shuō)法不一;另外一根是SDA數(shù)據(jù)線,SCL是一個(gè)單向的IO,由主機(jī)向從機(jī)發(fā)送.SDA則是條雙向IO,主機(jī)需要對(duì)其進(jìn)行讀寫操作,每次8位數(shù)據(jù).讀的時(shí)候接收數(shù)據(jù),寫的時(shí)候發(fā)送數(shù)據(jù).

IIC的速度分為三個(gè)等級(jí):標(biāo)準(zhǔn)模式100kbit/s,快速模式400kbit/s,高速模式3.4Mbit/s.由SCL的頻率來(lái)決定.一般情況下,需要參照外圍器件的要求來(lái)決定SCL頻率.在硬件上,SDA和SCL是需要有上拉電阻,從機(jī)設(shè)備需要是OC/OD狀態(tài),集電極開路或者漏極開路,且這個(gè)上拉電阻的取值,會(huì)對(duì)速度產(chǎn)生比較大的影響.10kohm以下比較常見,個(gè)人喜歡4.7k,IIC要求的細(xì)則很多,有興趣可以下載英文原版的手冊(cè)研讀.這里聊聊一些基本要求:

1、基本原則

SCL為高時(shí),SDA不能亂動(dòng).SCL為低時(shí),SDA隨便玩.SCL必須由主機(jī)控制.在尋址過(guò)程中,一次發(fā)送數(shù)據(jù)8位,其中高7位為從機(jī)地址,最后一位為讀寫標(biāo)志位.So,每個(gè)從機(jī)一個(gè)地址,一條IIC總線理論上最多掛載127個(gè)從設(shè)備.主機(jī)呼叫,從機(jī)聽到叫自己才作出回應(yīng)

2、起始信號(hào)

類似于打招呼hi,告訴別人,咱要發(fā)話了

時(shí)序圖

51入門系列教程| 協(xié)議協(xié)議(IIC篇)

SCL在高電平器件,SDA出現(xiàn)一次下降沿,也就是SDA從高電平跳變到低電平,看代碼:

void start()

{

SDA=1; //SDA拉高

delay();

SCL=1; //SCL拉高

delay();

SDA=0; //SDA拉低,出現(xiàn)一次下降沿,形成起始信號(hào)

delay();

SCL=0; //SCL拉低

delay();

}

3、停止信號(hào)

時(shí)序圖

51入門系列教程| 協(xié)議協(xié)議(IIC篇)

類似于再見goodbye,告訴別人交流結(jié)束,SCL高電平期間,SDA由低電平跳變到高電平 ,也就是出現(xiàn)一次上升沿 ,看代碼:

void stop()

{

SDA=0; //SDA拉低

delay();

SCL=1; //SCL拉高

delay();

SDA=1; //SDA拉高,出現(xiàn)一次上升沿

delay();

}

4、應(yīng)答信號(hào)

應(yīng)答信號(hào)有兩類:一類是主機(jī)發(fā)送給從機(jī)的,另一類是從機(jī)發(fā)送給主機(jī)的,出現(xiàn)在8位數(shù)據(jù)傳輸結(jié)束后,第九個(gè)時(shí)鐘到來(lái)之時(shí),應(yīng)答信號(hào)一般稱為ACK信號(hào).至于NACK(非應(yīng)答信號(hào)),其實(shí)就是ACK的另一種說(shuō)法,時(shí)序圖:

51入門系列教程| 協(xié)議協(xié)議(IIC篇)

表示從機(jī)已經(jīng)收到之前傳輸?shù)?位數(shù)據(jù),簡(jiǎn)單點(diǎn)理解,就是女神的“嗯”(邪惡了!!!!!!!) .這個(gè)需要由主機(jī)讀取SDA的值,來(lái)判斷是否有ACK信號(hào).看代碼:

bit respons()

{

bit temp=0;

SDA=1; //主機(jī)將SDA拉高,釋放SDA控制權(quán)(SDA是上拉到電源的喲)

delay();

SCL=1; //SCL拉高

delay();

temp = SDA; //讀取SDA的值,賦給temp

SCL=0; //SCL拉低

delay();

return temp; //返回temp值

}

So,temp=1的話,是個(gè)NACK信號(hào),從機(jī)無(wú)響應(yīng) ,temp=0的話,則是個(gè)ACK信號(hào)咯,那就可以認(rèn)為,從機(jī)已經(jīng)接收到主機(jī)發(fā)送過(guò)來(lái)的數(shù)據(jù)了.

5、數(shù)據(jù)發(fā)送過(guò)程

每次傳遞8位的數(shù)據(jù),這些數(shù)據(jù)啥時(shí)候發(fā)送呢 ?看時(shí)序圖:

51入門系列教程| 協(xié)議協(xié)議(IIC篇)

So easy ,SCL高電平期間,保持SDA數(shù)據(jù)穩(wěn)定,就是1位數(shù)據(jù)傳過(guò)去了 .SCL低電平期間,SDA可以進(jìn)行數(shù)據(jù)變化...瞧代碼:

void wr_byte(uchar date)

{

uchar i;

for(i=0;i<>

{

date=date<1;>

SDA=CY; //將左移進(jìn)位信號(hào)1或0賦給SDA,詳見REG51.h中SY寄存器

delay();

SCL=1; //SDA穩(wěn)定后,SCL拉高

delay();

SCL=0; //SCL拉低

delay();

}

}

上面2-4肢解了IIC一次數(shù)據(jù)通信過(guò)程,就這么些.但是不同的IIC設(shè)備,讀寫時(shí)序略有不同,咱來(lái)看些具體的例子吧!正好手頭上有塊24C08

51入門系列教程| 協(xié)議協(xié)議(IIC篇)看看這貨的地址情況

51入門系列教程| 協(xié)議協(xié)議(IIC篇)8位尋址數(shù)據(jù),最后一位為讀寫標(biāo)志位,0寫1讀,D7-D1為地址位,其中高四位固定為1010,B2、B1、B0可操作.但是注意一下,對(duì)于24C08而言,B2位是由外部管腳確定的,寫無(wú)效.也就是說(shuō),一條IIC總線上可以掛2個(gè)24C08,B2為0或者1.而其他,特別是24C02,B0、B1、B2都是由外部管腳確定,可掛8片.不過(guò)24c08可以軟件操作B1和B0.B1B0=00時(shí),指向block0的256個(gè)字節(jié)空間.后面依次類推.總共有4x256=1024k字節(jié)=8kbit.所以叫做24c08,呵呵。在寫尋址的時(shí)候,地址為0xa1.在讀尋址的時(shí)候,地址為0xa0.看看這貨的操作過(guò)程

51入門系列教程| 協(xié)議協(xié)議(IIC篇)

其他細(xì)節(jié),可以參考數(shù)據(jù)手冊(cè) ,動(dòng)手?jǐn)]代碼:

#include

#include

#define uint unsigned int /*宏定義*/

#define uchar unsigned char /*宏定義*/

uchar WRDADDS= 0xa0 ; /*I2C器件地址,尋址寫*/

uchar RDDADDS =0xa1 ; /*I2C器件地址,尋址讀*/

sbit SDA = P1^0; /*數(shù)據(jù)線*/

sbit SCL = P1^1; /*時(shí)鐘線*/

sbit LED = P1^3;

void Write(uchar address,uchar date); /*向24c02的地址address中,寫入一字節(jié)數(shù)據(jù)date*/

uchar Read(uchar address); /*從24c02的地址address中,讀取一個(gè)字節(jié)數(shù)據(jù)(返回值)*/

void wr_byte(uchar date); /*I2C總線寫一個(gè)字節(jié)(有參數(shù))*/

uchar rd_byte(); /*I2C總線讀一個(gè)字節(jié)(返回值)*/

void start(); /*啟動(dòng)I2C總線*/

void stop(); /*停止I2C總線*/

bit respons(); /*I2C總線應(yīng)答信號(hào)檢查*/

void delay(); /*延時(shí)微秒*/

void delayms(uint xms); /*延時(shí)毫秒*/

/*向24c02的地址address中,寫入一字節(jié)數(shù)據(jù)date*/

void Write(uchar address,uchar date)

{

start(); //啟動(dòng)信號(hào)

wr_byte(WRDADDS); //I2C器件地址,尋址寫

while(respons()); //等待應(yīng)答信號(hào)

wr_byte(address); //選擇單元地址

while(respons()); //等待應(yīng)答信號(hào)

wr_byte(date); //寫數(shù)據(jù)

while(respons()); //等待應(yīng)答信號(hào)

stop(); //停止信號(hào)

}

/*從24c02的地址address中讀取一個(gè)字節(jié)數(shù)據(jù)*/

uchar Read(uchar address)

{

uchar temp;

start(); //開始信號(hào)

wr_byte(WRDADDS); //I2C器件地址,尋址寫

while(respons()); //等待應(yīng)答信號(hào)

wr_byte(address); //選擇單元地址 信號(hào)

while(respons()); //等待應(yīng)答信號(hào)

start(); //重發(fā)啟動(dòng)信號(hào)

wr_byte(RDDADDS); //I2C器件地址,尋址讀

while(respons()); //等待應(yīng)答信號(hào)

temp = rd_byte(); //讀數(shù)據(jù)(函數(shù)返回值)

stop(); //停止信號(hào)

return temp;

} /*啟動(dòng)I2C總線*/

void start()

{

SDA=1;

delay();

SCL=1;

delay();

SDA=0;

delay();

SCL=0;

delay();

}

/*停止I2C總線*/

void stop()

{

SDA=0;

delay();

SCL=1;

delay();

SDA=1;

delay();

}

/*I2C總線應(yīng)答信號(hào)檢查*/

bit respons()

{

bit temp=0;

SDA=1;

delay();

SCL=1;

delay();

temp = SDA;

SCL=0;

delay();

return temp;

}

/*I2C總線寫一個(gè)字節(jié)*/

void wr_byte(uchar date)

{

uchar i;

for(i=0;i<>

{

date=date<>

SDA=CY;

delay();

SCL=1;

delay();

SCL=0;

delay();

}

}

/*I2C總線讀一個(gè)字節(jié)*/

uchar rd_byte()

{

uchar i,temp;

for(i=0;i<>

{

SCL=1;

delay();

temp=(temp<>

delay();

SCL=0;

delay();

}

return temp;

}

/*NOP延時(shí)函數(shù)*/

void delay()

{

_nop_();

_nop_();

_nop_();

_nop_();

_nop_();

}

/*延時(shí)函數(shù)*/

void delayms(uint xms)

{

uint i,j;

for(i=0;i<>

for(j=0;j<>

}

void main()

{

uchar num,x;

uint i,count1,count2;

LED = 1;

for(i=0;i<1024;i++)>

count2++;

if(i<256)>

Write(i,i);

delayms(20);

num = Read(i);

if(num==i)

{

count1++;

LED = ~LED;

}

}

if((256<><=512))>

x = (i-256);

WRDADDS = 0xa2;

RDDADDS = 0xa3;

Write(x,x);

delayms(20);

num = Read(x);

if(num==x)

{

count1++;

LED = ~LED;

}

}

if((512<><=768))>

x = (i-512);

WRDADDS = 0xa4;

RDDADDS = 0xa5;

Write(x,x);

delayms(20);

num = Read(x);

if(num==x)

{

count1++;

LED = ~LED;

}

}

if((768<><1024))>

WRDADDS = 0xa6;

RDDADDS = 0xa7;

x = (i-768);

Write(x,x);

delayms(20);

num = Read(x);

if(num==x)

{

count1++;

LED = ~LED; }

}

}

if(count1==count2)

{LED=0;}

else{LED = 1;}

while (1)

{

}

}

可以參照對(duì)比上面的時(shí)序,把代碼簡(jiǎn)單讀一下.寫得比較隨意,了解一下大概過(guò)程即可.尤其是Read和Write兩個(gè)函數(shù).大致功能就是把24C08所有的存儲(chǔ)單元都進(jìn)行一次讀寫同時(shí)blink.如果每個(gè)單元寫入和讀出的數(shù)據(jù)相同,最后LED點(diǎn)亮.上個(gè)GIF

51入門系列教程| 協(xié)議協(xié)議(IIC篇)

有些時(shí)候咱操作的不一定是EEPROM,還有一些其他傳感器器件 ,正好手頭上有塊TMP75B:

51入門系列教程| 協(xié)議協(xié)議(IIC篇)

很早以前向TI申請(qǐng)的樣片,溫度傳感器 ,看看這貨的地址和讀寫時(shí)序吧

51入門系列教程| 協(xié)議協(xié)議(IIC篇)

A0-A2均可由外部管腳確定,不過(guò)高4位固定為1001,tmp75b地址寫為0x90,地址讀為0x91

51入門系列教程| 協(xié)議協(xié)議(IIC篇)因?yàn)門MP75B需要16位來(lái)完成溫度的讀取,所以需要連續(xù)讀2個(gè)字節(jié)來(lái)獲得溫度值.注意紅圈內(nèi)的時(shí)序要求.在多字節(jié)傳輸?shù)臅r(shí)候,每個(gè)字節(jié)傳輸結(jié)束后,主機(jī)需要發(fā)送一個(gè)ACK.也就是SCL高電平期間,SDA保持低電平.表示接收到了一個(gè)8位數(shù)據(jù).然后將SDA拉高.簡(jiǎn)單修改一下上面的代碼,完成連續(xù)讀的操作.

#define WRDADDS 0x90 ; /*宏定義I2C器件tmp75b地址,尋址寫*/

#define RDDADDS 0x91 ; /*宏定義I2C器件tmp75b地址,尋址讀*/

void ack_master()

{

SDA=0;

delay();

SCL=1;

delay();

SCL=0;

delay();

SDA=1;

delay();

}

uint Read_temprature(uchar address)//連續(xù)讀2個(gè)字節(jié)的溫度數(shù)據(jù)

{

uint temp;

start(); //開始信號(hào)

wr_byte(WRDADDS); //I2C器件地址,尋址寫

while(respons()); //應(yīng)答信號(hào)

wr_byte(address); //選擇單元地址 信號(hào)

while(respons()); //應(yīng)答信號(hào)

stop();

start(); //重發(fā)啟動(dòng)信號(hào)

wr_byte(RDDADDS); //I2C器件地址,尋址讀

while(respons()); //應(yīng)答信號(hào)

temp = rd_byte()<8;>

ack_master();

temp |= rd_byte(); //低8位數(shù)據(jù)

ack_master();

stop(); //停止信號(hào)

return temp;

}

void main()

{

float temprature;

LED = 1; //熄滅LED

while (1)

{

Write(0x00,0x00);

delayms(20);

nums = Read_temprature(0x00); //獲取16位溫度HEX

temprature = (nums>>4)*0.0625; //換算溫度值

if(temprature>25.0){LED = 0;} //如果溫度大于25,點(diǎn)LED

else {LED = 1;} //否則熄滅

}

}

看看

Read_temprature

函數(shù),是不是和貼圖的時(shí)序一致呢?代碼基本功能就是,通過(guò)IIC與傳感器TMP75B通信.獲取溫度信息

如果超過(guò)25度就點(diǎn)亮LED, 否則熄滅LED!上GIF:

51入門系列教程| 協(xié)議協(xié)議(IIC篇)

好累!這次就先到這里.

了解更多51系列教程,請(qǐng)關(guān)注“云漢電子社區(qū)”官方微信公眾號(hào)ickeybbs,或者登錄云漢電子社區(qū)官方網(wǎng)站(bbs.ickey.cn)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多