0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

STM32基礎(chǔ)知識:IIC概述與軟件模擬IIC

CHANBAEK ? 來源:上下求索電子er ? 作者:上下求索電子er ? 2023-10-26 11:47 ? 次閱讀

IIC概述與軟件模擬IIC

1 IIC總線概述

1.1 基本概念

內(nèi)部集成電路(Inter Integrated circuit )的簡稱叫做IIC,是一種簡單的、半雙工同步通信的串行通信接口,IIC總線是上世紀(jì)80年代(1982年)由飛利浦公司設(shè)計出來,當(dāng)時的目的是為了給MCU和外圍芯片提供更簡單的交互方式。

1.2 引腳說明

IIC總線只需要兩根引腳就可以實現(xiàn)通信,一根是數(shù)據(jù)線SDA,另一根是時鐘線SCL,所有通過IIC接口通信的外圍器件都掛載在IIC總線上,通過這種機制就可以實現(xiàn)多機通信。

圖片

可以看到,外圍器件的時鐘線和數(shù)據(jù)線都是掛載在IIC總線(由主控芯片提供),并且在空閑狀態(tài)下所有器件的時鐘線SCL和數(shù)據(jù)線SDA都被總線的上拉電阻拉高,這樣就可以把SDA引腳和SCL引腳設(shè)置為開漏模式即可,好處是防止短路。

每個掛載在IIC總線上的外圍器件都有獨立的器件地址,主機發(fā)送開始信號后,只需要發(fā)送想要通信的設(shè)備的地址,如果設(shè)備收到地址并且匹配正確,則開始進行單獨通信。

1.3 通信速率

IIC總線支持不同的通信速率,但是一般常用的標(biāo)準(zhǔn)速率100KHZ,但是有的外圍器件可以支持高達400KHZ的通信速率,而由于IIC總線是半雙工通信,所以同一時刻只能接收或者發(fā)送,也就是說,IIC總線一般是為了控制,不適合作為大量數(shù)據(jù)傳輸?shù)?a target="_blank">接口。

1.4 通信過程

接口可以下述4種模式中的一種運行:

  • 從發(fā)送器模式
  • 接收器模式
  • 主發(fā)送器模式
  • 主接收器模式

默認(rèn)狀態(tài)下工作于從模式 。 接口在生成起始條件后自動地從從模式切換到主模式 (誰先發(fā)送開始信號,誰就作為主機)。當(dāng)仲裁丟失或產(chǎn)生停止信號時,則從主模式切換到從模式,從而實現(xiàn)多主模式功能。

通信流

  • 主模式時,I2C接口啟動數(shù)據(jù)傳輸并產(chǎn)生時鐘信號。串行數(shù)據(jù)傳輸總是以起始條件開始并以停止條件結(jié)束。起始條件和停止條件都是在主模式下由軟件控制產(chǎn)生。
  • 從模式時,I2C接口能識別它自己的地址(7位或10位)和廣播呼叫地址。軟件能夠控制開啟或禁止廣播呼叫地址的識別。
  • 數(shù)據(jù)和地址按8位/字節(jié)進行傳輸,高位在前。跟在起始條件后的1或2個字節(jié)是地址(7位模式為1個字節(jié),10位模式為2個字節(jié))。地址只在主模式發(fā)送。
  • 在一個字節(jié)傳輸?shù)?個時鐘后的第9個時鐘期間,接收器必須回送一個應(yīng)答位(ACK)給發(fā)送器。參考下圖。

圖片

可以看到,在建立通信的時候主機需要發(fā)送 開始信號 ,緊接著主機需要發(fā)出從器件的 設(shè)備地址 (7bit+1bit),從設(shè)備的物理地址是7bit,但是由于只有一根數(shù)據(jù)線,就需要說清楚數(shù)據(jù)的傳輸方向,數(shù)據(jù)的傳輸方向通過從設(shè)備的地址最低位進行表示(最低位是0,表示寫操作,最低位是1,表示讀操作),IIC總線提供了 應(yīng)答機制 ,也就是說從機收到了1個字節(jié)的數(shù)據(jù)之后,會在第九個脈沖發(fā)送給主機一個應(yīng)答信號(1bit),如果主機收到從機的應(yīng)答信號,則主機可以繼續(xù)發(fā)送數(shù)據(jù),反之,如果主機沒有收到從機發(fā)送的應(yīng)答信號,那主機就不應(yīng)該繼續(xù)發(fā)送數(shù)據(jù),而是應(yīng)該主動發(fā)出一個 停止信號 ,表示停止通信。

