IIC總線
一、與IIC有關的知識
(1)IIC屬于半雙工通信方式
(2)IIC的協議
1.空閑狀態:IIC的SCL和SDA兩條線均處于高電平狀態,此時即釋放總線
2.起始信號(Start):SCL為高電平期間,SDA產生一個下降沿信號
3.停止信號(End):SCL為高電平期間,SDA產生一個上升沿信號
4.應答信號ACK: 發送器每發送一個字節,就在時鐘脈沖9期間釋放數據線,由接收器反饋一個應答信號。應答信號為低電平時,規定為有效應答位(ACK簡稱應答位),表示接收器已經成功地接收了該字節;應答信號為高電平時,規定為非應答位(NACK),一般表示接收器接收該字節沒有成功。
5.數據有效性:I2C總線進行數據傳送時,時鐘信號為高電平期間,數據線上的數據必須保持穩定,只有在時鐘線上的信號為低電平期間,數據線上的高電平或低電平狀態才允許變化。即:數據在SCL的上升沿到來之前就需準備好。并在在下降沿到來之前必須穩定。
6.數據傳輸:在I2C總線上傳送的每一位數據都有一個時鐘脈沖相對應(或同步控制),即在SCL串行時鐘的配合下,在SDA上逐位地串行傳送每一位數據。數據位的傳輸是邊沿觸發。
(3)24C02
1.寫數據流程
第一步,首先是 I2C 的起始信號,接著跟上首字節,也就是我們前邊講的 I2C 的器件地址,并且在讀寫方向上選擇“寫”操作。第二步,發送數據的存儲地址。24C02 一共256 個字節的存儲空間,地址從0x00~0xFF,我們想把數據存儲在哪個位置,此刻寫的就是哪個地址。第三步,發送要存儲的數據第一個字節、第二個字節??注意在寫數據的過程中,EEPROM 每個字節都會回應一個“應答位 0”,來告訴我們寫 EEPROM 數據成功,如果沒有回應答位,說明寫入不成功。字
2.讀數據流程:
第一步,首先是 I2C 的起始信號,接著跟上首字節,也就是我們前邊講的 I2C 的器件地址,并且在讀寫方向上選擇“寫”操作。這個地方可能有同學會詫異,我們明明是讀數據為何方向也要選“寫”呢?剛才說過了, 24C02 一共有 256 個地址,我們選擇寫操作,是為了把所要讀的數據的存儲地址先寫進去,告訴 EEPROM 我們要讀取哪個地址的數據。這就如同我們打電話,先撥總機號碼( EEPROM 器件地址),而后還要繼續撥分機號碼(數據地址),而撥分機號碼這個動作,主機仍然是發送方,方向依然是“寫”。第二步,發送要讀取的數據的地址,注意是地址而非存在 EEPROM 中的數據,通知EEPROM 我要哪個分機的信息。第三步,重新發送 I2C 起始信號和器件地址,并且在方向位選擇“讀”操作。這三步當中,每一個字節實際上都是在“寫”,所以每一個字節EEPROM 都會回應一個“應答位0”。第四步,讀取從器件發回的數據,讀一個字節,如果還想繼續讀下一個字節,就發送一個“應答位 ACK(0)”,如果不想讀了,告訴EEPROM,我不想要數據了,別再發數據了,那就發送一個“非應答位 NAK(1)”
3.24C02地址
24C02的 7 位地址中,其中高 4 位是固定的 0b1010,而低 3 位的地址取決于具體電路的設計,由芯片上的 A2、 A1、 A0 這 3 個引腳的實際電平決定,高為1,低為0.最低位是數據方向位(R/W)0表示接下來要發送數據(寫),1表示接下來是請求數據(讀)。
二、用到的知識
1. GPIO、串口
2. IIC、24C02
三、功能
先在24c02的一個地址中寫入一個字符,然后在讀取該位置的字符并通過串口顯示出來。
#include "iic.h"#define iicsda PBout(7)#define iicscl PBout(6)#define iicsdain PBin(7)void SDAOUT(void)//sda×÷?aí?íìê?3?{ GPIO_InitTypeDef GPIO_InitTypeStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_7; GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitTypeStruct);}void SDAIN(void)//SDA×÷?a????ê?è?{ GPIO_InitTypeDef GPIO_InitTypeStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_7; GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitTypeStruct);}void Myiic_INIT()//IIC3?ê??ˉ{ GPIO_InitTypeDef GPIO_InitTypeStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7; GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitTypeStruct); GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);}void Myiic_Start(void)//?eê?D?o?{ SDAOUT(); iicsda=1; iicscl=1; delay_us(4); iicsda=0; delay_us(4); iicscl=0;}void Myiic_Stop(void)//í£?1D?o?{ SDAOUT(); iicscl=0; iicsda=0; delay_us(4); iicscl=1; iicsda=1; delay_us(4);}u8 Myiic_Wait_Ack(void)//μè′yACK{ u8 time=0; SDAIN(); iicsda=1; delay_us(1); iicscl=1; delay_us(1); while(iicsdain) { time++; if(time>250) { Myiic_Stop(); return 1; } } iicscl=0; return 0;}void Myiic_ACK(void)//2úéúACKó|′e{ iicscl=0; SDAOUT(); iicsda=0; delay_us(2); iicscl=1; delay_us(2); iicscl=0;}void Myiic_NACK(void)//2?2úéúó|′e??{ iicscl=0; SDAOUT(); iicsda=1; delay_us(2); iicscl=1; delay_us(2); iicscl=0;}void Myiic_Sendbyte(u8 w)//·¢?íò???×??ú{ u8 i; SDAOUT(); iicscl=0; for(i=0;i<8;i++) { iicsda=(w&0x80)>>7; w<<=1; delay_us(2); iicscl=1; delay_us(2); iicscl=0; delay_us(2); }}u8 Myiic_Readbyte(unsigned char ack)//?áè?ò???×??ú{ unsigned char i=0,r=0; SDAIN(); for(i=0;i<8;i++) { iicscl=0; delay_us(2); iicscl=1; r<<=1; if(iicsdain) r++; delay_us(1); } if(!ack) Myiic_NACK(); else Myiic_ACK(); return r;}
新聞熱點
疑難解答