PIC单片机 IIC通信及实现
IIC通信
??IIC是一種只需要2根數(shù)據(jù)線就可以實現(xiàn)數(shù)據(jù)通信的總線式結(jié)構(gòu)。IIC采用主從式通信方式,通信過程完全由主設(shè)備決定。完整的通信流程是主設(shè)備發(fā)送起始信號給從設(shè)備,再發(fā)送地址來選中從設(shè)備,然后就可以開始進(jìn)行數(shù)據(jù)傳輸,當(dāng)傳輸結(jié)束后由主設(shè)備發(fā)送結(jié)束信號告知從設(shè)備通信結(jié)束。
(示例代碼中,PORTA為所用單片機(jī)的8位引腳對應(yīng)的寄存器名稱,采用PORTA<7>作為數(shù)據(jù)位SDA、PORTA<6>作為時鐘位SCL)
起始信號
??起始信號由兩個下降沿組成,SDA信號先從1置0,然后SCL再從1置0,由此告知從設(shè)備要開始通信了。代碼如下:
/************************************************************* 啟動總線函數(shù) 函數(shù)原型: void start_i2c(); Function: start on the I2C bus *************************************************************/ void start_i2c() {PORTA |= 0b10000000; //SDA=1,發(fā)送啟始條件的數(shù)據(jù)信號delay_10us();PORTA |= 0b01000000; //SCL=1delay_10us();PORTA &= 0b01111111; //SDA=0,發(fā)送起始信號delay_10us();PORTA &= 0b10111111; //SCL=0,鉗住I2C總線,準(zhǔn)備發(fā)送數(shù)據(jù)或接收數(shù)據(jù)delay_10us(); }?
終止信號
??起始信號由兩個上升沿,SCL信號先從0置1,然后SDA再從0置1,由此告知從設(shè)備要結(jié)束通信。代碼如下:
/************************************************************* 停止總線函數(shù) 函數(shù)原型: void stop_i2c(); Function: stop the I2C bus **************************************************************/ void stop_i2c() {PORTA &= 0b01111111; //SDA=0,發(fā)送結(jié)束條件的數(shù)據(jù)信號delay_10us();PORTA |= 0b01000000; //SCL=1delay_10us();PORTA |= 0b10000000; //SDA=1delay_10us(); }?
發(fā)送8位數(shù)據(jù)
??無論發(fā)送地址還是數(shù)據(jù),都是通過相同方式一位一位地發(fā)送,并且要從高位開始。首先是將時鐘線SCL置0,意味著數(shù)據(jù)線SDA要開始準(zhǔn)備信息來發(fā)送。
??在每一位數(shù)據(jù)發(fā)送前時鐘線都要有一段低電平。當(dāng)數(shù)據(jù)線SDA置為要發(fā)送的電平后SCl置1,從設(shè)備讀取此時SDA電平值作為一個bit,隨后SCL置0,SDA置為下一個待發(fā)送位,重復(fù)上述步驟,循環(huán)8次即完成一次8bit數(shù)據(jù)傳輸。
/*==================================================== 字節(jié)數(shù)據(jù)傳送函數(shù) 函數(shù)原型: void send_byte(uchar c); Function: 將數(shù)據(jù)C發(fā)送出去,可以是地址,也可以是數(shù)據(jù),發(fā)完后等待回應(yīng),并對此狀態(tài) 位進(jìn)行操作(不應(yīng)答或非應(yīng)答都使ack=0 ),發(fā)送數(shù)據(jù)正常,ack=1;ack=0 表示被控器無應(yīng)答或損壞。 ====================================================*/ void send_byte(uint8_t c) {uint8_t bit_count;for (bit_count = 0; bit_count < 8; bit_count++){if (c & 0x80){PORTA |= 0b10000000; //SDA=1}else{PORTA &= 0b01111111; //SDA=0}delay_10us();PORTA |= 0b01000000; //SCL=1delay_10us();PORTA &= 0b10111111; //SCL=0c <<= 1;delay_10us();} }?
等待應(yīng)答
??為了確保從設(shè)備收到了主設(shè)備發(fā)送來的數(shù)據(jù),每次發(fā)送后主設(shè)備都要等待從設(shè)備回復(fù)ACK信號才能進(jìn)行后續(xù)通話。
??在等待ACK的過程中,主設(shè)備要先釋放總線SDA,將總線權(quán)限交給從設(shè)備,即SDA置1。后續(xù)如果檢測到SDA被置0了就說明從設(shè)備答復(fù)了ACK信號。
/*==================================================== 等待從設(shè)備應(yīng)答函數(shù) 函數(shù)原型: void wait_ack(); Function: 等待從設(shè)備對主設(shè)備發(fā)送行為的應(yīng)答 ====================================================*/ uint8_t wait_ack() {uint8_t re = 0;PORTA |= 0b10000000; //SDA=1,釋放總線,將總線權(quán)限交給從設(shè)備delay_10us();PORTA |= 0b01000000; //SCL=1TRISA = 0b10000000;delay_10us();if ((PORTA & 0b10000000) == 0){re = 1; //ACK}else{re = 0; //NACK}TRISA &= 0b01111111;PORTA &= 0b10111111; //SCL=0delay_10us();return re; }?
發(fā)送ACK
??主設(shè)備發(fā)送完數(shù)據(jù)需要從設(shè)備答復(fù)ACK信號,而從設(shè)備發(fā)送給主設(shè)備數(shù)據(jù)后同樣需要主設(shè)備給其答復(fù)ACK信號以確保收到。
/*==================================================== 給從設(shè)備發(fā)送應(yīng)答函數(shù) 函數(shù)原型: void wait_ack(); Function: 給從設(shè)備對主設(shè)備發(fā)送成功接收的應(yīng)答 ====================================================*/ void send_ack() {PORTA &= 0b01111111; //SDA=0;delay_10us();PORTA |= 0b01000000; //SCL=1delay_10us();PORTA &= 0b10111111; //SCL=0delay_10us(); }?
接收8位數(shù)據(jù)
??與發(fā)送數(shù)據(jù)時相同,SCL置1表示讀取此時SDA電平值作為一個bit,循環(huán)8次得到8位數(shù)據(jù)值。
/*================================================ 字節(jié)數(shù)據(jù)接收函數(shù) 函數(shù)原型:uchar receive_byte(); FUNCTION: 用來接收從器件傳來的數(shù)據(jù),并判斷總線錯誤(不發(fā)應(yīng)答信號), 發(fā)完后請用應(yīng)答函數(shù)。 ====================================================*/ uint8_t receive_byte() {uint8_t retc = 0;PORTA |= 0b10000000; //SDA=1,釋放總線,將總線權(quán)限交給從設(shè)備TRISA |= 0b10000000;delay_10us();uint8_t bit_count;for (bit_count = 0; bit_count < 8; bit_count++){retc = retc * 2; //retc<<1PORTA &= 0b10111111; //SCL=0delay_10us();PORTA |= 0b01000000; //SCL=1delay_10us();if (PORTA & 0b10000000){retc++;}delay_10us();}TRISA &= 0b01111111;PORTA &= 0b10111111; //SCL=0delay_10us();return (retc); }?
通話總程序
??開啟通信——>等待應(yīng)答——>發(fā)送地址和傳輸方向(前7bit為地址,后1bit表示數(shù)據(jù)方向)——>發(fā)送傳感器器件配置信息——>等待應(yīng)答——>再次開啟通信——>發(fā)送地址和傳輸方向——>等待應(yīng)答——>接收數(shù)據(jù)——>回復(fù)ACK——>結(jié)束通信
/*==================================================== IIC通話函數(shù) 函數(shù)原型: void iic_sensor(void); Function: 以IIC協(xié)議與溫度傳感器進(jìn)行通話,獲取溫度數(shù)據(jù) ====================================================*/ void iic_sensor() {start_i2c();send_byte(0b10010010); //發(fā)送地址值,并且設(shè)置為輸入wait_ack();send_byte(0x00); //發(fā)送配置信息wait_ack();start_i2c();send_byte(0b10010011); //發(fā)送地址值,并且設(shè)置為輸出wait_ack();temp[1] = receive_byte();send_ack();temp[0] = receive_byte();send_ack();stop_i2c(); //通話結(jié)束 }總結(jié)
以上是生活随笔為你收集整理的PIC单片机 IIC通信及实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PIC单片机 电容式触摸检测
- 下一篇: Linux文件系统映像:Initranf