2 軟件模擬IIC的實現(xiàn)

2.1 IIC初始化

// ---------- software_iic.h ----------
#ifndef __SOFTWARE_IIC_H__
#define __SOFTWARE_IIC_H__

#include "main.h"
#include "tim.h"
#include "gpio.h"

#define DLY_TIM_Handle (&htim1)


// SCL: PB10, SDA: PB11
#define IIC_SCL_PORT GPIOB
#define IIC_SCL_PIN  GPIO_PIN_10
#define IIC_SDA_PORT GPIOB
#define IIC_SDA_PIN  GPIO_PIN_11

#define IIC_SDA_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOB_CLK_ENABLE()
#define IIC_SCL_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOB_CLK_ENABLE()

#define IIC_SCL_WRITE_UP()    HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_SET)
#define IIC_SCL_WRITE_DOWN()  HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_RESET)
#define IIC_SDA_WRITE_UP()    HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_SET)
#define IIC_SDA_WRITE_DOWN()  HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_RESET)

#define IIC_SDA_READ()        HAL_GPIO_ReadPin(IIC_SDA_PORT, IIC_SDA_PIN)

void delay_us(uint16_t nus);

void IIC_Init(void);
void IIC_SDA_OutputMode(void);
void IIC_SDA_InputMode(void);
void IIC_StartSignal(void);
void IIC_StopSignal(void);
void IIC_SendBytes(uint8_t data);
uint8_t IIC_ReadBytes(void);
uint8_t IIC_WaitACK(void);
void IIC_MasterACK(uint8_t ack);

