如有錯誤希望各位大佬批評指正,郵件請發:[email protected] ...
————————————————————————————————————————————
參考地址:
http://blog.csdn.net/junyeer/article/details/46480863
http://blog.csdn.net/bob_fly1984/article/details/22690381
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
硬體結構:
- SDA數據線
- SCL時間線
-
上拉電阻
p.s. 當匯流排空閑狀態時,兩根線被上拉電阻拉高,保持高電平。連接匯流排上的任一器件輸出的低電平都將使匯流排的信號變低
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
匯流排特征:
- I2C匯流排上的每一個設備都可以作為主設備或從設備
-
每個設備會對應一個唯一的地址,主從設備之間通過地址來確定與哪個器件通信
p.s. 地址分為7位或10位,此處只介紹7位
- 通常情況下,把CPU帶有I2C匯流排介面的模塊作為主設備,其他掛在匯流排上的作為從設備
- 主從設備之間以位元組為單位進行雙向數據傳輸
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
工作方式:
-
主從工作方式:主器件啟動數據的發送,產生時鐘信號,發出停止信號
p.s. 是沒有I2C匯流排硬體介面的單片機採用軟體模擬I2C匯流排常用的工作方式
- 多主工作方式:需要匯流排競爭或仲裁
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
通信時序(主從工作方式):
-
空閑狀態:
- SCL和SDA保持高電平狀態
-
忙狀態:
p.s. SDA線必須在SCL時鐘的高電平周期才能保持穩定,SDA數據線的高或低電平狀態只能在SCL低電平時才能改變
-
起始條件 S:
- SCL為高電平,SDA下降沿1→0時,主器件產生起始信號
- 起始信號產生後,匯流排處於忙狀態,其他I2C器件無法訪問匯流排
-
停止條件 P:
-
SCL為高電平,SDA上升沿0→1時,主器件產生停止信號
p.s. 非應答信號規定:當主機為接收設備,主機對最後一個位元組不應答,以向發送設備表示數據傳送結束
- 停止條件產生後,主從設備釋放匯流排,匯流排再次處於空閑狀態
-
SCL為高電平,SDA上升沿0→1時,主器件產生停止信號
-
傳輸過程:
-
主設備在傳輸有效數據之前先指定從設備的地址,設備地址為7位時,再加一個最低位表示數據傳輸的方向,0表示主設備→從設備寫數據,1表示主設備讀數據。
7位地址碼:其中DA3~DA0(硬體出廠時固有的地址編碼)及A2~A0(用戶設定)為從機地址
- 主設備在SCL線上產生每個時鐘脈衝的過程中將在SDA線上傳輸一個bit
-
當一個位元組按數據位從高到低順序傳輸完之後,接收設備將SDA拉為低電平,表示數據傳輸正確,回傳給主設備一個應答位。一個位元組傳輸完畢。
p.s. 並不是所有的位元組傳輸都必須有一個應答位,比如:當從設備不能再接收主設備發送的數據時,從設備回傳一個非應答位
在一次傳輸中可以傳輸多個位元組,圖中只畫出首位元組
-
主設備在傳輸有效數據之前先指定從設備的地址,設備地址為7位時,再加一個最低位表示數據傳輸的方向,0表示主設備→從設備寫數據,1表示主設備讀數據。
-
起始條件 S:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
當主機向從機發送1位元組數據時
p.s. 實際上主從機的SDA信號是在同一根線上的,分開畫有助於理解各自的行為
- 當主機從從機接收1位元組數據時
————————————————————————————————————————————
AT24C02
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
主要型號:
ATMEL公司生產的AT24C系列EEPROM中具有I2C匯流排介面。
這類晶元可以解決掉電而造成的數據丟失的問題,可以保存數據100年,擦寫100w次以上。
晶元地址固定部分為1010
型號 |
存儲容量 |
AT24C01 |
128*8 |
AT24C02 |
256*8 |
AT24C04 |
512*8 |
AT24C08 |
1024*4 |
AT24C16 |
2048*8 |
晶元特性:略
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
引腳描述:
- A0/A1/A2是3條地址線,用於確定晶元的硬體地址,在上圖系統中均接地,選擇000
- 第4腳和第8腳為正負電源
- 第5腳為SDA串列數據輸入/輸出,與單片機P3.5相連
- 第6腳為SCL串列時鐘輸入線,與單片機P3.6相連
- SDA和SCL都需要與正電源間接一個5.1k歐上拉電阻
- 第7腳防寫功能接地
- 24C02中帶有片內地址寄存器,每寫入或讀出一個數據位元組後,該地址寄存器自動+1,實現對下一個存儲單元的讀寫。為降低總的寫入時間,一次操作可以寫入多達8個位元組的數據。
————————————————————————————————————————————
AT24C02應用實例
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
設計要求:
- 採用定時中斷方式,設計一個0~59s變化的秒錶,將每次顯示在數位管上的時間存入AT24C02中
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
設計思路:
- 通過定時器50ms觸發中斷,每次觸發中斷時中斷計數,到達1s時flag標識為1
- 在死迴圈中始終顯示當前秒數
- 每次秒數變化時寫入flag清零並寫入AT24C02中
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
硬體清單及連線情況:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
實現代碼:
1 #include <reg51.h> 2 typedef unsigned char uchar; 3 typedef unsigned int uint; 4 sbit scl = P3 ^ 0; 5 sbit sda = P3 ^ 1; 6 uchar second = 0; 7 uchar count = 0; 8 bit flag = 0; 9 uchar code table[] = 10 { 11 0xFC, 0x60, 0xDA, 0xF2, 0x66, 0xB6, 0xBE, 0xE0, 0xFE, 0xF6, 0xEE, 0x3E, 0x9C, 0x7A, 0x9E, 0x8E 12 }; 13 void Init(); //初始化匯流排 14 void Start(); //開始 15 void Stop(); //停止 16 void Respons(); //響應位 17 uchar ReadByte(); //讀數據 18 uchar ReadAddress(uchar address); //讀地址 19 void WriteByte(uchar dat); //寫位元組 20 void WriteAddress(uchar address, uchar dat); //寫地址 21 void Display(); //顯示數位管 22 void Delay1ms(uchar m); //延時1ms 23 void Delay(); //延時2個機器周期 24 void main() 25 { 26 /* 初始化匯流排 */ 27 Init(); 28 /* 初始化LED */ 29 P1 = 0xff; 30 /* 設置定時器 */ 31 TMOD = 0x01; 32 TH0 = (65536 - 50000) / 256; 33 TL0 = (65536 - 50000) % 256; 34 /* 中斷初始化 */ 35 EA = 1; 36 ET0 = 1; 37 /* 定時器開始 */ 38 TR0 = 1; 39 /* 顯示數位管並寫入 */ 40 while(1) 41 { 42 if (flag == 1) 43 { 44 flag = 0; 45 WriteAddress(2, second); 46 } 47 Display(); 48 } 49 50 } 51 void Init() 52 { 53 //空間狀態時SCL與SDA均保持高電平 54 sda = 1; 55 Delay(); 56 scl = 1; 57 Delay(); 58 } 59 void Start() 60 { 61 //SCL高電平情況下,SDA下降沿啟動 62 sda = 1; 63 Delay(); 64 scl = 1; 65 Delay(); 66 sda = 0; 67 Delay(); 68 } 69 void Stop() 70 { 71 //SCL高電平情況下,SDA上升沿停止 72 sda = 0; 73 Delay(); 74 scl = 1; 75 Delay(); 76 sda = 1; 77 Delay(); 78 } 79 void Respons() 80 { 81 //在SCL位為高電平時產生響應信號,數據傳輸正確時產生應答且SDA拉低 82 uchar i; 83 scl = 1; //此處scl拉高後在while迴圈中降低,參照時序圖 84 Delay(); 85 while ((sda == 1) && (i < 255)) 86 { 87 //SDA拉低時跳出迴圈,表示數據傳輸正確,產生應答.如果在一段時間內未收到應答,則不再等待跳出迴圈 88 i++; 89 scl = 0; 90 Delay(); 91 } 92 } 93 void WriteAddress(uchar address, uchar dat) 94 { 95 Start(); //開始 96 WriteByte(0xA0); //寫入 1010 0000 高4位為固定值,5-7位為A0 A1 A2,最低位0為寫操作標識 97 Respons(); 98 WriteByte(address); //寫入 0000 0010 99 Respons(); 100 WriteByte(dat); //寫入數據(秒數) 101 Respons(); 102 Stop(); //停止 103 } 104 void WriteByte(uchar dat) 105 { 106 uchar i, temp; 107 temp = dat; //將dat讀入temp 108 for (i = 0; i < 8; ++i) 109 { 110 temp = temp << 1; //temp左移,最高位移入CY 111 scl = 0; //SCL複位,等待最高位存入SDA後置位 112 Delay(); 113 sda = CY; //CY在頭文件中已規定,通過SDA發送bit 114 Delay(); 115 scl = 1; //SCL置位,延遲2個機器周期後複位 116 Delay(); 117 } 118 scl = 0; //為最後一個SCL高電平複位 119 Delay(); 120 sda = 1; //一個位元組數據發送完畢後置位準備響應 121 Delay(); 122 } 123 uchar ReadAddress(uchar address) 124 { 125 uchar byte; 126 Start(); 127 WriteByte(0xA0); 128 Respons(); 129 WriteByte(address); 130 Respons(); 131 Start(); 132 WriteByte(0xA1); //寫入地址 1010 0001,讀寫標誌位1為讀 133 Respons(); 134 byte = ReadByte(); 135 Stop(); 136 return byte; 137 } 138 uchar ReadByte() 139 { 140 uchar i, k; 141 scl = 0; 142 Delay(); 143 sda = 1; 144 Delay(); 145 for (i = 0; i < 8; ++i) 146 { 147 scl = 1; 148 Delay(); 149 k = (k << 1) | sda; 150 scl = 0; 151 Delay(); 152 } 153 return k; 154 } 155 void Display() 156 { 157 P2 = 0xfe; 158 P1 = table[second % 10]; 159 Delay1ms(1); 160 P2 = 0xfd; 161 // P1 = table[second / 10 %10]; 162 P1 = table[second / 10]; 163 Delay1ms(1); 164 // P2 = 0xfb; 165 // P1 = table[second / 100]; 166 // Delay1ms(5); 167 } 168 void Delay() 169 { 170 ;; 171 } 172 void Delay1ms(uchar m) //使用1ms時二極體閃爍,此處將y=110改成y=50 173 { 174 uchar x, y; 175 for (x = m; x > 0; ++x) 176 for (y = 50; y > 0; --y) 177 ; 178 } 179 void time()interrupt 1 180 { 181 TH0 = (65536 - 50000) / 256; 182 TL0 = (65536 - 50000) % 256; 183 count++; 184 if (count == 20) 185 { 186 count = 0; 187 flag = 1; 188 second++; 189 if (second == 60) 190 second = 0; 191 } 192 }