九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

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

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

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

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

韓:hi,lilei,how are you

李:fine,thank you,and you?

韓:I’m fine too,goodbye

李:goodbye

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

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

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

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

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

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

1、基本原則

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

2、起始信號

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

時序圖

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

void start()

{

SDA=1; //SDA拉高

delay();

SCL=1; //SCL拉高

delay();

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

delay();

SCL=0; //SCL拉低

delay();

}

3、停止信號

時序圖

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

void stop()

{

SDA=0; //SDA拉低

delay();

SCL=1; //SCL拉高

delay();

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

delay();

}

4、應答信號

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

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

bit respons()

{

bit temp=0;

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

delay();

SCL=1; //SCL拉高

delay();

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

SCL=0; //SCL拉低

delay();

return temp; //返回temp值

}

So,temp=1的話,是個NACK信號,從機無響應 ,temp=0的話,則是個ACK信號咯,那就可以認為,從機已經(jīng)接收到主機發(fā)送過來的數(shù)據(jù)了.

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

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

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

void wr_byte(uchar date)

{

uchar i;

for(i=0;i<>

{

date=date<1;>

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

delay();

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

delay();

SCL=0; //SCL拉低

delay();

}

}

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

看看這貨的地址情況

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

其他細節(jié),可以參考數(shù)據(jù)手冊 ,動手擼代碼:

#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; /*時鐘線*/

sbit LED = P1^3;

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

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

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

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

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

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

bit respons(); /*I2C總線應答信號檢查*/

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

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

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

void Write(uchar address,uchar date)

{

start(); //啟動信號

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

while(respons()); //等待應答信號

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

while(respons()); //等待應答信號

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

while(respons()); //等待應答信號

stop(); //停止信號

}

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

uchar Read(uchar address)

{

uchar temp;

start(); //開始信號

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

while(respons()); //等待應答信號

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

while(respons()); //等待應答信號

start(); //重發(fā)啟動信號

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

while(respons()); //等待應答信號

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

stop(); //停止信號

return temp;

} /*啟動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總線應答信號檢查*/

bit respons()

{

bit temp=0;

SDA=1;

delay();

SCL=1;

delay();

temp = SDA;

SCL=0;

delay();

return temp;

}

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

void wr_byte(uchar date)

{

uchar i;

for(i=0;i<>

{

date=date<>

SDA=CY;

delay();

SCL=1;

delay();

SCL=0;

delay();

}

}

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

uchar rd_byte()

{

uchar i,temp;

for(i=0;i<>

{

SCL=1;

delay();

temp=(temp<>

delay();

SCL=0;

delay();

}

return temp;

}

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

void delay()

{

_nop_();

_nop_();

_nop_();

_nop_();

_nop_();

}

/*延時函數(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)

{

}

}

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

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

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

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

因為TMP75B需要16位來完成溫度的讀取,所以需要連續(xù)讀2個字節(jié)來獲得溫度值.注意紅圈內(nèi)的時序要求.在多字節(jié)傳輸?shù)臅r候,每個字節(jié)傳輸結束后,主機需要發(fā)送一個ACK.也就是SCL高電平期間,SDA保持低電平.表示接收到了一個8位數(shù)據(jù).然后將SDA拉高.簡單修改一下上面的代碼,完成連續(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個字節(jié)的溫度數(shù)據(jù)

{

uint temp;

start(); //開始信號

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

while(respons()); //應答信號

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

while(respons()); //應答信號

stop();

start(); //重發(fā)啟動信號

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

while(respons()); //應答信號

temp = rd_byte()<8;>

ack_master();

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

ack_master();

stop(); //停止信號

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,點LED

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

}

}

看看

Read_temprature

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

如果超過25度就點亮LED, 否則熄滅LED!上GIF:

好累!這次就先到這里.

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

本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
基于51的IIC通訊原理及協(xié)議詳解(I2C)
IIC總線通信協(xié)議
IIC 通訊協(xié)議
IIC總線操作AT24C02芯片詳解
I2C總線三
I2c串行總線組成及其工作原理
更多類似文章 >>
生活服務
熱點新聞
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服