#endif
// ---------- software_iic.c ----------
void IIC_Init(void)
{
  // 初始化SCL和SDA為開漏輸出
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  IIC_SDA_GPIO_CLK_ENABLE();
  IIC_SCL_GPIO_CLK_ENABLE(); 

  GPIO_InitStruct.Pin = IIC_SCL_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(IIC_SCL_PORT, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = IIC_SDA_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(IIC_SDA_PORT, &GPIO_InitStruct);

  // 初始化SCL和SDA為高電平
  IIC_SCL_WRITE_UP();
  IIC_SDA_WRITE_UP();
}

2.2 IIC模式

// SDA輸出模式
void IIC_SDA_OutputMode(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  IIC_SDA_GPIO_CLK_ENABLE();

  GPIO_InitStruct.Pin = IIC_SDA_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(IIC_SDA_PORT, &GPIO_InitStruct);
}

// SDA輸入模式
void IIC_SDA_InputMode(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  IIC_SDA_GPIO_CLK_ENABLE();

  GPIO_InitStruct.Pin = IIC_SDA_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;

  HAL_GPIO_Init(IIC_SDA_PORT, &GPIO_InitStruct);
}

2.3 開始信號

圖片

開始信號由主機發(fā)出,表示打算和所有的從器件進行通信,IIC總線規(guī)定在SCL時鐘線保持高電平期間,把SDA數(shù)據(jù)線拉低,表示開始信號。

// IIC開始信號
void IIC_StartSignal(void)
{
  IIC_SDA_OutputMode();  // 設(shè)置SDA為輸出模式

  // 確保SCL和SDA都是高電平 
  IIC_SCL_WRITE_UP();
  IIC_SDA_WRITE_UP();

  // 拉低SDA,產(chǎn)生一個下降沿
  // 一般常用的IIC總線標(biāo)準(zhǔn)速率為100kHz,即每個時鐘周期為10us,故SDA低電平應(yīng)持續(xù)5us
  IIC_SDA_WRITE_DOWN();  // SDA拉低
  delay_us(6);           // 為了保證兼容性,這里延時6us

  // 拉低SCL,表示準(zhǔn)備通信
  IIC_SCL_WRITE_DOWN();  // SCL拉低
}

如何實現(xiàn)微秒級的延時可以參考下文

STM32基于HAL庫實現(xiàn)微秒延時

2.4 停止信號圖片

停止信號由主機發(fā)出,表示不打算和從器件繼續(xù)通信,IIC總線規(guī)定在SCL時鐘線保持高電平期間,把SDA數(shù)據(jù)線拉高,表示停止信號。

// IIC停止信號
void IIC_StopSignal(void)
{
  IIC_SDA_OutputMode();  // 設(shè)置SDA為輸出模式

  // 確保SCL和SDA都是低電平
  IIC_SCL_WRITE_DOWN();
  IIC_SDA_WRITE_DOWN();

  // 拉高SCL,產(chǎn)生一個上升沿
  // 一般常用的IIC總線標(biāo)準(zhǔn)速率為100kHz,即每個時鐘周期為10us,故SCL高電平應(yīng)持續(xù)5us
  IIC_SCL_WRITE_UP();
  delay_us(5);
  
  IIC_SDA_WRITE_UP(); // 拉高SDA,表示通信結(jié)束
  delay_us(5);        // 確保SDA的電平可以被其他器件檢測
}

2.5 數(shù)據(jù)發(fā)送

圖片

在主機發(fā)送開始信號后,就可以發(fā)送數(shù)據(jù)或者地址,IIC總線規(guī)定數(shù)據(jù)的收發(fā)都是 MSB (高位先出),由于只有一個數(shù)據(jù)線,所以IIC采用串行方式把數(shù)據(jù)的每個bit位發(fā)出去。

由于SCL提供的脈沖周期是有規(guī)律的,所以IIC總線規(guī)定只能在SCL脈沖周期的高電平期間進行數(shù)據(jù)的讀取或者寫入,在SCL脈沖周期的低電平期間可以進行數(shù)據(jù)的修改。

// 主機發(fā)送數(shù)據(jù)
void IIC_SendBytes(uint8_t Data)
{
  uint8_t i = 0;

  IIC_SDA_OutputMode();  // 設(shè)置SDA為輸出模式
      
  // 確保SCL和SDA都是低電平
  IIC_SCL_WRITE_DOWN();
  IIC_SDA_WRITE_DOWN();

  // 開始發(fā)送8位數(shù)據(jù)
  for (i = 0; i < 8; i++)
  {
    // SCL低電平期間主機準(zhǔn)備數(shù)據(jù)
    if (Data & (1 < < (7 - i))) // 判斷數(shù)據(jù)的第7-i位是否為1
    {
      IIC_SDA_WRITE_UP();  // 如果為1,SDA拉高
    }
    else
    {
      IIC_SDA_WRITE_DOWN();// 如果為0,SDA拉低
    }
    delay_us(5); // 至此,數(shù)據(jù)準(zhǔn)備完畢

    // 拉高SCL,主機發(fā)送數(shù)據(jù)
    IIC_SCL_WRITE_UP();    
    delay_us(5); // 至此,數(shù)據(jù)發(fā)送完畢

    // 拉低SCL,準(zhǔn)備發(fā)送下一個數(shù)據(jù)
    IIC_SCL_WRITE_DOWN();
    delay_us(5);
  }
}

2.6 數(shù)據(jù)接收

圖片

在主機發(fā)送開始信號后,就可以發(fā)送數(shù)據(jù)或者地址,IIC總線規(guī)定數(shù)據(jù)的收發(fā)都是MSB(高位先出),由于只有一個數(shù)據(jù)線,所以IIC采用串行方式把數(shù)據(jù)的每個bit位發(fā)出去。

由于SCL提供的脈沖周期是有規(guī)律的,所以IIC總線規(guī)定只能在SCL脈沖周期的高電平期間進行數(shù)據(jù)的讀取或者寫入,在SCL脈沖周期的低電平期間可以進行數(shù)據(jù)的修改。

// 主機接收數(shù)據(jù)
uint8_t IIC_ReadBytes(void)
{
  uint8_t i = 0;
  uint8_t Data = 0; // 用于存儲接收到的數(shù)據(jù)

  IIC_SDA_InputMode();  // 設(shè)置SDA為輸入模式

  IIC_SCL_WRITE_DOWN(); // 確保SCL為低電平

  // 開始接收8位數(shù)據(jù)
  for (i = 0; i < 8; i++)
  {
    // 拉高SCL,主機準(zhǔn)備接收數(shù)據(jù)
    IIC_SCL_WRITE_UP();
    delay_us(5);  // 至此,從機數(shù)據(jù)準(zhǔn)備完畢,主機開始接收

    if (IIC_SDA_READ() == 1)   // 主機收到1
    {
      Data |= (1 < < (7 - i));  // 將收到的1存儲到Data的第7-i位
    }

    /* 由于Data初始化為0000 0000,所以不需要else語句
    else // 收到0
    {
      Data &= ~(1 < < (7 - i)); // 將收到的0存儲到Data的第7-i位
    }
    */
    
    // 拉低SCL,主機準(zhǔn)備接收下一個數(shù)據(jù)
    IIC_SCL_WRITE_DOWN();
    delay_us(5);
  }
  return Data;  // 返回接收到的數(shù)據(jù)
}

2.7 應(yīng)答信號

圖片

IIC總線增加了應(yīng)答機制,在主機發(fā)送一個字節(jié)數(shù)據(jù)之后,從機在第9個脈沖周期進行應(yīng)答,如果SDA為0,則表示應(yīng)答,如果SDA=1,則表示無應(yīng)答,如果從機沒有應(yīng)答,則主機應(yīng)該發(fā)送停止信號,表示停止通信。這里分為兩種情況:

第一種:主機發(fā)送數(shù)據(jù),從機進行應(yīng)答

// 主機發(fā)送數(shù)據(jù),從機進行應(yīng)答
uint8_t IIC_WaitACK(void)
{
  uint8_t ack;
  IIC_SDA_InputMode();  // 設(shè)置SDA為輸入模式

  IIC_SCL_WRITE_DOWN(); // 確保SCL是低電平
  delay_us(5); 

  IIC_SCL_WRITE_UP();  // 拉高SCL,主機準(zhǔn)備接收從機的應(yīng)答信號
  delay_us(5);         // 至此,從機應(yīng)答信號準(zhǔn)備完畢,主機開始接收

  // 如果從機應(yīng)答信號為0,表示從機接收到數(shù)據(jù)
  if (IIC_SDA_READ() == 0)
  {
    ack = 0;
  }
  else // 如果從機應(yīng)答信號為1,表示從機沒有接收到數(shù)據(jù)
  {
    ack = 1;
  }
  
  IIC_SCL_WRITE_DOWN(); // 拉低SCL,主機忽略數(shù)據(jù)
  delay_us(5);

  return ack;  // 返回從機的應(yīng)答信號
}

第二種:從機發(fā)送數(shù)據(jù),主機進行應(yīng)答

// 從機發(fā)送數(shù)據(jù),主機進行應(yīng)答,0表示應(yīng)答,1表示不應(yīng)答
void IIC_MasterACK(uint8_t ack)
{
  IIC_SDA_OutputMode();  // 設(shè)置SDA為輸出模式

  // 確保SCL和SDA都是低電平
  IIC_SCL_WRITE_DOWN();
  IIC_SDA_WRITE_DOWN();

  if (ack == 0) // 如果ack為0,表示主機應(yīng)答
  {
    IIC_SDA_WRITE_DOWN(); // SDA拉低
  }
  else // 如果ack為1,表示主機不應(yīng)答
  {
    IIC_SDA_WRITE_UP();   // SDA拉高
  }
  delay_us(5);  //  至此,應(yīng)答信號準(zhǔn)備完畢

  // 拉高SCL,主機發(fā)出應(yīng)答信號
  IIC_SCL_WRITE_UP();
  delay_us(5);  // 至此,應(yīng)答信號發(fā)送完畢

  // 拉低SCL,從機忽略數(shù)據(jù)
  IIC_SCL_WRITE_DOWN();
  delay_us(5);
}
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 集成電路
    +關(guān)注

    關(guān)注

    5371

    文章

    11248

    瀏覽量

    359735
  • mcu
    mcu
    +關(guān)注

    關(guān)注

    146

    文章

    16796

    瀏覽量

    349325
  • STM32
    +關(guān)注

    關(guān)注

    2262

    文章

    10846

    瀏覽量

    353676
  • 總線
    +關(guān)注

    關(guān)注

    10

    文章

    2848

    瀏覽量

    87839
  • IIC
    IIC
    +關(guān)注

    關(guān)注

    11

    文章

    293

    瀏覽量

    38206
收藏 人收藏

    評論

    相關(guān)推薦

    在FreeRTOS操作系統(tǒng)下的使用軟件模擬IIC的驅(qū)動例程

    STM32軟件模擬IIC驅(qū)動的設(shè)計概述定義一個IIC設(shè)備II
    發(fā)表于 08-24 06:13

    STM32軟件模擬IIC實現(xiàn)

    STM32軟件模擬IICIIC硬件連接模擬I2C 的GPIO配置IIC協(xié)議模擬
    發(fā)表于 01-19 07:49

    軟件模擬stm32IIC和硬件stm32IIC有何區(qū)別呢

    怎樣使用IO口進行stm32IIC傳輸呢?軟件模擬stm32IIC和硬件
    發(fā)表于 02-11 06:05

    STM32 IIC和USART接口的基礎(chǔ)知識點匯總,絕對實用

    STM32 IIC和USART接口的基礎(chǔ)知識點匯總,絕對實用
    發(fā)表于 02-22 08:00

    IO模擬IIC通訊

    IO模擬IIC通訊1.STM32使用軟件IIC原因由于STM32的硬件
    發(fā)表于 03-01 06:20

    STM32軟件模擬IIC和硬件IIC有什么區(qū)別?

    STM32軟件模擬IIC和硬件IIC有什么區(qū)別
    發(fā)表于 10-10 06:09

    介紹IIC總線特點與STM32 IIC:為ARM初學(xué)者導(dǎo)航(11)

    、ACK和NACK 4、設(shè)備地址 5、內(nèi)部地址 四 STM32 IIC介紹 1、介紹 2、主要特性 五 STM32 IIC功能描述 1、
    的頭像 發(fā)表于 07-02 10:07 ?5784次閱讀

    STM32F103 模擬IIC時序

    STM32F103 模擬IIC時序
    發(fā)表于 11-25 09:51 ?34次下載
    <b class='flag-5'>STM32</b>F103  <b class='flag-5'>模擬</b><b class='flag-5'>IIC</b>時序

    STM32入門開發(fā): 介紹IIC總線、讀寫AT24C02(EEPROM)(采用模擬時序)

    一、環(huán)境介紹編程軟件: keil5操作系統(tǒng): win10MCU型號: STM32F103ZET6STM32編程方式: 寄存器開發(fā) (方便程序移植到其他單片機)IIC總線:STM32本身
    發(fā)表于 11-25 20:06 ?39次下載
    <b class='flag-5'>STM32</b>入門開發(fā): 介紹<b class='flag-5'>IIC</b>總線、讀寫AT24C02(EEPROM)(采用<b class='flag-5'>模擬</b>時序)

    實現(xiàn)模擬IIC與EEPROM(24c02)通信(基于STM32F103ZET6)

    一句話梳理流程stm32模擬硬件IIC時序,按照時序,EEPROM識別外部信號,完成對其的數(shù)據(jù)操作目的:使用32開發(fā)板軟件模擬
    發(fā)表于 12-14 18:39 ?16次下載
    實現(xiàn)<b class='flag-5'>模擬</b><b class='flag-5'>IIC</b>與EEPROM(24c02)通信(基于<b class='flag-5'>STM32</b>F103ZET6)

    STC——IIC外設(shè)使用及模擬IIC

    目錄1、使用配置流程2、相關(guān)寄存器3、代碼4、GPIO模擬IIC1、使用配置流程IIC協(xié)議描述初始化iic將EAXFR(P_SW2最高位)置1設(shè)置i
    發(fā)表于 12-23 19:51 ?16次下載
    STC——<b class='flag-5'>IIC</b>外設(shè)使用及<b class='flag-5'>模擬</b><b class='flag-5'>IIC</b>

    IIC實測波形入手,搞懂IIC通信

    IIC的通信原理。1 IIC基礎(chǔ)知識首先復(fù)習(xí)一下IIC基礎(chǔ)知識,這部分看不懂的請先帶著疑問,然后我們通過分析
    發(fā)表于 01-12 17:35 ?9次下載
    從<b class='flag-5'>IIC</b>實測波形入手,搞懂<b class='flag-5'>IIC</b>通信

    [轉(zhuǎn)]從IIC實測波形入手,搞懂IIC通信

    IIC的通信原理。1 IIC基礎(chǔ)知識首先復(fù)習(xí)一下IIC基礎(chǔ)知識,這部分看不懂的請先帶著疑問,然后我們通過分析
    發(fā)表于 01-12 17:59 ?17次下載
    [轉(zhuǎn)]從<b class='flag-5'>IIC</b>實測波形入手,搞懂<b class='flag-5'>IIC</b>通信

    STM32IIC通信原理詳解

    本文將介紹STM32 IIC的通信原理和協(xié)議。
    的頭像 發(fā)表于 04-25 09:51 ?4130次閱讀
    <b class='flag-5'>STM32</b>的<b class='flag-5'>IIC</b>通信原理詳解

    MSP430F5529軟件模擬IIC協(xié)議

    MSP430F5529軟件模擬IIC協(xié)議
    發(fā)表于 11-24 16:35 ?0次下載