概要
IIC(IIC,inter-Integrated circuit),兩線式串行總線,用於MCU和外設間的通信。
IIC只需兩根線:數據線SDA和時鐘線SCL。以半雙工方式實現MCU和外設之間數據傳輸,速度可達400kbps。
多主機I2C總線結構
注意SDA和SCL兩根總線需要上拉,使總線處於空閒狀態。
IIC協議
空閒狀態
協議規定,SDA和SCL同時爲高電平時,總線處於空閒狀態。上拉電阻保證電平處於高電平。
起始信號和停止信號
起始信號:SCL爲高電平時,SDA電平發生高到低的跳變
停止信號:SCL爲高電平時,SDA電平發生低到高的跳變
應答信號
發送器每發送完一個字節(8個脈衝),在第9個脈衝間釋放總線,接收器返回一個ACK信號,協議規定,低電平爲有效應答,高電平爲無效應答。
數據有效性
協議對有效數據進行了規定:即時鐘信號爲高電平期間,數據必須保持穩定,時鐘信號低電平期間,數據線上的電平才允許變化。也就是說,數據在時鐘信號到來前必須準備好,並保持到時鐘信號的下降沿之後。
數據傳輸
I2C爲同步傳輸,時鐘控制數據位的傳輸,邊沿觸發。
驅動程序
直接引用實驗中的代碼。測試沒問題。
起始信號
//產生IIC起始信號
void IIC_Start(void)
{
SDA_OUT(); //sda線輸出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//鉗住I2C總線,準備發送或接收數據
}
停止信號
//產生IIC停止信號
void IIC_Stop(void)
{
SDA_OUT();//sda線輸出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//發送I2C總線結束信號
delay_us(4);
}
有效應答
//產生ACK應答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
無效應答
//不產生ACK應答
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
發送單字節
//IIC發送一個字節
//返回從機有無應答
//1,有應答
//0,無應答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低時鐘開始數據傳輸
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(2); //對TEA5767這三個延時都是必須的
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
接收單字節
//讀1個字節,ack=1時,發送ACK,ack=0,發送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA設置爲輸入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//發送nACK
else
IIC_Ack(); //發送ACK
return receive;
}
EEPROM
24C02爲IIC接口,容量爲256字節。
封裝如下圖:
管腳定義:
設備地址的高四位固定,中間爲地址線定義的地址,最後一位爲讀寫位。
由於A0,A1,A2設置爲0,所以
讀的時候:Device Address = 0xA1;
寫的時候:Device Address = 0xA0;
24C02字節寫時序
- 起始信號
- 寫設備地址,Device Address = 0xA0;
- 等待應答
- 確定寫入的EEPROM地址即WORD ADDRESS
- 等待應答
- 向SDA數據線上寫入數據DATA
- 等待應答
- 停止信號
//在AT24CXX指定地址寫入一個數據
//WriteAddr :寫入數據的目的地址
//DataToWrite:要寫入的數據
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{
IIC_Start();
if(EE_TYPE>AT24C16)
{
IIC_Send_Byte(0XA0); //發送寫命令
IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr>>8);//發送高地址
}else IIC_Send_Byte(0XA0+((WriteAddr/256)<<1)); //發送器件地址0XA0,寫數據
IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr%256); //發送低地址
IIC_Wait_Ack();
IIC_Send_Byte(DataToWrite); //發送字節
IIC_Wait_Ack();
IIC_Stop();//產生一個停止條件
delay_ms(10);
}
24C02字節讀時序
- 起始信號
- 寫設備地址,Device Address = 0xA0;
- 等待應答
- 確定寫入的EEPROM地址即WORD ADDRESS
- 等待應答
- 起始信號
- 讀設備地址,Device Address = 0xA1;
- 等待應答
- 讀SDA上數據
- 等待應答
- 停止信號
//在AT24CXX指定地址讀出一個數據
//ReadAddr:開始讀數的地址
//返回值 :讀到的數據
u8 AT24CXX_ReadOneByte(u16 ReadAddr)
{
u8 temp=0;
IIC_Start();
if(EE_TYPE>AT24C16)
{
IIC_Send_Byte(0XA0); //發送寫命令
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr>>8);//發送高地址
}else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1)); //發送器件地址0XA0,寫數據
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr%256); //發送低地址
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(0XA1); //進入接收模式
IIC_Wait_Ack();
temp=IIC_Read_Byte(0);
IIC_Stop();//產生一個停止條件
return temp;
}
參考
STM32F3與 F4 系列 Cortex M4 內核編程手冊
STM32F4xxx中文參考手冊
STM32F4xxx英文參考手冊
STM32F4 開發指南(寄存器版)