/****************************************************************************** IIC通信原理介紹 I2C(Inter-Integrated Circuit)總線是由PHILIPS公司開(kāi)發(fā)的兩線式(SCL、 SDA)串行總線,用于連接微控制器及其外圍設(shè)備。SDA(serial data line)表示串行數(shù)據(jù)線,SCL(serial clock line)為串行時(shí)鐘線,SDA是雙線數(shù)據(jù)線,既可以接收也可以發(fā)送數(shù)據(jù)。在使用時(shí),SDA和SCL都必須利用外部上拉電阻連接到VCC(當(dāng)總線空閑時(shí)可以保持高電平)。IIC總線快速模式下可以達(dá)到400kHZ的傳輸速率。每一個(gè)IIC器件都有一個(gè)唯一的可識(shí)別的地址。 ST(START):IIC數(shù)據(jù)傳輸開(kāi)始于一個(gè)起始信號(hào)。起始信號(hào)定義為當(dāng)SCL為高電平 (HIGH)時(shí)SDA從高電平(HIGH)跳為低電平(LOW); SAD(Slave Adress):起始信號(hào)傳輸后,下一個(gè)Byte前7bit表示從機(jī)的地址,第8 位表示發(fā)送or接收數(shù) 據(jù),若從機(jī)接收到前7bit,并與自己的地址比較,若匹配,則從機(jī)認(rèn)為主機(jī)選中自己,需要 進(jìn)行通信; ACK(Acknowledge):主從機(jī)接收到數(shù)據(jù)后會(huì)發(fā)送一個(gè)應(yīng)答信號(hào); SP(STOP):停止信號(hào)定義為當(dāng)SCL線為高電平時(shí),SDA從低電平(LOW)跳變?yōu)楦唠娖剑?/font>HIGH)。 以上僅僅是針對(duì)IIC通信的簡(jiǎn)單的介紹,更加詳細(xì)的介紹請(qǐng)參考IIC的datesheet。 *****************************************************************************/ /****************************************************************************** 說(shuō)明: 1、本文件主要功能是:用普通IO口模擬IIC實(shí)現(xiàn)通信功能 2、本文件版權(quán)屬思飛工作室 3、使用方法:在需要使用IIC的工程中,包含IIC.h和IIC.c文件 4、由于使用普通IO口模擬IIC,所以此處理論上可以用任意IO口來(lái)模擬 ******************************************************************************/ #include "IIC.h" #include "delay.h" /************************************************************************** 函數(shù)名稱(chēng):IIC_Init(void) 功能:初始化IIC使用的引腳。此處使用stm32的PB10/PB11來(lái)模擬IIC通信 參數(shù):無(wú) 返回值 : 無(wú) 說(shuō)明:端口配置需要使用CNFx[1:0],MODEx[1:0]相關(guān)位含義列出如下: MODEx[1:0] 00:輸入模式(復(fù)位后的狀態(tài)) 01:輸出模式,最大速度10MHz 10:輸出模式,最大速度2MHz 11:輸出模式,最大速度50MHz CNFx[1:0] 在輸入模式(MODE[1:0]=00): 00:模擬輸入模式 01:浮空輸入模式(復(fù)位后的狀態(tài)) 10:上拉/下拉輸入模式 11:保留 在輸出模式(MODE[1:0]>00): 00:通用推挽輸出模式 01:通用開(kāi)漏輸出模式 10:復(fù)用功能推挽輸出模式 11:復(fù)用功能開(kāi)漏輸出模式 ***************************************************************************/ void IIC_Init(void) { RCC->APB2ENR|=1<<3; //先使能外設(shè)IO PORTB時(shí)鐘 GPIOB->CRH&=0XFFFF00FF; //PB10,11 推挽輸出, CNFx[1:0],MODEx[1:0],配置0011表示推挽輸出 GPIOB->CRH|=0X00003300; GPIOB->ODR|=3<<10; //PB10 11輸出高 } /************************************************************************** 函數(shù)名稱(chēng):IIC_Start(void) 功 能:產(chǎn)生IIC起始信號(hào)(ST) 參 數(shù):無(wú) 返回值 : 無(wú) 說(shuō)明:IIC起始信號(hào)定義為當(dāng)SCL為高電平(HIGH)時(shí),SDA線從高到低的跳變 ***************************************************************************/ void IIC_Start(void) { SDA_OUT(); //SDA線輸出 IIC_SDA=1; //SDA為高電平輸出 delay_us(1); IIC_SCL=1; //SCL為高電平 delay_us(6); IIC_SDA=0; //START:when CLK is high,DATA change form high to low delay_us(6); IIC_SCL=0; //鉗住I2C總線,準(zhǔn)備發(fā)送或接收數(shù) 據(jù),避免在SCL為高電平期間,再次發(fā)出起始信號(hào)或者停止信號(hào) delay_us(2); } /************************************************************************** 函數(shù)名稱(chēng): IIC_Stop(void) 功 能: 產(chǎn)生IIC停止信號(hào)(SP) 參 數(shù):None 返回值 : None 說(shuō)明 :IIC停止信號(hào)定義為當(dāng)SCL為高電平(HIGH)時(shí),SDA線從低到高的跳變 ***************************************************************************/ void IIC_Stop(void) { SDA_OUT(); //SDA線輸出 IIC_SDA=0; //SDA為低電平 delay_us(2); IIC_SCL=1; //SCL為高電平 delay_us(6); IIC_SDA=1; //STOP:when CLK is high DATA change form low to high delay_us(4); } /************************************************************************** 函數(shù)名稱(chēng): IIC_Wait_Ack(void) 功能: 等待應(yīng)答信號(hào)到來(lái) 參數(shù):無(wú) 返回值 : [1,接收應(yīng)答失;0,接收應(yīng)答成功] 說(shuō)明:IIC通信時(shí),接收到數(shù)據(jù),從機(jī)(Slave)會(huì)發(fā)出ACK信號(hào),一般是一個(gè)低電平 信號(hào)出現(xiàn)在SDA線上,若主機(jī)檢測(cè)到,則認(rèn)為此次通信成功 注意:應(yīng)答信號(hào)是在SCL為高電平器件,SDA一直為低電平表示應(yīng)答 ***************************************************************************/ u8 IIC_Wait_Ack(void) { u8 ucErrTime=0; SDA_IN(); //SDA設(shè)置為輸入 IIC_SDA=1;delay_us(2); IIC_SCL=1;delay_us(2); while(READ_SDA) //若超過(guò)250個(gè)時(shí)鐘周期沒(méi)有收到應(yīng) 答信號(hào),認(rèn)為通信失敗,返回1,并結(jié)束此次通信 { ucErrTime++; if(ucErrTime>250) { IIC_Stop(); return 1; } } IIC_SCL=0; //時(shí)鐘輸出0 return 0; //若通信成功,則返回0 } /************************************************************************** 函數(shù)名稱(chēng): IIC_Ack() 功 能: 產(chǎn)生應(yīng)答信號(hào) ,主機(jī)從從機(jī)讀取數(shù)據(jù)后,向從機(jī)發(fā)出應(yīng)答信號(hào) 參 數(shù):None 返回值 : None 說(shuō)明: 主機(jī)在接收到從機(jī)的數(shù)據(jù)后,向從機(jī)返回一個(gè)應(yīng)答信號(hào),繼續(xù)通信,在SCL為 高電平器件,SDA一直保持低電平表示應(yīng)答 ***************************************************************************/ void IIC_Ack(void) { IIC_SCL=0; //SCL初始為低 SDA_OUT(); IIC_SDA=0; //SDA輸出低 delay_us(2); IIC_SCL=1; //SCL輸出高電平 delay_us(2); IIC_SCL=0; //SCL再輸出低電平,保證在SCL為高電平 期間,SDA始終保持高電平,表示應(yīng)答信號(hào) } /************************************************************************** 函數(shù)名稱(chēng): IIC_NAck() 功能: 不產(chǎn)生應(yīng)答信號(hào),主機(jī)接收到從機(jī)的數(shù)據(jù)后,不發(fā)出應(yīng)答信號(hào) 參 數(shù):None 返回值 : None 說(shuō)明:在IIC中SCL為高電平器件,SDA也保持高電平則表示不應(yīng)答,NACK ***************************************************************************/ void IIC_NAck(void) { IIC_SCL=0; //SCL輸出低電平 SDA_OUT(); IIC_SDA=1; //SDA輸出高電平 delay_us(2); IIC_SCL=1; //SCL輸出高電平 delay_us(2); IIC_SCL=0; //SCL再次輸出低電平,保證SCL為高時(shí), SDA一直為高 } /************************************************************************** 函數(shù)名稱(chēng): IIC_Send_Byte() 功能: 主機(jī)發(fā)送一個(gè)字節(jié)數(shù)據(jù)到從機(jī) 參 數(shù):需要發(fā)送的數(shù)據(jù) 返回值 : 無(wú) 說(shuō)明: IIC每次傳輸?shù)臄?shù)據(jù)位8bit, ***************************************************************************/ void IIC_Send_Byte(u8 txd) { u8 t; SDA_OUT(); //SDA輸出 IIC_SCL=0; //拉低時(shí)鐘開(kāi)始數(shù)據(jù)傳輸 for(t=0;t<8;t++) //循環(huán)八次,把txd中的8bit數(shù)據(jù)通過(guò)SDA線輸出,但同 時(shí)SCL時(shí)鐘也必須翻轉(zhuǎn) { IIC_SDA=(txd&0x80)>>7; txd<<=1; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; delay_us(2); } } /************************************************************************** 函數(shù)名稱(chēng): IIC_Read_Byte() 功能: IIC接收一個(gè)字節(jié)的內(nèi)容 參數(shù):ack表示是否返回ACK信號(hào),若ack=1,則發(fā)送ACK(),否則發(fā)送NACK() 返回值 : 返回讀出的8bit的數(shù)據(jù) ***************************************************************************/ u8 IIC_Read_Byte(unsigned char ack) { u8 i,receive=0; SDA_IN(); //SDA設(shè)置為輸入 for(i=0;i<8;i++) //根據(jù)SDA電平的高低,決定receive的8bit信息 { 第 4 頁(yè) IIC.txt IIC_SCL=0; delay_us(2); IIC_SCL=1; receive<<=1; if(READ_SDA)receive++; delay_us(2); } IIC_SCL = 0; if (!ack) IIC_NAck(); //發(fā)送nACK else IIC_Ack(); //發(fā)送ACK return receive; //返回讀到的數(shù)據(jù) } /************************************************************************** 函數(shù)名稱(chēng):IIC_ReadReg(u8 DeviceAddr,u8ReadAddr) 功能:在指定的器件地址中指定的寄存器地址中讀出一個(gè)數(shù)據(jù) 參 數(shù):DeviceAddr:從器件的地址 ReadAddr:寄存器的地址 返回值 : 讀到的數(shù)據(jù) 說(shuō)明:讀取數(shù)據(jù)流程如下 master(主機(jī)):ST SAD+W SUB SR SAD+R NMAK SP slave(從機(jī)) : SAK SAK SAK DATA 其中各符號(hào)含義如下: ST :起始信號(hào) SAD+W:從器件地址+Write SAK:從機(jī)應(yīng)答信號(hào) SUB:寄存器地址 SR :重新啟動(dòng) DATA :數(shù)據(jù) NMAK :主機(jī)無(wú)應(yīng)答 SP :停止信號(hào) **************************************************************************/ u8 IIC_ReadReg(u8 DeviceAddr,u8 ReadAddr) { u8 temp=0; IIC_Start(); //起始信號(hào) IIC_Send_Byte(DeviceAddr); //發(fā)送器件地址 IIC_Wait_Ack(); //等待應(yīng)答 IIC_Send_Byte(ReadAddr); //發(fā)送寄存器地址 IIC_Wait_Ack(); //等待應(yīng)答 IIC_Start(); //重新啟動(dòng)IIC總線 IIC_Send_Byte(DeviceAddr+1); //發(fā)送器件地址 IIC_Wait_Ack(); //再次等待應(yīng)答 temp=IIC_Read_Byte(0); //只讀取1byte的數(shù)據(jù),無(wú)需主機(jī)應(yīng)答 IIC_Stop(); //產(chǎn)生一個(gè)停止條件 return temp;
|