用I/O口模擬總線時(shí)序
我們平時(shí)計(jì)算機(jī)常用的RS232/485工作在異步工作狀態(tài)時(shí)是有嚴(yán)格的數(shù)據(jù)時(shí)鐘限制,也就是我們所說的波特率,通信的兩個(gè)設(shè)備有相同的波特率才能正確的通信。對于同步通信一般沒有嚴(yán)格的時(shí)間限制,總線通過高低電平來分辨數(shù)據(jù)是"0"還是"1",有兩個(gè)關(guān)鍵的時(shí)刻:上升沿,下降沿。它 是用過上升沿和下降沿的時(shí)刻來讀寫數(shù)據(jù)的,也就是說這樣的話通信頻率不是固定的,因?yàn)橥ㄐ诺脑O(shè)備"數(shù)"的是上升沿和下降沿的數(shù)目,然后讀寫數(shù)據(jù)線上的數(shù) 據(jù)。筆者做過實(shí)驗(yàn),將I2C通信的頻率降到了10Hz左右,這樣用示波器能夠很好的捕捉到每一個(gè)時(shí)鐘,通信的結(jié)果也是正確的。
本文引用地址:http://m.butianyuan.cn/article/201611/315354.htm好了,直接來看案例吧。
通常我們的I2C的通信時(shí)序應(yīng)該如下圖所示,在時(shí)鐘線拉高的情況下,將數(shù)據(jù)線拉低就會(huì)產(chǎn)生一個(gè)啟動(dòng)信號(hào)。但是傳感器SHT的啟動(dòng)信號(hào)卻是一個(gè)數(shù)據(jù)線拉低后,時(shí)鐘線產(chǎn)生一個(gè)脈沖,而后再將數(shù)據(jù)線拉高,這樣做的好處是在一定程度上確保了總線正確的啟動(dòng),但是幾乎與之匹配的MCU。這個(gè)時(shí)候就需要通過I/O模擬的方式來與SHT11完成通信。
#define IIC_SCL RC0 //I2C時(shí)鐘線
#define IIC_SDA RC1 //I2C數(shù)據(jù)線
#define IIC_SCL_DIR TRISC0 //I2C時(shí)鐘線傳輸方向
#define IIC_SDA_DIR TRISC1 //I2C數(shù)據(jù)線傳輸方向
#define PORT_INPUT 1
#define PORT_OUTPUT 0
#define IIC_SCL_HIGH() IIC_SCL_DIR = PORT_INPUT //時(shí)鐘線拉高
#define IIC_SCL_LOW() IIC_SCL_DIR = PORT_OUTPUT;IIC_SCL=0//時(shí)鐘線拉低
#define IIC_SDA_HIGH() IIC_SDA_DIR = PORT_INPUT //數(shù)據(jù)線拉高
#define IIC_SDA_LOW() IIC_SDA_DIR = PORT_OUTPUT;IIC_SDA=0//數(shù)據(jù)線拉低
/***************
*SHT11啟動(dòng)時(shí)序
***************/
void SHT_START(void)
{
IIC_SCL_HIGH();
IIC_SDA_HIGH();
delay_us(5);
IIC_SDA_LOW();
delay_us(5);
IIC_SCL_LOW();
delay_us(5);
IIC_SCL_HIGH();
delay_us(5);
IIC_SDA_HIGH();
delay_us(5);
IIC_SCL_LOW();
}
/***************
*SHT11發(fā)送數(shù)據(jù)時(shí)序
***************/
void SHT_SEND(uchar data)
{uchar i,data1;
for(i=0;i<8;i++)
{
data1=data<
if(!(data1&0x80))
IIC_SDA_LOW();
if(data1&0x80)
IIC_SDA_HIGH();
IIC_SCL_LOW();//寫完1位數(shù)據(jù)將時(shí)鐘線拉低,等待發(fā)送
delay_us(5);
IIC_SCL_HIGH();//時(shí)鐘線上升沿,發(fā)送1位數(shù)據(jù)
delay_us(5); //等待1位數(shù)據(jù)發(fā)送完成
}
IIC_SCL_LOW();
IIC_SDA_HIGH();//8位數(shù)據(jù)發(fā)送完成,數(shù)據(jù)線拉高,等待SLAVE器件響應(yīng)
delay_us(5);
IIC_SCL_HIGH();//時(shí)鐘線拉高,產(chǎn)生上升沿讀取數(shù)據(jù)線是否SLAVE器件有響應(yīng)
//while(IIC_SDA==1);
delay_us(5);
IIC_SCL_LOW();
IIC_SDA_HIGH();//數(shù)據(jù)線拉高,時(shí)鐘線拉低,等待轉(zhuǎn)換完成
}
/***************
*SHT11接收數(shù)據(jù)時(shí)序
***************/
uint SHT_REC(void)
{
uint i;
uint REC1=0,REC0=0,REC=0;
for(i=0;i<8;i++)
{
IIC_SCL_HIGH();//轉(zhuǎn)換完成,SLAVE器件將數(shù)據(jù)線拉低,時(shí)鐘線產(chǎn)生上升沿讀取高8位數(shù)據(jù)
REC1=(REC1<<1)+IIC_SDA;
delay_us(5);
IIC_SCL_LOW(); //將時(shí)鐘線拉低,等待下一個(gè)上升沿的到來
delay_us(5);
}
SHT_ASK(); //高8位數(shù)據(jù)接收完畢,發(fā)送應(yīng)答信號(hào)
for(i=0;i<8;i++)
{
IIC_SCL_HIGH();//轉(zhuǎn)換完成,SLAVE器件將數(shù)據(jù)線拉低,時(shí)鐘線產(chǎn)生上升沿讀取低8位數(shù)據(jù)
REC0=(REC0<<1)+IIC_SDA;
delay_us(5);
IIC_SCL_LOW();
delay_us(5);
}
SHT_STOP();//低8位數(shù)據(jù)接收完畢,結(jié)束
REC=(REC1<<8)+REC0;
return REC;
}
/***************
*SHT11應(yīng)答時(shí)序
***************/
void SHT_ASK(void)
{
IIC_SCL_LOW();
IIC_SDA_LOW();//數(shù)據(jù)線拉低
delay_us(5);
IIC_SCL_HIGH();//時(shí)鐘線拉高才生應(yīng)答信號(hào)
delay_us(5);
IIC_SDA_HIGH();
IIC_SCL_LOW();
delay_us(5);
}
/***************
*SHT11停止時(shí)序
***************/
void SHT_STOP(void)
{
IIC_SDA_HIGH();
IIC_SCL_LOW();
delay_us(5);
IIC_SCL_HIGH();
delay_us(5);
IIC_SDA_HIGH();
IIC_SCL_LOW();
}
評(píng)論