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