久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 20753|回復: 9
打印 上一主題 下一主題
收起左側

51單片機I2C詳解與程序源碼

  [復制鏈接]
跳轉到指定樓層
樓主
ID:338578 發表于 2018-5-26 12:09 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
I2C是由Philips公司發明的一種串行數據通信協議,僅使用兩根信號線:SerialClock(簡稱SCL)和SerialData(簡稱SDA)。I2C是總線結構,1個Master,1個或多個Slave,各Slave設備以7位地址區分,地址后面再跟1位讀寫位,表示讀(=1)或者寫(=0),所以我們有時也可看到8位形式的設備地址,此時每個設備有讀、寫兩個地址,高7位地址其實是相同的。
I2C數據格式如下:
無數據:SCL=1,SDA=1;
開始位(Start):當SCL=1時,SDA由1向0跳變;
停止位(Stop):當SCL=1時,SDA由0向1跳變;
數據位:當SCL由0向1跳變時,由發送方控制SDA,此時SDA為有效數據,不可隨意改變SDA;
當SCL保持為0時,SDA上的數據可隨意改變;
地址位:定義同數據位,但只由Master發給Slave;
應答位(ACK):當發送方傳送完8位時,發送方釋放SDA,由接收方控制SDA,且SDA=0;
否應答位(NACK):當發送方傳送完8位時,發送方釋放SDA,由接收方控制SDA,且SDA=1。

當數據為單字節傳送時,格式為:
開始位,8位地址位(含1位讀寫位),應答,8位數據,應答,停止位。
當數據為一串字節傳送時,格式為:
開始位,8位地址位(含1位讀寫位),應答,8位數據,應答,8位數據,應答,……,8位數據,應答,停止位。

需要注意的是:
1,SCL一直由Master控制,SDA依照數據傳送的方向,讀數據時由Slave控制SDA,寫數據時由Master控制SDA。當8位數據傳送完畢之后,應答位或者否應答位的SDA控制權與數據位傳送時相反。
2,開始位“Start”和停止位“Stop”,只能由Master來發出。
3,地址的8位傳送完畢后,成功配置地址的Slave設備必須發送“ACK”。否則否則一定時間之后Master視為超時,將放棄數據傳送,發送“Stop”。
4,當寫數據的時候,Master每發送完8個數據位,Slave設備如果還有空間接受下一個字節應該回答“ACK”,Slave設備如果沒有空間接受更多的字節應該回答“NACK”,Master當收到“NACK”或者一定時間之后沒收到任何數據將視為超時,此時Master放棄數據傳送,發送“Stop”。
5,當讀數據的時候,Slave設備每發送完8個數據位,如果Master希望繼續讀下一個字節,Master應該回答“ACK”以提示Slave準備下一個數據,如果Master不希望讀取更多字節,Master應該回答“NACK”以提示Slave設備準備接收Stop信號。
6,當Master速度過快Slave端來不及處理時,Slave設備可以拉低SCL不放(SCL=0將發生“線與”)以阻止Master發送更多的數據。此時Master將視情況減慢或結束數據傳送。

在實際應用中,并沒有強制規定數據接收方必須對于發送的8位數據做出回應,尤其是在Master和Slave端都是用GPIO軟件模擬的方法來實現的情況下,編程者可以事先約定數據傳送的長度,slave不檢查NACK,有時可以起到減少系統開銷的效果。但是如果slave方是硬件i2c要求一定要標準的NACK,master方是GPIO軟件模擬i2c并沒有正確的發送NACK,就會出現“slave收不到stop”導致i2c掛死。

在正常情況下,I2C總線協議能夠保證總線正常的讀寫操作。但是,當I2C主設備異常復位時(看門狗動作,板上電源異常導致復位芯片動作,手動按鈕復位等等)有可能導致I2C總線死鎖產生。下面詳細說明一下總線死鎖產生的原因。

    在I2C主設備進行讀寫操作的過程中.主設備在開始信號后控制SCL產生8個時鐘脈沖,然后拉低SCL信號為低電平,在這個時候,從設備輸出應答信號,將SDA信號拉為低電平。如果這個時候主設備異常復位,SCL就會被釋放為高電平。此時,如果從設備沒有復位,就會繼續I2C的應答,將SDA一直拉為低電平,直到SCL變為低電平,才會結束應答信號。而對于I2C主設備來說.復位后檢測SCL和SDA信號,如果發現SDA信號為低電平,則會認為I2C總線被占用,會一直等待SCL和SDA信號變為高電平。這樣,I2C主設備等待從設備釋放SDA信號,而同時I2C從設備又在等待主設備將SCL信號拉低以釋放應答信號,兩者相互等待,I2C總線進人一種死鎖狀態。同樣,當I2C進行讀操作,I2C從設備應答后輸出數據,如果在這個時刻I2C主設備異常復位而此時I2C從設備輸出的數據位正好為0,也會導致I2C總線進入死鎖狀態。

