IIC通信(解決各傳感器怎么接線的問題)
講到IIC通訊就順便講講串口通訊吧(以前上FPGA課程的資料)
處理器和外部設(shè)備通訊的兩種方式(并行通信和串行通信)
并行通信
? 是指數(shù)據(jù)的各個(gè)位用多條數(shù)據(jù)線同時(shí)進(jìn)行傳輸,傳輸速度很快,但是引腳資源占用較多

? ? ???串行通信
? ? ? ? ? ? 將數(shù)據(jù)分為一位一位的形式在一條數(shù)據(jù)線上逐個(gè)傳輸,傳輸速度慢,引腳占用少

串行通信的通信方式:同步通信和異步通信
同步通訊
帶時(shí)鐘同步信號(hào)的數(shù)據(jù)傳輸;發(fā)送設(shè)備和接收設(shè)備在同一時(shí)鐘的控制下,進(jìn)行 同步傳輸數(shù)據(jù)

異步通信
不帶時(shí)鐘同步信號(hào)的數(shù)據(jù)傳輸,發(fā)送設(shè)備和接收設(shè)備使用各自的時(shí)鐘控制數(shù)據(jù) 的發(fā)送和接收過程。


常見的串行通信接口:UART、SPI、IIC(三大串行總線協(xié)議)

? UART:(Universal Asynchronous Receiver-Transmitter:通用異步收發(fā)器) 功能:在發(fā)送數(shù)據(jù)時(shí)將并行數(shù)據(jù)轉(zhuǎn)換成串行數(shù)據(jù)來(lái)傳輸,在接收數(shù)據(jù)時(shí)將接收到的串行 數(shù)據(jù)轉(zhuǎn)成成并行數(shù)據(jù)。 協(xié)議層:通信協(xié)議(包括數(shù)據(jù)格式、數(shù)據(jù)傳輸速率等...) 物理層:接口類型、電平標(biāo)準(zhǔn)等...

協(xié)議層:通信協(xié)議(數(shù)據(jù)格式)

? SPI:(Serial Peripheral Interface:串行外設(shè)接口)**此處以FPGA芯片為例


? IIC:(Inter-Integrated Circuit:集成電路總線):半雙工**此處以FPGA芯片為例


IIC(Inter-Integrated Circuit)又稱I2C(習(xí)慣讀“I方C”),是IICBus簡(jiǎn)稱,中文名為集成電路總線,它是一種串行通信總線,使用多主從架構(gòu),由飛利浦公司在1980年代為了讓主板、嵌入式系統(tǒng)或手機(jī)用以連接低速周邊設(shè)備而發(fā)展。適用于IC間的短距離數(shù)據(jù)傳輸。
IIC是單片機(jī)最常用的通訊方式之一,如果單片機(jī)需要擴(kuò)展EEPROM存儲(chǔ)芯片,就會(huì)用到IIC通信來(lái)讀寫EEPROM的數(shù)據(jù)。
除此很多傳感器(如溫濕度傳感器,加速度傳感器等)、外設(shè)(如OLED屏幕、LCD顯示板等)也會(huì)采用IIC與單片機(jī)進(jìn)行數(shù)據(jù)的傳輸。

硬件IIC:我們知道,STM32外設(shè)豐富,包括硬件級(jí)的IIC通信,也就是在其內(nèi)部集成有專門用于IIC通信的硬件模塊,只要在程序中配置相關(guān)的參數(shù),就能啟用該模塊,再通過官方已經(jīng)做好的庫(kù)函數(shù),就能很容易的實(shí)現(xiàn)IIC通信了。
但是由于STM32的硬件IIC存在著應(yīng)答信號(hào)卡死的問題,所以很多開發(fā)者更喜歡使用軟件模擬IIC通信。另外,軟件模擬IIC還有方便移植到其他設(shè)備的優(yōu)點(diǎn)。
IC物理接口:IIC串行總線有兩根信號(hào)線,一根是雙向的數(shù)據(jù)線SDA,另一根是時(shí)鐘線SCL。所有接到I2C總線設(shè)備上的串行數(shù)據(jù)SDA都接到總線的SDA上,各設(shè)備的時(shí)鐘線SCL接到總線的SCL上,屬于一主多從總線。主機(jī)一次只能跟一個(gè)從機(jī)通信,如果要跟多個(gè)從機(jī)傳輸數(shù)據(jù),則需要采用輪詢的方式。通常會(huì)給SDA和SCL外接上拉電阻,確保無(wú)數(shù)據(jù)傳輸時(shí),總線處于閑置狀態(tài)。但是不接也可以,可以使用STM32的片內(nèi)上拉電阻。

