IIC模擬通信實例(基於51單片機)

在本文中,主要描述了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的高低電平值,可以改變器件的地址。
在這裏插入圖片描述
讀寫操作

  1. 發送起始信號
  2. 寫器件地址
  3. 應答
  4. 數據地址
  5. 應答
  6. 寫數據
  7. 應答
  8. 結束信號

在這裏插入圖片描述

  1. 起始信號
  2. 寫器件地址
  3. 應答
  4. 寫數據地址
  5. 應答
  6. 起始信號
  7. 寫數據地址加讀寫位
  8. 讀出數據
  9. 直接停止,沒有應答

在這裏插入圖片描述

程序實例

現在對着時序圖來寫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);
	
}


在這裏插入圖片描述
最後,今天五四青年節,借魯迅先生的一段話與大家共勉。

願中國青年都擺脫冷氣,只是向上走,不必聽自暴自棄者流的話。能做事的做事,能發聲的發聲。有一分熱,發一分光。就令螢火一般,也可以在黑暗裏發一點光,不必等候炬火。 ——魯迅 《熱風·隨感錄四十一》

奔涌吧,後浪!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章