方法

    (1)盡量選用帶復位輸人的I2C從器件。

    (2)將所有的從I2C設備的電源連接在一起,通過MOS管連接到主電源,而MOS管的導通關斷由I2C主設備來實現。
    (3)在I2C從設備設計看門狗的功能。

    (4)在I2C主設備中增加I2C總線恢復程序。

        每次I2C主設備復位后,如果檢測到SDA數據線被拉低,則控制I2C中的SCL時鐘線產生9個時鐘脈沖(針對8位數據的情況,“9個clk可以激活”的方法來自NXP的文檔,NXP(Philips)作為I2C總線的鼻祖,這樣的說法是可信的),這樣I2C從設備就可以完成被掛起的讀操作,從死鎖狀態中恢復過來。

        這種方法有很大的局限性,因為大部分主設備的I2C模塊由內置的硬件電路來實現,軟件并不能夠直接控制SCL信號模擬產生需要時鐘脈沖。

        或者,發送I2C_Stop條件也能讓從設備釋放總線。

        如果是GPIO模擬I2C總線實現,那么在I2C操作之前,加入I2C總線狀態檢測I2C_Probe,如果總線被占用,則可嘗試恢復總線,待總線釋放后,再進行操作。要保證I2C操作最小單元的完整性,不被其他事件(中斷、高優先級線程,等)打斷。

  (5)在I2C總線上增加一個額外的總線恢復設備。這個設備監視I2C總線。當設備檢測到SDA信號被拉低超過指定時間時,就在SCL總線上產生9個時鐘脈沖,使I2C從設備完成讀操作,從死鎖狀態上恢復出來。總線恢復設備需要有具有編程功能,一般可以用單片機或CPLD實現這一功能。

  (6)在I2C上串人一個具有死鎖恢復的I2C緩沖器,如Linear公司的LTC4307是一個雙向的I2C總線緩沖器,并且具有I2C總線死鎖恢復的功能。LTC4307總線輸入側連接主設備,總線輸出側連接所有從設備。當LTC4307檢測到輸出側SDA或SCL信號被拉低30ms時,就自動斷開I2C總線輸入側與輸出側的連接.并且在輸出側SCL信號上產生16個時鐘脈沖來釋放總線。當總線成功恢復后,LTC4307會再次連接輸入輸出側,使總線能夠正常工作。


  1. void I2Cstart()//開始標志  
  2. {     
  3.     SDA=1;  
  4.     SCL=1;  
  5.     SDA=0;  
  6.     delay1ms(4);  
  7.     SCL=0;  
  8.     delay1ms(4);  
  9. }  
  10. void I2Cstop()//結束標志  
  11. {  
  12.     SCL=0;  
  13.     delay1ms(4);  
  14.     SDA=0;  
  15.     delay1ms(4);  
  16.     SCL=1;  
  17.     delay1ms(4);  
  18.     SDA=1;  
  19.     delay1ms(4);  
  20. }  
  21. unsigned char I2Creadack()  
  22. {  
  23.     unsigned char i,byte;  
  24.     byte=0;  
  25.     for(i=0;i<8;i++)  
  26.     {  
  27.         SCL=0;  
  28.         SDA=1;  
  29.         delay1ms(4);  
  30.         byte<<=1;  
  31.         if(SDA==1)  
  32.         {  
  33.             byte|=0x01;  
  34.             delay1ms(4);  
  35.         }  
  36.     }  
  37.     SCL=0;  
  38.     delay1ms(4);  
  39.     SDA=0;  
  40.     delay1ms(4);  
  41.     SCL=1;  
  42.     delay1ms(4);  
  43.     SCL=0;  
  44.     return byte;  
  45. }  
  46. void I2Csend(unsigned char byte)//I2C寫數據的過程  
  47. {  
  48.   
  49.     unsigned char mask,i;  
  50.     for(i=0;i<8;i++)  
  51.     {     
  52.         SCL=0;  
  53.         if((mask&byte)==0)  
  54.         {  
  55.             SDA=0;  
  56.         }  
  57.         else  
  58.         {  
  59.             SDA=1;  
  60.         }  
  61.         mask>>=1;  
  62.         delay1ms(4);  
  63.         SCL=1;//給足夠時間讓數據讀取  
  64.         delay1ms(4);  
  65.   
  66.     }  
  67.     SCL=0;  
  68.     SDA=1;      //因為總線上有一個信號為低則低  
  69.     delay1ms(4);  
  70.     SCL=1;  
  71.     delay1ms(4);//等待應答位  
  72.     SCL=0;  
  73. }  
  74. unsigned char I2Cread(void)  
  75. {  
  76.     unsigned char i,byte;  
  77.     byte =0;  
  78.     for(i=0;i<8;i++)  
  79.     {  
  80.         SCL=0;  
  81.         SDA=1;//讀數據必須拉高  
  82.         delay1ms(4);  
  83.         SCL=1;//數據穩定  
  84.         delay1ms(4);  
  85.         byte<<=1;  
  86.         if(SDA==1)  
  87.         {  
  88.             byte|=0x01;  
  89.         }  
  90.         delay1ms(4);  
  91.     }  
  92.     SCL=0;  
  93.     delay1ms(4);  
  94.     SDA=0;//發送的應答位  
  95.     delay1ms(4);  
  96.     SCL=1;  
  97.     delay1ms(4);  
  98.     SCL=0;  
  99.     return byte;  
  100. }  
  101. unsigned char I2Cread_eeprom(unsigned char addr)//I2C讀取數據  
  102. {  
  103.     unsigned char datebyte,datebyte2;  
  104.     I2Cstart();  
  105.     I2Csend(0xa0);//寫數據  
  106.     I2Csend(addr);  
  107.     I2Cstart();  
  108.     I2Csend(0xa1);//讀數據  
  109.     datebyte2=I2Creadack();  
  110.     datebyte=I2Cread();  
  111.     I2Cstop();  
  112.     return datebyte;  
  113.   
  114. }  
  115.   
  116. void write_eeprom(unsigned char addr,unsigned char datebyte)  
  117. {  
  118.     I2Cstart();  
  119.     I2Csend(0xa0);  
  120.     I2Csend(addr);  
  121.     I2Csend(datebyte);  
  122.     I2Cstop();  
  123. }  
