Ⅰ 51單片機如何模擬I2C匯流排中從機接收ID,發送數據的程序
#include /*頭文件的包含*/
#include
#define uchar unsigned char /*宏定義*/
#define uint unsigned int
/*埠位定義*/
sbit BELL_OUT=P3^5;
sbit SCL="P1"^3;/*模擬I2C數據傳送位*/
sbit SDA="P1"^4;/*模擬I2C時鍾控制位*/
bit ack; /*應答標志位*/
/*********************************************************************
起動匯流排函數
函數原型: void Start_I2c();
功能:啟動I2C匯流排,即發送I2C起始條件
********************************************************************/
void Start_I2c()
{
SDA="1"; /*發送起始條件的數據信號*/
_nop_();
SCL="1"; /*起始條件建立時間大於4.7us,延時*/
_nop_();
SDA="0"; /*發送起始信號*/
_nop_(); /* 起始條件鎖定時間大於4μs*/
SCL="0"; /*鉗住I2C匯流排,准備發送或接收數據 */
_nop_();
}
/***********************************************
結束匯流排函數
函數原型: void Stop_I2c();
功能:結束I2C匯流排,即發送I2C結束條件
***********************************************/
void Stop_I2c()
{
SDA="0"; /*發送結束條件的數據信號*/
_nop_(); /*發送結束條件的時鍾信號*/
SCL="1"; /*結束條件建立時間大於4μs*/
_nop_();
SDA="1"; /*發送I2C匯流排結束信號*/
_nop_();
}
/*******************************************************************
位元組數據傳送函數
函數原型: void SendByte(uchar c);
功能:將數據c發送出去,可以是地址,也可以是數據,發完後等待應答,並對此狀
態位進行操作(不應答或非應答都使ack=0 假) 。發送數據正常,ack=1;
ack=0表示被控器無應答或損壞。
********************************************************************/
void SendByte(uchar c)
{
uchar BitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++) /*要傳送的數據長度為8位*/
{
SCL="0";
if((c<
else SDA="0";
SCL="1"; /*置時鍾線為高,通知被控器開始接收數據位*/
_nop_(); /*保證時鍾高電平周期大於4μs*/
}
//從機應答,可以用應答和非應答信號代替
_nop_();
SCL="0";
_nop_();
SDA="1"; //
_nop_();
SCL="1";
_nop_();
if(SDA==1){ack=0;} /*判斷是否接收到應答信號*/
else ack="1";
SCL="0";
_nop_();
}
/*******************************************************************
位元組數據傳送函數
函數原型: uchar RcvByte();
功能:用來接收從器件傳來的數據,並判斷匯流排錯誤(不發應答信號),
發完後請用應答函數。
********************************************************************/
uchar RcvByte()
{
uchar retc;
uchar BitCnt;
retc="0";
for(BitCnt=0;BitCnt<8;BitCnt++)
{
SCL="1"; /*置時鍾線為高使數據線上數據有效*/
_nop_();
retc="retc"<<1;
if(SDA==1) retc="retc"+1; /*讀數據位,接收的數據位放入retc中 */
SCL="0";
}
return(retc);
}
/********************************************************************
應答子函數
原型: void Ack_I2c();
功能:主控器進行應答信號
********************************************************************/
void Ack_I2c()
{
SDA="0"; /*在此發出應答信號 */
_nop_();
SCL="0";
_nop_();
SCL="1";
_nop_();
SCL="0"; /*清時鍾線,鉗住I2C匯流排以便繼續接收*/
_nop_();
SDA="1";
_nop_();
}
/********************************************************************
非應答子函數
原型: void NoAck_I2c();
功能:主控器進行非應答信號
********************************************************************/
void NoAck_I2c()
{
SDA="1"; /*在此發出非應答信號 */
_nop_();
SCL="1";
_nop_();
SCL="0"; /*清時鍾線,鉗住I2C匯流排以便繼續接收*/
}
/*******************************************************************
向無子地址器件發送位元組數據函數
函數原型: bit ISendByte(uchar sla,ucahr c);
功能:從啟動匯流排到發送地址,數據,結束匯流排的全過程,從器件地址sla。如果
返回1表示操作成功,否則操作有誤。
********************************************************************/
bit ISendByte(uchar sla,uchar c)
{
Start_I2c(); /*啟動匯流排*/
SendByte(sla); /*發送器件地址*/
if(ack==0)return(0);
SendByte(c); /*發送數據*/
if(ack==0)return(0);
Stop_I2c(); /*結束匯流排*/
return(1);
}
/*******************************************************************
向有子地址器件發送多位元組數據函數
函數原型: bit ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);
功能:從啟動匯流排到發送地址,子地址,數據,結束匯流排的全過程,從器件地址sla,
子地址suba,發送內容是s指向的內容,發送no個位元組。如果返回1表示
操作成功,否則操作有誤。
********************************************************************/
bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no)
{
uchar i;
Start_I2c(); /*啟動匯流排*/
SendByte(sla); /*發送器件地址*/
if(ack==0)return(0);
SendByte(suba); /*發送器件子地址*/
if(ack==0)return(0);
for(i=0;i
{
SendByte(*s); /*發送數據*/
if(ack==0)return(0);
s++;
}
Stop_I2c(); /*結束匯流排*/
//delayMs(1); //
return(1);
}
/*******************************************************************
向無子地址器件讀位元組數據函數
函數原型: bit IRcvByte(uchar sla,ucahr *c);
功能:從啟動匯流排到發送地址,讀數據,結束匯流排的全過程,從器件地址sla,返
回值在c。如果返回1表示操作成功,否則操作有誤。
********************************************************************/
bit IRcvByte(uchar sla,uchar *c)
{
Start_I2c(); /*啟動匯流排*/
SendByte(sla+1); /*發送器件地址*/
if(ack==0)return(0);
*c=RcvByte(); /*讀取數據*/
NoAck_I2c(); /*發送非就答位*/
Stop_I2c(); /*結束匯流排*/
return(1);
}
/**********************************************************************
向有子地址器件讀取多位元組數據函數
函數原型: bit ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);
功能:從啟動匯流排到發送地址,子地址,讀數據,結束匯流排的全過程,從器件地址sla,
子地址suba,讀出的內容放入s指向的存儲區,讀no個位元組。如果返回1
表示操作成功,否則操作有誤。
**********************************************************************/
bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no)
{
Start_I2c(); /*啟動匯流排*/
SendByte(sla); /*發送器件地址*/
if(ack==0)return(0);
SendByte(suba); /*發送器件子地址*/
if(ack==0)return(0);
Start_I2c();
SendByte(sla+1);
if(ack==0)return(0);
while(no!=1)
{
*s=RcvByte();/*發送數據*/
Ack_I2c(); /*發送就答位*/
s++;
no--;
}
*s=RcvByte();
NoAck_I2c(); /*發送非應位*/
Stop_I2c(); /*結束匯流排*/
return(1);
}
Ⅱ 求:51單片機模擬i2c匯流排程序
//給你一個簡單的可斷電保存的計時程序,用的是24C08
#include <reg52.h> // 包含51單片機寄存器定義的頭文件
#include <intrins.h> //包含_nop_()函數定義的頭文件
#define OP_READ 0xa1 // 器件地址以及讀取操作,0xa1即為1010 0001B
#define OP_WRITE 0xa0 // 器件地址以及寫入操作,0xa1即為1010 0000B
sbit SCL=P3^4; //將串列時鍾匯流排SCL位定義在為P3.4引腳
sbit SDA=P3^5; //將串列數據匯流排SDA位定義在為P3.5引腳
unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//定義共陽數碼管顯示字型碼
unsigned char sec=0; //定義計數值,每過1秒,sec加1
unsigned int count; //定時中斷次數
bit write=0; //寫24C08的標志;
sbit shiwei=P2^6; //十位選通定義
sbit gewei=P2^7; //個位選通定義
sbit K5=P3^2; //清0按鍵
/*****************************************************
函數功能:延時1ms
***************************************************/
void delay1ms()
{
unsigned char i,j;
for(i=0;i<10;i++)
for(j=0;j<33;j++)
;
}
/*****************************************************
函數功能:延時若干毫秒
入口參數:n
***************************************************/
void delaynms(unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++)
delay1ms();
}
/***************************************************
函數功能:開始數據傳送
***************************************************/
void start()
// 開始位
{
SDA = 1; //SDA初始化為高電平「1」
SCL = 1; //開始數據傳送時,要求SCL為高電平「1」
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
SDA = 0; //SDA的下降沿被認為是開始信號
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
SCL = 0; //SCL為低電平時,SDA上數據才允許變化(即允許以後的數據傳遞)
}
/***************************************************
函數功能:結束數據傳送
***************************************************/
void stop()// 停止位
{
SDA = 0; //SDA初始化為低電平「0」 _n
SCL = 1; //結束數據傳送時,要求SCL為高電平「1」
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
SDA = 1; //SDA的上升沿被認為是結束信號
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
SDA=0;
SCL=0;
}
/***************************************************
函數功能:檢測應答位
***************************************************/
bit Ask() //檢測應答
{
bit ack_bit; //儲存應答位
SDA = 1; // 發送設備(主機)應在時鍾脈沖的高電平期間(SCL=1)釋放SDA線,
//以讓SDA線轉由接收設備(AT24Cxx)控制
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
SCL = 1; //根據上述規定,SCL應為高電平
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
ack_bit = SDA; //接受設備(AT24Cxx)向SDA送低電平,表示已經接收到一個位元組
//若送高電平,表示沒有接收到,傳送異常 結束發送
SCL = 0; //SCL為低電平時,SDA上數據才允許變化(即允許以後的數據傳遞)
return ack_bit; // 返回AT24Cxx應答位
}
/***************************************************
函數功能:從AT24Cxx讀取數據
出口參數:x
***************************************************/
unsigned char ReadData()
// 從AT24Cxx移入數據到MCU
{
unsigned char i;
unsigned char x; //儲存從AT24Cxx中讀出的數據
for(i = 0; i < 8; i++)
{
SCL = 1; //SCL置為高電平
x<<=1; //將x中的各二進位向左移一位
x|=(unsigned char)SDA; //將SDA上的數據通過按位「或「運算存入x中
SCL = 0; //在SCL的下降沿讀出數據
}
return(x); //將讀取的數據返回
}
/***************************************************
函數功能:向AT24Cxx的當前地址寫入數據
入口參數:y (儲存待寫入的數據)
***************************************************/
//在調用此數據寫入函數前需首先調用開始函數start(),所以SCL=0
void WriteCurrent(unsigned char y)
{
unsigned char i;
for(i = 0; i < 8; i++) // 循環移入8個位
{
SDA = (bit)(y&0x80); //通過按位「與」運算將最高位數據送到S
//因為傳送時高位在前,低位在後
_nop_(); //等待一個機器周期
SCL = 1; //在SCL的上升沿將數據寫入AT24Cxx
_nop_(); //等待一個機器周期
_nop_(); //等待一個機器周期
SCL = 0; //將SCL重新置為低電平,以在SCL線形成傳送數據所需的8個脈沖
y <<= 1; //將y中的各二進位向左移一位
}
}
/***************************************************
函數功能:向AT24Cxx中的指定地址寫入數據
入口參數:add (儲存指定的地址);dat(儲存待寫入的數據)
***************************************************/
void WriteSet(unsigned char add, unsigned char dat)
// 在指定地址addr處寫入數據WriteCurrent
{
start(); //開始數據傳遞
WriteCurrent(OP_WRITE); //選擇要操作的AT24Cxx晶元,並告知要對其寫入數據
Ask();
WriteCurrent(add); //寫入指定地址
Ask();
WriteCurrent(dat); //向當前地址(上面指定的地址)寫入數據
Ask();
stop(); //停止數據傳遞
delaynms(4); //1個位元組的寫入周期為1ms, 最好延時1ms以上
}
/***************************************************
函數功能:從AT24Cxx中的當前地址讀取數據
出口參數:x (儲存讀出的數據)
***************************************************/
unsigned char ReadCurrent()
{
unsigned char x;
start(); //開始數據傳遞
WriteCurrent(OP_READ); //選擇要操作的AT24Cxx晶元,並告知要讀其數據
Ask();
x=ReadData(); //將讀取的數據存入x
stop(); //停止數據傳遞
return x; //返回讀取的數據
}
/***************************************************
函數功能:從AT24Cxx中的指定地址讀取數據
入口參數:set_addr
出口參數:x
***************************************************/
unsigned char ReadSet(unsigned char set_addr)
// 在指定地址讀取
{
start(); //開始數據傳遞
WriteCurrent(OP_WRITE); //選擇要操作的AT24Cxx晶元,並告知要對其寫入數據
Ask();
WriteCurrent(set_addr); //寫入指定地址
Ask();
return(ReadCurrent()); //從指定地址讀出數據並返回
}
/***********************************************************/
void LEDshow() //LED顯示函數
{
P0=table[sec/10];
shiwei=0;
delaynms(2);
shiwei=1;
P0=table[sec%10];
gewei=0;
delaynms(2);
gewei=1;
}
/***********************************************************/
/***************************************************
函數功能:主函數
***************************************************/
void main(void)
{
TMOD=0x01; //定時器0工作在方式1
ET0=1;
EA=1;
TH0=(65536-50000)/256; //對TH0 TL0賦值
TL0=(65536-50000)%256; //使定時器0.05秒中斷一次
SDA = 1; // SDA=1,SCL=1,使主從設備處於空閑狀態
SCL = 1;
sec=ReadSet(2);//讀出保存的數據賦於sec
TR0=1; //開始計時
while(1)
{
LEDshow();
if(write==1) //判斷計時器是否計時一秒
{
write=0; //清零
WriteSet(2,sec); //在24c08的地址2中寫入數據sec
}
if(K5==0){
delaynms(10);
if(K5==0){
sec=0;
}
}
}
}
/**************************************************************/
void t0(void) interrupt 1 using 0 //定時中斷服務函數
{
TH0=(65536-50000)/256; //對TH0 TL0賦值
TL0=(65536-50000)%256; //重裝計數初值
count++; //每過50ms tcnt加一
if(count==20) //計滿20次(1秒)時
{
count=0; //重新再計
sec++;
write=1; //1秒寫一次24C08
if(sec==100) //定時100秒,在從零開始計時
{sec=0;}
}
}
Ⅲ 51單片機模擬IIC匯流排問題
IIC的地址你可以自己定義的
在硬體上提供過IIC地址的你可以直接選擇他的地址進行發送
像你這種情況的話可以自己定義地址:
假設你有兩台或者以上的S3C2410,單片機作為主機,然後單片機發送數據,所有S3C接收(接收的前提是他的接收埠上獲得IIC的開始信號,你可以選擇利用中斷進行檢測),然後你在軟體里可以預先設置好每台S3C的地址,即接收單片機的前8BIT,然後對照地址,一樣的話就開始接收接下來的信息,沒有就放棄這個通信,這樣的話8BIT就可以控制256台S3C了
其實IIC也只是一種通信方式,你可以選擇自己的協議,以IIC為基礎,比如地址位選擇16BIT甚至更多,如果從機是S3C這種32位的RAM9的話,數據位的傳輸可以32位的傳。所謂的開始信號跟終止信號也只是雙方默認的方式而已,就像是「點頭YES,搖頭NO」,你也可以選擇相反的方式,只要兩台通信的機子能懂就好。
不過最好是採用大家一起的,這樣在軟體移植的時候會有幫助,也方便別人看懂。當大家在某一領域都用一種方式的時候也就形成所謂的協議,比如TCP/IP,UART,IIC等等。
Ⅳ 51單片機如何模擬I2C匯流排中從機接收ID,發送數據的程序
希望能給你解答:
1、時鍾信號都是主機產生的,從機只有一種情況下才能控制時鍾線,即在忙的時候,主機還在發送數據,從機會主動把時鍾拉低,表示我正在忙,不能收數據。
2、兩個主機的話,在發送的時候一定會有一個從屬關系,這個需要自己設置。
3、響應:i2c上每傳輸一個位元組,都必須要有響應,方向是從機到主機。