標(biāo)準(zhǔn)AVR單片機(jī)模擬I2C總線的主機(jī)程序
.H文件預(yù)處理
typedef unsignedcharINT8U;//0~255
typedef signedcharINT8S;//-128~127
typedef unsigned int INT16U;//0~65535
typedef signed int INT16S;//-32768~32767
typedef unsigned long INT32U;//0~0xFFFFFFFF
typedef signed long INT32S;//0x8000 0000~7FFFFFFF
typedef float FP32;//Single precision floating point
typedef double FP64; //Double precision floating point
#defineXTAL 1//晶振頻率,單位MHz
#definem_delayus(x)__delay_cycles((unsigned long)(x*XTAL))
#definem_delayms(x)__delay_cycles((unsigned long)(x*XTAL*1000UL))
#definem_delays(x)__delay_cycles((unsigned long)(x*XTAL*1000000UL))
#defineBIT0 0x01
#defineBIT1 0x02
#defineBIT2 0x04
#defineBIT3 0x08
#defineBIT4 0x10
#defineBIT5 0x20
#defineBIT6 0x40
#defineBIT7 0x80
//假設(shè)SCL是端口PD6,SDA是端口PD7,WP是端口PD5
#definem_EnE2pWrite PORTD&=~BIT5 //允許EEPROM讀寫
#definem_DiE2pWrite PORTD|=BIT5 //EEPROM只讀
#definem_I2CWritePort DDRD|=BIT7//I2C寫時(shí),SDA端口方向?yàn)檩敵?/p>
#definem_I2CReadPort DDRD&=~BIT7//I2C讀時(shí),SDA端口方向?yàn)檩斎?/p>
#definem_SetSCLPORTD|=BIT6 //PD6=1,SCL置位
#definem_ClrSCLPORTD&=~BIT6 //PD6=0,SCL清0
#definem_SetSDA PORTD|=BIT7 //PD7=1,SDA置位
#definem_ClrSDA PORTD&=~BIT7//PD7=0,SDA清0
#definem_SDAIn (PIND&BIT7) //SDA讀入
#definem_I2C_Delaym_delayus(5)//I2C延時(shí),不同器件可能不同
#definem_I2C_StopDelay m_delayms(10)//在下一次產(chǎn)生Start之前,總線空閑時(shí)間
void I2C_Start();//產(chǎn)生I2C總線的起始狀態(tài)
void I2C_Write(INT8U dat);//向I2C總線寫1個(gè)字節(jié)的數(shù)據(jù)
INT8U I2C_Read();//從從機(jī)讀取1個(gè)字節(jié)的數(shù)據(jù)
INT8U I2C_GetAck();//讀取從機(jī)應(yīng)答位
void I2C_PutAck(INT8U ack);//主機(jī)產(chǎn)生應(yīng)答位或非應(yīng)答位
void I2C_Stop();//產(chǎn)生I2C總線的停止?fàn)顟B(tài)
INT8U I2C_Puts(INT8U SlaveAddr,INT16U SubAddr,INT8U SubMod,INT8U *dat,INT16U Size);//I2C總線綜合發(fā)送函數(shù),向從機(jī)發(fā)送多個(gè)字節(jié)的數(shù)據(jù)
INT8U I2C_Gets(INT8U SlaveAddr,INT16U SubAddr,INT8U SubMod,INT8U *dat,INT16U Size);//I2C總線綜合接收函數(shù),從從機(jī)接收多個(gè)字節(jié)的數(shù)據(jù)
INT8U I2C_DigitalPot(INT8U SlaveAddr,INT8U dat);//I2C總線數(shù)字電位器發(fā)送程序
.C文件
void I2C_Start()
{
m_I2CWritePort;//端口方向?yàn)檩敵?/p>
m_SetSDA;
m_I2C_Delay;
m_SetSCL;
m_I2C_Delay;
m_ClrSDA;
m_I2C_Delay;
m_ClrSCL;
m_I2C_Delay;
}
void I2C_Write(INT8Udat)
{
m_I2CWritePort;//端口方向?yàn)檩敵?/p>
for(INT8U t=0;t<8;t++)
{
if ((dat&0x80)!=0)
{
m_SetSDA; //SDA=1
}
else
{
m_ClrSDA; //SDA=0
}
m_I2C_Delay;
dat<<=1;
m_SetSCL; //SCK=1
m_I2C_Delay;
m_ClrSCL; //SCK=0
m_I2C_Delay;
}
}
INT8UI2C_Read()
{
INT8U dat;
m_I2CReadPort;//端口方向?yàn)檩斎?/p>
for(INT8U t=0;t<8;t++)
{
m_SetSCL;//SCK=1
dat<<=1;
if(m_SDAIn)
{
dat|=0x01;
}
m_ClrSCL;//SCK=0
m_I2C_Delay;
}
return dat;
}
INT8UI2C_GetAck()
{
INT8Uack=0;
m_I2CReadPort;//端口方向?yàn)檩斎?/p>
//總線準(zhǔn)備,接受應(yīng)答
m_SetSDA;
m_I2C_Delay;
m_SetSCL;
m_I2C_Delay;
if(m_SDAIn!=0)
ack =1;
m_ClrSCL;
m_I2C_Delay;
return ack;
}
/******************************************************************************
函數(shù):I2C_PutAck()
功能:主機(jī)產(chǎn)生應(yīng)答位或非應(yīng)答位
參數(shù):
ack=0:主機(jī)產(chǎn)生應(yīng)答位;ack=1:主機(jī)產(chǎn)生非應(yīng)答位
說明:
主機(jī)在接收完每一個(gè)字節(jié)的數(shù)據(jù)后,都應(yīng)當(dāng)產(chǎn)生應(yīng)答位
主機(jī)在接收完最后一個(gè)字節(jié)的數(shù)據(jù)后,應(yīng)當(dāng)產(chǎn)生非應(yīng)答位
******************************************************************************/
void I2C_PutAck(INT8Uack)
{
m_I2CWritePort;//端口方向?yàn)檩敵?/p>
if(ack==0)
{
m_ClrSDA;
}
else
{
m_SetSDA;
}
m_I2C_Delay;
m_SetSCL;
m_I2C_Delay;
m_ClrSCL;
m_I2C_Delay;
m_SetSDA;
}
/******************************************************************************
函數(shù):I2C_Stop()
功能:產(chǎn)生I2C總線的停止?fàn)顟B(tài)
說明:
SCL處于高電平期間,當(dāng)SDA出現(xiàn)上升沿時(shí)停止I2C總線
不論SDA和SCL處于什么電平狀態(tài),本函數(shù)總能正確產(chǎn)生停止?fàn)顟B(tài)
本函數(shù)執(zhí)行后,I2C總線處于空閑狀態(tài)
******************************************************************************/
void I2C_Stop()
{
m_I2CWritePort;//端口方向?yàn)檩敵?/p>
m_ClrSDA;
m_I2C_Delay;
m_SetSCL;
m_I2C_Delay;
m_SetSDA;
m_I2C_StopDelay;
}
/******************************************************************************
函數(shù):I2C_Puts()
功能:I2C總線綜合發(fā)送函數(shù),向從機(jī)發(fā)送多個(gè)字節(jié)的數(shù)據(jù)
參數(shù):
SlaveAddr:從機(jī)地址(7位純地址,不含讀寫位,0xxx xxxx)
SubAddr:從機(jī)的子地址
SubMod:子地址模式,0-無子地址,1-單字節(jié)子地址,2-雙字節(jié)子地址
*dat:要發(fā)送的數(shù)據(jù)
Size:數(shù)據(jù)的字節(jié)數(shù)
返回:
0:發(fā)送成功
1:在發(fā)送過程中出現(xiàn)異常
說明:
本函數(shù)能夠很好地適應(yīng)所有常見的I2C器件,不論其是否有子地址
當(dāng)從機(jī)沒有子地址時(shí),參數(shù)SubAddr任意,而SubMod應(yīng)當(dāng)為0
******************************************************************************/
INT8UI2C_Puts(INT8USlaveAddr,INT16USubAddr,INT8USubMod,INT8U*dat,INT16USize)
{
m_EnE2pWrite; //允許EEPROM讀寫
INT8Ua[3];
if (Size==0) return1;//檢查長(zhǎng)度,在接收過程中出現(xiàn)異常
a[0]=(SlaveAddr<<1);//準(zhǔn)備從機(jī)地址
if (SubMod>2) SubMod = 2;//檢查子地址模式
//確定子地址
switch (SubMod)
{
case 0:
break;
case 1:
a[1]=(INT8U)(SubAddr);
break;
case 2:
a[1]=(INT8U)(SubAddr >> 8);
a[2]=(INT8U)(SubAddr);
break;
default:
break;
}
//主機(jī)發(fā)送從機(jī)地址(a[0]),接著發(fā)送子地址(如果有子地址的話)(a[1],a[2])
I2C_Start();
for (INT8Ut=0;t<=SubMod;t++)
{
I2C_Write(a[t]);
if (I2C_GetAck())
{
I2C_Stop();
m_DiE2pWrite;//EEPROM只讀
return 1;
}
}
//主機(jī)發(fā)送數(shù)據(jù)
while(Size--)
{
I2C_Write(*dat++);
if (I2C_GetAck())
{
I2C_Stop();
m_DiE2pWrite;//EEPROM只讀
return 1;
}
}
//發(fā)送完畢,停止I2C總線,并返回結(jié)果
I2C_Stop();
m_DiE2pWrite;//EEPROM只讀
return 0;//發(fā)送成功
}
/******************************************************************************
函數(shù):I2C_Gets()
功能:I2C總線綜合接收函數(shù),從從機(jī)接收多個(gè)字節(jié)的數(shù)據(jù)
參數(shù):
SlaveAddr:從機(jī)地址(7位純地址,不含讀寫位,0xxx xxxx)
SubAddr:從機(jī)的子地址
SubMod:子地址模式,0-無子地址,1-單字節(jié)子地址,2-雙字節(jié)子地址
*dat:保存接收到的數(shù)據(jù)
Size:數(shù)據(jù)的字節(jié)數(shù)
返回:
0:接收成功
1:在接收過程中出現(xiàn)異常
說明:
本函數(shù)能夠很好地適應(yīng)所有常見的I2C器件,不論其是否有子地址
當(dāng)從機(jī)沒有子地址時(shí),參數(shù)SubAddr任意,而SubMod應(yīng)當(dāng)為0
******************************************************************************/
INT8UI2C_Gets(INT8USlaveAddr,INT16USubAddr,INT8USubMod,INT8U*dat,INT16USize)
{
m_EnE2pWrite; //允許EEPROM讀寫
INT8Ua[3];
if(Size=