復制代碼


i2c.zip

723 Bytes, 下載次數: 179, 下載積分: 黑幣 -5

示例程序

評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏15 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:184273 發表于 2018-8-22 15:39 | 只看該作者
多謝樓主分享!
回復

使用道具 舉報

板凳
ID:585781 發表于 2019-7-22 14:41 | 只看該作者
這個i2c協議真厲害
回復

使用道具 舉報

地板
ID:476487 發表于 2019-9-24 10:45 | 只看該作者
講解真詳細,謝謝樓主分享
回復

使用道具 舉報

5#
ID:18797 發表于 2019-10-4 17:47 | 只看該作者
謝謝,進一步增強了對IIC的認識
回復

使用道具 舉報

6#
ID:558533 發表于 2019-10-15 08:54 | 只看該作者
謝謝樓主,
回復

使用道具 舉報

7#
ID:476274 發表于 2020-2-16 20:32 | 只看該作者
不錯,學習下
回復

使用道具 舉報

8#
ID:891939 發表于 2021-4-1 00:23 | 只看該作者
請問  if((mask&byte)==0)   此語句怎么理解?mask沒初始化,它和參數byte按位與結果不都是0x00嗎?
回復

使用道具 舉報

9#
ID:24486 發表于 2024-3-13 20:56 | 只看該作者
xxx1949 發表于 2021-4-1 00:23
請問  if((mask&byte)==0)   此語句怎么理解?mask沒初始化,它和參數byte按位與結果不都是0x00嗎?

講解真詳細,謝謝樓主分享
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 黑人久久 | 成人在线免费视频观看 | 一级免费在线视频 | 九九热在线免费视频 | 欧美午夜精品久久久久免费视 | 午夜影院在线播放 | 黄色欧美视频 | 成人性生交大片免费看中文带字幕 | 精品久久久久久亚洲精品 | 成人在线网址 | 成人精品在线观看 | h片在线免费看 | 国产片侵犯亲女视频播放 | 婷婷丁香综合网 | 精品久久久久久久久久久久久久 | 日韩欧美福利视频 | 亚洲国产aⅴ成人精品无吗 国产精品永久在线观看 | 国产日韩一区二区 | 成人h视频 | 亚洲在线免费 | 人人爱干 | 日本精a在线观看 | 国产最好的av国产大片 | 午夜精品久久久久久久久久久久 | 国产 日韩 欧美 在线 | 综合久久国产 | 婷婷毛片 | 亚洲激情在线观看 | 精品视频一区二区 | 亚洲国产成人精品女人久久久 | 2023亚洲天堂 | 成人免费视频在线观看 | 久久久久久久久久久久久久国产 | 中文字幕在线观看一区 | 国产一级一级毛片 | 国产精品视频www | 精精国产xxxx视频在线播放 | 在线毛片网 | 亚洲欧美激情视频 | 欧美日韩成人影院 | 国产精品99久久久久久久久 |