這兩根線中,SCL是時(shí)鐘線,用來(lái)同步時(shí)鐘信號(hào);SDA是數(shù)據(jù)線,用來(lái)傳輸數(shù)據(jù)。
?但對(duì)于軟件模擬IIC,就沒有任何限制,可以定義任意兩個(gè)IO口分別作為SCL與SDA。
定義SCL與SDA的引腳,以及兩個(gè)引腳置高、置低的函數(shù)。
#define IIC_SCL_H() GPIO_SetBits(GPIOA,GPIO_Pin_1) //定義SCL置高為PA1置位
#define IIC_SCL_L() GPIO_ResetBits(GPIOA,GPIO_Pin_1) //定義SCL置低為PA1復(fù)位
#define IIC_SDA_H() GPIO_SetBits(GPIOA,GPIO_Pin_2) //定義SDA置高為PA2置位
#define IIC_SDA_L() GPIO_ResetBits(GPIOA,GPIO_Pin_2) //定義SDA置低為PA2復(fù)位
延時(shí)函數(shù):
void Delay_us(int Time)?
{?
int i=0;
while(Time--)?
{?
i=8;
?while(i--);
}?
return;?
}
由于SDA需要在輸入輸出模式之間切換(等待應(yīng)答時(shí)需要將PA2切換成輸入模式),所以還要定義這兩個(gè)函數(shù)。輸出模式用推挽輸出即可,輸入模式采用上拉輸入模式(如果總線外接了上拉電阻,采用浮空輸入也可以)。
void SDA_OUT(void) //SDA輸出模式?
{
GPIO_InitTypeDef GPIO_InitStructure;?
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_2;?
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //推挽輸出模式 GPIO_Init(GPIOA, &GPIO_InitStructure);?
}?
void SDA_IN(void) //SDA輸入模式
{?
GPIO_InitTypeDef GPIO_InitStructure;?
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //上拉輸入模式?
GPIO_Init(GPIOA, &GPIO_InitStructure);?
}
起始信號(hào):
void IIC_Start(void)
{?
SDA_OUT();?
//SDA切換至輸出模式?
IIC_SDA_H(); //SDA置高?
IIC_SCL_H();
?//SCL置高?
Delay_us(1);
IIC_SDA_L(); //SDA置低?
Delay_us(1);?
}
停止信號(hào):
void IIC_Stop(void)
{?
IIC_SCL_H(); //SCL置高?
IIC_SDA_L(); //SDA置低
Delay_us(1);?
IIC_SDA_H(); //SDA置高?
Delay_us(1);?
}
數(shù)據(jù)幀:
void IIC_WriteByte(u8 data) //發(fā)送一個(gè)數(shù)據(jù)串,data為要發(fā)送的數(shù)據(jù)
{
u8 i;
SDA_OUT(); //SDA設(shè)置為輸出模式?
for(i=0;i<8;i++) //循環(huán)發(fā)送,每次循環(huán)發(fā)送1bit,循環(huán)8次就是1Byte
{
IIC_SCL_L(); //SCL置低?
if(data & 0x80) //如果Data的第八位是高電平?
IIC_SDA_H(); //SDA置高
else
IIC_SDA_L(); //SDA置低?
IIC_SCL_H(); //SCL置高?
Delay_us(1); //延時(shí)?
data<<=1; //data左移一位?
}?
}
應(yīng)答信號(hào):
u8 IIC_Wait_Ask(void)?
{?
int count=0;?
IIC_SCL_L(); //SCL置低?
Delay_us(1); //延時(shí)?
IIC_SDA_H(); //SDA置高?
SDA_IN(); //SDA切換成輸入模式?
IIC_SCL_H(); //SCL置高?
Delay_us(1); //延時(shí),等待從機(jī)發(fā)出應(yīng)答信號(hào)?
while(Read_IIC_SDA) //如果SDA為低電平?
{?
count++; //開始計(jì)數(shù)?
if(count>250) //計(jì)數(shù)超過250,則認(rèn)為數(shù)據(jù)發(fā)送失敗,從機(jī)無(wú)響應(yīng)?
{?
IIC_Stop(); //發(fā)出停止信號(hào)?
return 1; //函數(shù)返回1?
}?
}?
IIC_SCL_L(); //如果SDA為高電平,則認(rèn)為收到應(yīng)答,
SCL置低
Delay_us(1);?
return 0; //函數(shù)返回0?
}

文章參考:https://blog.csdn.net/qq_55203246/article/details/123944252