在本文中,主要描述了IIC通信協議與讀寫24c02(EEPROM)的具體實例,並將P1口連接8個LED小燈,將從24c02裏面讀取出來的數據賦值給P1口,使小燈的亮滅情況根據讀取的數據發生相應的改變。
目錄
1. IIC簡介
2. IIC通信時序
3. EEPROM簡介
4. 程序實例
5. 仿真結果
IIC簡介
IIC(Inter-Integrated Circuit)總線是一種由PHILIPS公司開發的兩線式串行總線,用於連接微控制器及其外圍設備(特別是外部存儲器件)。
IIC 主要由兩條信號線線來完成通信過程:
SDA——數據線
SCL——時鐘線
一條IIC總線上能掛載多個IIC器件
當總線空閒時,兩根線均爲高電平。連到總線上的任一器件輸出的低電平,都將使總線的信號變低,即各器件的SDA及SCL都是線“與”關係。
每個接到IIC總線上的器件都有唯一地址,可避免接收混亂,不知道讀哪一個器件的情況。
IIC通信時序
空閒狀態:SCL線與SDA線均處於高電平狀態,等待起始信號
起始信號:SCL線爲高電平期間,SDA線由高電平向低電平的變化表示起始信號
終止信號:SCL線爲高電平期間,SDA線由低電平向高電平的變化表示終止信號
數據傳輸:IIC總線進行數據傳送時,時鐘信號爲高電平期間,數據線上的數據必須保持穩定,只有在時鐘線上的信號爲低電平期間,數據線上的高電平或低電平狀態才允許變化。
數據傳送格式:
每一個字節必須保證是8位長度。數據傳送時,先傳送最高位,每一個被傳送的字節後面都必須跟隨一位應答位(即一幀共有9位)。
應答位:返回0,表示成功應答。應答不成功,返回1。
IIC時序要求:
EEPROM簡介
EEPROM(Electrically Erasable Programmable Read Only Memory),電可擦除可編程只讀存儲器,是一種掉電之後數據不會丟失的存儲芯片。
EEPROM裏面用的芯片是24c0x系列芯片,它能夠存儲數據的大小爲:
24C01:128字節(128×8位)
24C02:256字節(256×8位)
24C04:512字節(512×8位)
24C08:1K字節(1K×8位)
24C16:2K字節(2K×8位)
原理圖
引腳說明
引腳 | 功能 |
---|---|
SCL | 時鐘線 |
SDA | 數據線 |
A0、A1、A2 | 可編程器件地址 |
WP | 寫保護 |
爲什麼說A0、A1、A2三位共同來構成24c0x的器件地址呢?
從數據手冊來看,高4位是1010,低4位是A0、A1、A2、R/W,傳7位有效地址,R/W決定讀還是寫。
如果將A0=A1=A2=0,那麼地址爲:0101 0000=0x50。
所以改變A0~A3的高低電平值,可以改變器件的地址。
讀寫操作:
寫:
- 發送起始信號
- 寫器件地址
- 應答
- 數據地址
- 應答
- 寫數據
- 應答
- 結束信號
讀:
- 起始信號
- 寫器件地址
- 應答
- 寫數據地址
- 應答
- 起始信號
- 寫數據地址加讀寫位
- 讀出數據
- 直接停止,沒有應答
程序實例
現在對着時序圖來寫IIC通信程序(仔細對應時序看程序)
#include <reg52.h>
#include <intrins.h>
sbit SCL = P2^0;
sbit SDA = P2^1;
void IIC_Delay() //前圖中大於4us或4.7us的延時
{
_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();
}
void IIC_Init() //將兩根線拉高,進入初始狀態,等待開始信號
{
SDA = 1;
SCL = 1;
}
void IIC_Start() //起始信號,SCL爲高時,SDA由高變低
{
SCL = 1;
SDA = 1;
IIC_Delay();
SDA = 0;
IIC_Delay();
SCL = 0;
IIC_Delay();
}
void IIC_Stop() //結束信號,SCL爲高時,SDA由低變高
{
SCL = 0;
SDA = 0;
IIC_Delay();
SCL = 1;
IIC_Delay();
SDA = 1;
IIC_Delay();
}
void IIC_ACK() //應答信號
{
unsigned char i=0;
SCL = 1; //SCL爲高時,接收應答
IIC_Delay();
while((SDA==1)&&(i<255)) //過了一段時間SDA仍爲高,就是非應答信號;否則,SDA=0,返回應答信號
i++;
SCL = 0; //應答後拉低時鐘線,等待結束信號
IIC_Delay();
}
void IIC_Write_Byte(unsigned char j) //寫一個字節,從高位到低位發送
{
unsigned char i,temp;
temp = j;
SCL = 0; //數據只在SCL爲低時允許改變
IIC_Delay();
for(i=0;i<8;i++)
{
temp <<= 1; //temp = temp << 1,從高到低依次移出
SDA = CY; //CY爲PSW狀態寄存器中的最高位,1000 0000<<1,CY=1;0000 0001>>1,CY=1.CY就是移出來的那一位
IIC_Delay();
SCL = 1; //等待SDA數據穩定
IIC_Delay();
SCL = 0; //等待下一次發送
IIC_Delay();
}
SDA = 1;
IIC_Delay();
}
unsigned char IIC_Read_Byte() //讀一個字節,從低位到高位讀
{
unsigned char i,j,k=0;
SCL = 0; //拉低時鐘線,等待數據變化
IIC_Delay();
for(i=0;i<8;i++)
{
SCL = 1; //在這個時刻已經獲取到了SDA的一位數據
IIC_Delay();
if(SDA == 1)
j = 1;
else
j = 0;
k = (k<<1) | j; //k依次往右移,最低位每次接受新的SDA 變化
SCL = 0; //等待下一次數據變化
}
return(k); //返回讀到的字節數據
}
void delay(unsigned int m) //做一個稍長一點的延時
{ unsigned int n;
for(n=0;n<m;n++);
}
void main()
{
int a; //將讀到的數據送給a,通過a給P1口
IIC_Init(); //IIC初始化
IIC_Start(); //IIC起始信號
IIC_Write_Byte(0xa0); //寫器件地址
IIC_ACK(); //應答
IIC_Write_Byte(0x00); //寫字節地址,24c02是256字節,不要超過最大地址
IIC_ACK();
IIC_Write_Byte(0x55); //寫數據
IIC_ACK();
IIC_Stop();
delay(2000);
IIC_Start();
IIC_Write_Byte(0xa0); //寫器件地址
IIC_ACK();
IIC_Write_Byte(0x00); //數據地址
IIC_ACK();
IIC_Start();
IIC_Write_Byte(0xa1); //7位地址位,加上最低位讀寫位,允許讀
IIC_ACK();
a = IIC_Read_Byte();
IIC_Stop();
P1 = ~a; //讓P1口的LED按寫入的數據亮
while(1);
}
最後,今天五四青年節,借魯迅先生的一段話與大家共勉。
願中國青年都擺脫冷氣,只是向上走,不必聽自暴自棄者流的話。能做事的做事,能發聲的發聲。有一分熱,發一分光。就令螢火一般,也可以在黑暗裏發一點光,不必等候炬火。 ——魯迅 《熱風·隨感錄四十一》
奔涌吧,後浪!