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