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

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

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

軟件模擬I2C從機(jī)的實(shí)現(xiàn)方法及注意事項(xiàng)

CHANBAEK ? 來(lái)源:固件工人 ? 作者:固件工人 ? 2023-01-17 14:56 ? 次閱讀

1.1 前言

在使用I2C通信時(shí),一般會(huì)用到軟件模擬I2C。目前網(wǎng)絡(luò)上能搜索到的軟件模擬I2C一般都是模擬I2C主機(jī),很少有模擬I2C從機(jī)的例程。由于I2C主機(jī)在進(jìn)行數(shù)據(jù)收發(fā)時(shí),有明確的可預(yù)見(jiàn)性,也就是主機(jī)明確知道什么時(shí)候要進(jìn)行數(shù)據(jù)的收發(fā)操作,而且I2C的同步時(shí)鐘信號(hào)也是由主機(jī)產(chǎn)生的,所以實(shí)現(xiàn)起來(lái)相對(duì)來(lái)說(shuō)比較簡(jiǎn)單。而I2C從機(jī)的通信受制于主機(jī),即什么時(shí)候需要進(jìn)行數(shù)據(jù)的收發(fā)都是由主機(jī)發(fā)起的,數(shù)據(jù)收發(fā)的發(fā)起時(shí)機(jī)具有隨機(jī)性,所以實(shí)現(xiàn)方法不能參照軟件模擬I2C主機(jī)那樣使用單純的軟件查詢狀態(tài)的方法。由于實(shí)際使用時(shí),MCU的固件還會(huì)執(zhí)行其他的操作,所以如果單純使用軟件查詢的方法來(lái)判斷I2C通信的起始信號(hào)不太現(xiàn)實(shí)。這里提供一種軟件模擬I2C從機(jī)的實(shí)現(xiàn)方法,考慮使用GPIO中斷的方法來(lái)及時(shí)接收I2C通信的起始信號(hào),并進(jìn)行數(shù)據(jù)的收發(fā)。

1.2 測(cè)試平臺(tái)

這里使用的開(kāi)發(fā)環(huán)境和相關(guān)硬件如下。

  • 操作系統(tǒng):Ubuntu 20.04.2 LTS x86_64(使用uname -a命令查看)
  • 集成開(kāi)發(fā)環(huán)境(IDE):Eclipse IDE for Embedded C/C++ Developers,Version: 2021-06 (4.20.0)
  • 硬件開(kāi)發(fā)板:STM32F429I-DISCO
  • 本文對(duì)應(yīng)的例程代碼鏈接如下。

https://download.csdn.net/download/goodrenze/85272480

1.3 軟件模擬I2C從機(jī)實(shí)現(xiàn)方法

這里結(jié)合開(kāi)發(fā)板STM32F429I-DISCO上的STM32F429ZI的單片機(jī)來(lái)演示軟件模擬I2C從機(jī)的實(shí)現(xiàn)方法。

I2C通信的時(shí)序圖如下圖1所示。

圖1 I2C通信時(shí)序圖

I2C通信的時(shí)序中關(guān)鍵的幾個(gè)點(diǎn)如下。

1)START和ReSTART信號(hào):用于標(biāo)識(shí)I2C通信的開(kāi)始,時(shí)序特點(diǎn)是SCL為高電平的時(shí)候,SDA從高電平變成低電平。

2)STOP信號(hào):用于標(biāo)識(shí)I2C通信的結(jié)束,時(shí)序特點(diǎn)是SCL為高電平的時(shí)候,SDA從低電平變成高電平。

3)應(yīng)答信號(hào):I2C通信每傳輸完8個(gè)比特的數(shù)據(jù)位后,緊接著需要傳輸應(yīng)答標(biāo)志位,當(dāng)該位為0時(shí),是ACK應(yīng)答信號(hào),該位為1時(shí),是NACK無(wú)應(yīng)答信號(hào)。應(yīng)答信號(hào)在SCL的第9個(gè)時(shí)鐘周期的位置。

4)數(shù)據(jù)采集時(shí)刻:I2C通信的數(shù)據(jù)在SCL的上升沿進(jìn)行采集確認(rèn),所以在SCL的高電平期間,數(shù)據(jù)必須保持不變,防止數(shù)據(jù)采集出錯(cuò)。當(dāng)然,START信號(hào)和STOP信號(hào)的時(shí)序在SCL高電平期間是特殊情況,具有專門(mén)的含義。

5)數(shù)據(jù)更新時(shí)刻:I2C通信的數(shù)據(jù)更新需要在SCL為低電平的時(shí)候進(jìn)行。

通過(guò)以上幾個(gè)關(guān)鍵點(diǎn),軟件模擬I2C從機(jī)的基本思路就有了。由于各個(gè)關(guān)鍵點(diǎn)基本都發(fā)生在SCL或SDA的上升沿或者下降沿的地方,所以可以將用于模擬I2C通信引腳的GPIO口配置成邊沿中斷,這樣就可以通過(guò)中斷實(shí)時(shí)抓取邊沿信號(hào),并在中斷中進(jìn)行及時(shí)的數(shù)據(jù)處理。使用GPIO的邊沿中斷來(lái)模擬I2C從機(jī)的好處是可以實(shí)時(shí)獲取到START和STOP信號(hào),I2C主機(jī)發(fā)過(guò)來(lái)的數(shù)據(jù)可以通過(guò)中斷得到及時(shí)處理,而且程序主流程無(wú)需關(guān)心模擬I2C從機(jī)的相關(guān)處理,可以處理其他事務(wù)。

因?yàn)槭荌2C從機(jī),所以SCL引腳直接固定成輸入引腳即可,而SDA信號(hào)由于是雙向的,所以需要根據(jù)I2C通信中的各個(gè)狀態(tài)來(lái)設(shè)置輸入或輸出方向。另外,由于GPIO中斷只在GPIO配置成輸入時(shí)才會(huì)產(chǎn)生,所以默認(rèn)情況下,SDA必須設(shè)置成輸入引腳。

程序的具體設(shè)計(jì)思路如下。

1)將SCL和SDA引腳設(shè)置成GPIO的邊沿中斷模式,默認(rèn)為輸入引腳。I2C通信狀態(tài)機(jī)設(shè)置成默認(rèn)的IDLE狀態(tài)。SCL的中斷用于處理數(shù)據(jù)的收發(fā),SDA的中斷只用于START/ReSTART/STOP這些特殊信號(hào)的判斷。

2)SDA引腳中斷處理思路:發(fā)生下降沿中斷,并且SCL為高電平,則收到START信號(hào),狀態(tài)機(jī)更新成START狀態(tài);發(fā)生上升沿中斷,并且SCL為高電平,則收到STOP信號(hào),緊接著I2C通信就應(yīng)該處于空閑狀態(tài),所以這里直接將狀態(tài)機(jī)設(shè)置成IDLE狀態(tài)。

3)SCL引腳中斷處理思路:

A. 發(fā)生下降沿中斷時(shí)

A1. 如果狀態(tài)機(jī)為START狀態(tài),則I2C通信正式開(kāi)始,準(zhǔn)備開(kāi)始接收設(shè)備地址,狀態(tài)機(jī)更新成DATA狀態(tài)。

A2. 如果狀態(tài)機(jī)為DATA狀態(tài),SCL下降沿計(jì)數(shù)小于8時(shí),如果是主機(jī)讀取數(shù)據(jù),則更新SDA的位數(shù)據(jù)輸出。SCL下降沿計(jì)數(shù)等于8時(shí),進(jìn)入應(yīng)答階段,狀態(tài)機(jī)更新成ACK狀態(tài);如果是主機(jī)寫(xiě)入數(shù)據(jù),并且是設(shè)備地址數(shù)據(jù),則判斷設(shè)備地址是否匹配,如果設(shè)備地址匹配,則將SDA設(shè)置成輸出,并輸出ACK信號(hào),否則如果地址不匹配,則SDA保持為輸入狀態(tài),不輸出ACK信號(hào);如果是主機(jī)讀取數(shù)據(jù),將SDA設(shè)置成輸入,準(zhǔn)備接收主機(jī)的應(yīng)答信號(hào)。

A3. 如果狀態(tài)機(jī)為ACK狀態(tài),這時(shí)應(yīng)答信號(hào)已經(jīng)傳輸完畢,狀態(tài)機(jī)更新成DATA狀態(tài),準(zhǔn)備繼續(xù)接收或發(fā)送數(shù)據(jù)。如果是主機(jī)寫(xiě)入數(shù)據(jù),將SDA設(shè)置成輸入,繼續(xù)接收后續(xù)數(shù)據(jù);如果是主機(jī)讀取數(shù)據(jù),將SDA設(shè)置成輸出,繼續(xù)發(fā)送后續(xù)數(shù)據(jù)。

A4. 如果狀態(tài)機(jī)為NACK狀態(tài),說(shuō)明緊接著I2C通信將停止或重新啟動(dòng),準(zhǔn)備接收STOP或者ReSTART信號(hào),所以需要將SDA設(shè)置成輸入。此時(shí)狀態(tài)機(jī)狀態(tài)保持不變。

B. 發(fā)生上升沿中斷時(shí)

B1. 如果狀態(tài)機(jī)為DATA狀態(tài),I2C通信處于數(shù)據(jù)階段,如果是主機(jī)寫(xiě)入數(shù)據(jù),則采集主機(jī)通過(guò)SDA發(fā)送過(guò)來(lái)的位數(shù)據(jù)。

B2. 如果狀態(tài)機(jī)為ACK狀態(tài),I2C通信處于應(yīng)答階段,如果是主機(jī)讀取數(shù)據(jù),則采集主機(jī)的應(yīng)答信號(hào),如果主機(jī)應(yīng)答信號(hào)為1,說(shuō)明主機(jī)發(fā)送了NACK的應(yīng)答,狀態(tài)機(jī)需要更新成NACK狀態(tài),準(zhǔn)備接收停止或重新啟動(dòng)信號(hào)。

1.4 軟件模擬I2C從機(jī)的代碼實(shí)現(xiàn)

根據(jù)上面的程序思路,可以開(kāi)始進(jìn)行程序代碼的設(shè)計(jì),步驟如下。

1)設(shè)計(jì)I2C從機(jī)通信對(duì)應(yīng)的結(jié)構(gòu)體,I2C通信狀態(tài)定義,I2C通信相關(guān)的宏定義的聲明。部分代碼如下。

// ...
#define SW_SLAVE_ADDR      0xA2


#define SW_SLAVE_SCL_CLK_EN()  __HAL_RCC_GPIOB_CLK_ENABLE()
#define SW_SLAVE_SDA_CLK_EN()  __HAL_RCC_GPIOB_CLK_ENABLE()


#define SW_SLAVE_SCL_PRT    GPIOB
#define SW_SLAVE_SCL_PIN    GPIO_PIN_6
#define SW_SLAVE_SDA_PRT    GPIOB
#define SW_SLAVE_SDA_PIN    GPIO_PIN_7


#define GPIO_MODE_MSK           0x00000003U


#define I2C_STA_IDLE      0
#define I2C_STA_START      1
#define I2C_STA_DATA      2
#define I2C_STA_ACK        3
#define I2C_STA_NACK      4
#define I2C_STA_STOP      5


#define I2C_READ        1
#define I2C_WRITE        0


#define GPIO_DIR_IN        0
#define GPIO_DIR_OUT      1
// ...
typedef struct _SwSlaveI2C_t
{
  uint8_t State;          // I2C通信狀態(tài)
  uint8_t Rw;            // I2C讀寫(xiě)標(biāo)志:0-寫(xiě),1-讀
  uint8_t SclFallCnt;        // SCL下降沿計(jì)數(shù)
  uint8_t Flag;          // I2C狀態(tài)標(biāo)志,BIT0:0-地址無(wú)效,1-地址匹配
  uint32_t StartMs;        // I2C通信起始時(shí)間,單位ms,用于判斷通信是否超時(shí)
  uint8_t* RxBuf;          // 指向接收緩沖區(qū)的指針
  uint8_t* TxBuf;          // 指向發(fā)送緩沖區(qū)的指針
  uint8_t RxIdx;          // 接收緩沖區(qū)數(shù)據(jù)寫(xiě)入索引,最大值255
  uint8_t TxIdx;          // 發(fā)送緩沖區(qū)數(shù)據(jù)讀取索引,最大值255
}SwSlaveI2C_t;


extern SwSlaveI2C_t SwSlaveI2C;
// ...

2)I2C通信引腳SCL/SDA對(duì)應(yīng)的GPIO的初始化。這里使用PB6/PB7引腳。代碼如下。

void InitSwSlaveI2C(void)
{
  GPIO_InitTypeDef   GPIO_InitStructure;


  /* Enable I2C GPIO clock */
  SW_SLAVE_SCL_CLK_EN();
  SW_SLAVE_SDA_CLK_EN();


  /* Configure SCL GPIO pin */
  GPIO_InitStructure.Pin       = SW_SLAVE_SCL_PIN;
  GPIO_InitStructure.Mode      = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStructure.Pull      = GPIO_PULLUP;
  GPIO_InitStructure.Speed     = GPIO_SPEED_FAST;
  HAL_GPIO_Init(SW_SLAVE_SCL_PRT, &GPIO_InitStructure);


  /* Configure SDA GPIO pin */
  GPIO_InitStructure.Pin       = SW_SLAVE_SDA_PIN;
  HAL_GPIO_Init(SW_SLAVE_SDA_PRT, &GPIO_InitStructure);


  /* Configure SCL GPIO pin as input interruption with pull up */
  GPIO_InitStructure.Pin       = SW_SLAVE_SCL_PIN;
  GPIO_InitStructure.Mode      = GPIO_MODE_IT_RISING_FALLING;
  HAL_GPIO_Init(SW_SLAVE_SCL_PRT, &GPIO_InitStructure);


  /* Configure SDA GPIO pin as input interruption with pull up */
  GPIO_InitStructure.Pin       = SW_SLAVE_SDA_PIN;
  HAL_GPIO_Init(SW_SLAVE_SDA_PRT, &GPIO_InitStructure);


  /* Enable and set EXTI Line9_5 Interrupt to the highest priority */
  HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
}

3)由于SCL/SDA引腳被設(shè)置成中斷引腳,需要實(shí)現(xiàn)GPIO的中斷處理函數(shù)。中斷處理函數(shù)中已經(jīng)包含了軟件模擬I2C從機(jī)的所有功能。代碼如下。

void EXTI9_5_IRQHandler(void)
{
  I2cGpioIsr();
}


void I2cGpioIsr(void)
{
  uint32_t temp;


  // 處理SCL的上下沿中斷
  if(__HAL_GPIO_EXTI_GET_IT(SW_SLAVE_SCL_PIN) != RESET)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(SW_SLAVE_SCL_PIN);
    // 更新通信起始時(shí)間
    SwSlaveI2C.StartMs = HAL_GetTick();
    // SCL的下降沿事件處理,此時(shí)需要更新要傳輸?shù)臄?shù)據(jù)
    if((SW_SLAVE_SCL_PRT->IDR & SW_SLAVE_SCL_PIN) == (uint32_t)GPIO_PIN_RESET)
    {
      switch(SwSlaveI2C.State)
      {
        case I2C_STA_START:    // 起始信號(hào)的下降沿,初始化相關(guān)參數(shù)并轉(zhuǎn)到接收比特?cái)?shù)據(jù)狀態(tài)
          SwSlaveI2C.SclFallCnt = 0;
          SwSlaveI2C.RxIdx = 0;
          SwSlaveI2C.TxIdx = 0;
          SwSlaveI2C.Flag = 0;  // 默認(rèn)地址不匹配
          SwSlaveI2C.RxBuf[SwSlaveI2C.RxIdx] = 0;
          SwSlaveI2C.Rw = I2C_WRITE;  // 第1字節(jié)為設(shè)備地址,一定是寫(xiě)入
          SwSlaveI2C.State = I2C_STA_DATA;
          break;
        case I2C_STA_DATA:
          SwSlaveI2C.SclFallCnt++;
          if(8 > SwSlaveI2C.SclFallCnt)
          {
            // 如果是主機(jī)讀取數(shù)據(jù),則在SCL低電平時(shí)更新比特?cái)?shù)據(jù)
            if(SwSlaveI2C.Rw == I2C_READ)
            {
              if(SwSlaveI2C.TxBuf[SwSlaveI2C.TxIdx] & (1 << (7 - SwSlaveI2C.SclFallCnt)))
              {
                SET_SDA_PIN();
              }
              else
              {
                CLR_SDA_PIN();
              }
            }
          }
          else if(8 == SwSlaveI2C.SclFallCnt)
          {
            if(SwSlaveI2C.Rw == I2C_WRITE)
            {
              // 從第一個(gè)地址字節(jié)中獲取讀寫(xiě)標(biāo)志位,并判斷地址是否匹配
              if(SwSlaveI2C.RxIdx == 0)
              {
                if((SwSlaveI2C.RxBuf[0] & 0xFE) == SW_SLAVE_ADDR)
                {
                  SwSlaveI2C.Flag = 1;  // 地址匹配
                  SwSlaveI2C.Rw = SwSlaveI2C.RxBuf[0] & 0x01;
                }
              }
              if(SwSlaveI2C.Flag)
              {
                // 如果是主機(jī)寫(xiě)入數(shù)據(jù),且地址匹配,則接收完8比特?cái)?shù)據(jù)后,需要發(fā)送ACK信號(hào)進(jìn)行應(yīng)答
                SET_SDA_DIR(temp, GPIO_DIR_OUT);
                CLR_SDA_PIN();
              }
            }
            else
            {
              // 如果是主機(jī)讀取數(shù)據(jù),需要將SDA設(shè)置成輸入以便判斷應(yīng)答標(biāo)志位狀態(tài)
              SET_SDA_DIR(temp, GPIO_DIR_IN);
              // 如果是主機(jī)讀取數(shù)據(jù),準(zhǔn)備發(fā)送下一個(gè)字節(jié)的數(shù)據(jù)
              SwSlaveI2C.TxIdx++;
            }
            // 接收或發(fā)送完8比特?cái)?shù)據(jù)后,準(zhǔn)備發(fā)送或接收應(yīng)答信號(hào)
            SwSlaveI2C.State = I2C_STA_ACK;
          }
          break;
        case I2C_STA_ACK:
          SwSlaveI2C.SclFallCnt = 0;
          if(SwSlaveI2C.Rw == I2C_WRITE)
          {
            // 如果是主機(jī)寫(xiě)入數(shù)據(jù),且ACK發(fā)送完畢,則SDA設(shè)置成輸入,繼續(xù)接收數(shù)據(jù)
            SET_SDA_DIR(temp, GPIO_DIR_IN);
            SwSlaveI2C.RxIdx++;
            SwSlaveI2C.RxBuf[SwSlaveI2C.RxIdx] = 0;
          }
          else
          {
            // 如果是主機(jī)讀取數(shù)據(jù),且ACK接收完畢,則SDA設(shè)置成輸出,繼續(xù)發(fā)送數(shù)據(jù)
            SET_SDA_DIR(temp, GPIO_DIR_OUT);
            if(SwSlaveI2C.TxBuf[SwSlaveI2C.TxIdx] & 0x80)
            {
              SET_SDA_PIN();
            }
            else
            {
              CLR_SDA_PIN();
            }
          }
          SwSlaveI2C.State = I2C_STA_DATA;
          break;
        case I2C_STA_NACK:    // 如果收到了NACK,則后面將是STOP或者ReSTART信號(hào),需要將SDA設(shè)置成輸入
          SwSlaveI2C.SclFallCnt = 0;
          SET_SDA_DIR(temp, GPIO_DIR_IN);
          break;
      }
    }
    // SCL的上升沿事件處理,此時(shí)需要采集數(shù)據(jù),而且在數(shù)據(jù)階段,SCL高電平時(shí)數(shù)據(jù)必須保持不變
    else
    {
      switch(SwSlaveI2C.State)
      {
        case I2C_STA_DATA:  // 數(shù)據(jù)階段,如果是主機(jī)寫(xiě)入數(shù)據(jù),則采集比特?cái)?shù)據(jù)
          if((I2C_WRITE == SwSlaveI2C.Rw) && (8 > SwSlaveI2C.SclFallCnt))
          {
            if(SW_SLAVE_SDA_PRT->IDR & SW_SLAVE_SDA_PIN)
            {
              SwSlaveI2C.RxBuf[SwSlaveI2C.RxIdx] |= (1 << (7 - SwSlaveI2C.SclFallCnt));
            }
          }
          break;
        case I2C_STA_ACK:  // 應(yīng)答階段,如果是主機(jī)讀取數(shù)據(jù),則判斷ACK/NACK信號(hào),默認(rèn)狀態(tài)是ACK
          if((SwSlaveI2C.Rw == I2C_READ) && (SW_SLAVE_SDA_PRT->IDR & SW_SLAVE_SDA_PIN))
          {
            SwSlaveI2C.State = I2C_STA_NACK;
          }
          break;
      }
    }
  }
  else if(__HAL_GPIO_EXTI_GET_IT(SW_SLAVE_SDA_PIN) != RESET)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(SW_SLAVE_SDA_PIN);
    if((SW_SLAVE_SDA_PRT->IDR & SW_SLAVE_SDA_PIN) == (uint32_t)GPIO_PIN_RESET)
    {
      // SCL為高電平時(shí),SDA從高變低,說(shuō)明是起始信號(hào)
      if(SW_SLAVE_SCL_PRT->IDR & SW_SLAVE_SCL_PIN)
      {
        SwSlaveI2C.State = I2C_STA_START;
      }
    }
    else
    {
      // SCL為高電平時(shí),SDA從低變高,說(shuō)明是停止信號(hào),一次I2C通信結(jié)束,直接將狀態(tài)設(shè)置成空閑
      if(SW_SLAVE_SCL_PRT->IDR & SW_SLAVE_SCL_PIN)
      {
        SwSlaveI2C.State = I2C_STA_IDLE;
      }
    }
  }
}

4)為了確保模擬I2C從機(jī)通信的可靠性,額外設(shè)計(jì)了I2C通信超時(shí)處理函數(shù)。在I2C通信進(jìn)行的過(guò)程中,如果通信出現(xiàn)了中斷,則通過(guò)超時(shí)判斷來(lái)重置I2C從機(jī)狀態(tài),確保出現(xiàn)通信異常時(shí)可以從異常狀態(tài)中自動(dòng)恢復(fù)。該函數(shù)需要在主流程中調(diào)用。代碼如下。

void CheckSwSlaveI2cTimeout(void)
{
  uint32_t TimeMs, TimeCurMs;


  if(SwSlaveI2C.State != I2C_STA_IDLE)
  {
    TimeCurMs = HAL_GetTick();
    if(TimeCurMs >= SwSlaveI2C.StartMs)
    {
      TimeMs = TimeCurMs - SwSlaveI2C.StartMs;
    }
    else
    {
      TimeMs = ~(SwSlaveI2C.StartMs - TimeCurMs) + 1;
    }
    if(500 <= TimeMs)
    {
      // I2C通信超時(shí)的話,重置狀態(tài)機(jī),并把SDA設(shè)置成輸入
      SwSlaveI2C.State = I2C_STA_IDLE;
      SET_SDA_DIR(TimeMs, GPIO_DIR_IN);
    }
  }
}

5)軟件模擬I2C從機(jī)相關(guān)功能驗(yàn)證代碼。這里需要借助STM32的另外一個(gè)I2C主機(jī)進(jìn)行配合測(cè)試。這里將PF0/PF1對(duì)應(yīng)的引腳配置成I2C主機(jī),主機(jī)直接使用STM32的硬件I2C實(shí)現(xiàn)。PF0/PF1分別和PB7/PB6連接,然后驗(yàn)證數(shù)據(jù)收發(fā)的正確性。具體代碼參見(jiàn)上面的工程鏈接。這里只展示最終的測(cè)試結(jié)果數(shù)據(jù)。如下圖所示。

軟件模擬I2C從機(jī)狀態(tài)

I2C主機(jī)發(fā)送數(shù)據(jù)

軟件模擬I2C從機(jī)接收數(shù)據(jù)

圖2 軟件模擬I2C從機(jī)數(shù)據(jù)接收驗(yàn)證結(jié)果

軟件模擬I2C從機(jī)狀態(tài)

軟件模擬I2C從機(jī)發(fā)送數(shù)據(jù)

I2C主機(jī)接收數(shù)據(jù)

圖3 軟件模擬I2C從機(jī)數(shù)據(jù)發(fā)送驗(yàn)證結(jié)果

1.5 軟件模擬I2C從機(jī)的注意事項(xiàng)

本例程中,對(duì)于400kbps速率的I2C通信,在進(jìn)行代碼編譯鏈接時(shí),需要使用-Ofast的優(yōu)化方式,以提高中斷處理函數(shù)的執(zhí)行速度,使程序能正確執(zhí)行。如果使用默認(rèn)的無(wú)優(yōu)化配置,會(huì)造成程序無(wú)法正確運(yùn)行。

對(duì)于主頻比較低的MCU,使用這里提供的軟件模擬I2C從機(jī)進(jìn)行I2C通信時(shí),建議使用100kpbs以下的通信速率,并且注意使用可以提高代碼執(zhí)行速度的代碼優(yōu)化配置。

另外,建議將用于模擬SDA/SCL的GPIO引腳中斷優(yōu)先級(jí)設(shè)置成最高,以便能及時(shí)響應(yīng)I2C通信時(shí)序的中斷。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • mcu
    mcu
    +關(guān)注

    關(guān)注

    146

    文章

    16887

    瀏覽量

    349928
  • 主機(jī)
    +關(guān)注

    關(guān)注

    0

    文章

    982

    瀏覽量

    35008
  • I2C
    I2C
    +關(guān)注

    關(guān)注

    28

    文章

    1477

    瀏覽量

    123059
  • 軟件模擬
    +關(guān)注

    關(guān)注

    0

    文章

    8

    瀏覽量

    7217
  • 從機(jī)
    +關(guān)注

    關(guān)注

    0

    文章

    3

    瀏覽量

    850
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    GPIO模擬I2C總線的驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)

    I2C總線簡(jiǎn)單方便,是我們經(jīng)常使用的一種總線。但有時(shí)候我們的MCU沒(méi)有足夠多的I2C控制器來(lái)實(shí)現(xiàn)我們的應(yīng)用,所幸我可以使用普通的GPIO引腳來(lái)模擬低速的
    發(fā)表于 12-14 14:19 ?5307次閱讀
    GPIO<b class='flag-5'>模擬</b><b class='flag-5'>I2C</b>總線的驅(qū)動(dòng)設(shè)計(jì)與<b class='flag-5'>實(shí)現(xiàn)</b>

    怎樣使用STM32的GPIO模擬I2C總線時(shí)序

    使用STM32的GPIO模擬I2C總線時(shí)序,GPIO設(shè)置為開(kāi)漏模式,SDA和SCK外部必須使用上拉電阻,一般是4.7K。開(kāi)漏模式的好處是,可以同時(shí)讀取輸入電平,而無(wú)需切換輸入/輸出模式。注意事項(xiàng):在
    發(fā)表于 02-22 06:48

    淺析I2C總線的工作原理與使用注意事項(xiàng)

    情況?! ?b class='flag-5'>I2C總線使用注意事項(xiàng)  當(dāng)使用I2C總線時(shí),除了遵循I2C總線規(guī)范,還需要注意以下幾個(gè)要點(diǎn):  1.
    發(fā)表于 03-08 14:06

    億恒C166 系列單片機(jī)I2C 總線的軟件模擬

    億恒C166 系列單片機(jī)I2C 總線的軟件模擬
    發(fā)表于 05-14 16:11 ?6次下載

    HT66F40使用SIM I2C Mode之用法與注意事項(xiàng)

    HT66F40使用SIM I2C Mode之用法與注意事項(xiàng)HT66F40 內(nèi)建有SIM 功能,其中包括了SPI 和I2C 這兩種功能,本文以HT66F40 為母體,介紹使用I2C 進(jìn)行
    發(fā)表于 03-27 08:37 ?17次下載

    HT56R678使用I2C進(jìn)行數(shù)據(jù)傳輸?shù)?b class='flag-5'>方法

    HT56R678使用I2C進(jìn)行數(shù)據(jù)傳輸?shù)?b class='flag-5'>方法HT56R678 內(nèi)建有SIM 功能,其中包括了SPI 和I2C 兩種通信接口,本文以HT56R678 為母體,介紹使用I2C 進(jìn)行數(shù)據(jù)傳輸
    發(fā)表于 03-28 22:39 ?7次下載

    模擬I2C總線多主節(jié)點(diǎn)通信原理及實(shí)現(xiàn)方法

    摘要 介紹模擬I2C總線的多主節(jié)點(diǎn)通信原理,并提出一種新的實(shí)現(xiàn)方法。這種采用延時(shí)接收比較來(lái)實(shí)現(xiàn)仲裁的方法
    發(fā)表于 06-18 17:57 ?5516次閱讀
    <b class='flag-5'>模擬</b><b class='flag-5'>I2C</b>總線多主節(jié)點(diǎn)通信原理及<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>方法</b>

    基于pic單片機(jī)模擬I2C通信

    基于pic單片機(jī)模擬I2C通信設(shè)計(jì)
    發(fā)表于 05-25 08:58 ?2443次閱讀

    軟件模擬I2C總線的C51實(shí)現(xiàn)

    軟件模擬I2C總線的C51實(shí)現(xiàn)
    發(fā)表于 10-13 11:03 ?8次下載
    <b class='flag-5'>軟件</b><b class='flag-5'>模擬</b><b class='flag-5'>I2C</b>總線的<b class='flag-5'>C</b>51<b class='flag-5'>實(shí)現(xiàn)</b>

    80C51單片機(jī)模擬I2C總線的主機(jī)程序分享

    I2C總線協(xié)議程序 在使用的過(guò)程中一定要注意時(shí)序、時(shí)間的問(wèn)題。 i2c.c /* I2C.c 標(biāo)準(zhǔn)80C51單
    發(fā)表于 12-05 15:39 ?3365次閱讀
    80<b class='flag-5'>C</b>51單片<b class='flag-5'>機(jī)</b><b class='flag-5'>模擬</b><b class='flag-5'>I2C</b>總線的主機(jī)程序分享

    STM32 通用GPIO模擬I2C實(shí)現(xiàn)

    STM32 模擬I2C實(shí)現(xiàn)#通用GPIO模擬I2C通信實(shí)現(xiàn)樣例1 GPIO初始化``#ifdef
    發(fā)表于 11-29 15:21 ?28次下載
    STM32 通用GPIO<b class='flag-5'>模擬</b><b class='flag-5'>I2C</b><b class='flag-5'>實(shí)現(xiàn)</b>

    硬件I2C模擬I2C

    硬件I2C對(duì)應(yīng)芯片上的I2C外設(shè),有相應(yīng)I2C驅(qū)動(dòng)電路,其所使用的I2C管腳也是專用的,因而效率要遠(yuǎn)高于軟件
    發(fā)表于 12-28 19:14 ?81次下載
    硬件<b class='flag-5'>I2C</b>與<b class='flag-5'>模擬</b><b class='flag-5'>I2C</b>

    經(jīng)過(guò)驗(yàn)證的GPIO模擬I2C時(shí)序代碼

    使用STM32的GPIO模擬I2C總線時(shí)序,GPIO設(shè)置為開(kāi)漏模式,SDA和SCK外部必須使用上拉電阻,一般是4.7K。開(kāi)漏模式的好處是,可以同時(shí)讀取輸入電平,而無(wú)需切換輸入/輸出模式。注意事項(xiàng):在
    發(fā)表于 12-28 19:36 ?13次下載
    經(jīng)過(guò)驗(yàn)證的GPIO<b class='flag-5'>模擬</b><b class='flag-5'>I2C</b>時(shí)序代碼

    可編程USB轉(zhuǎn) UART/I2C Wire常見(jiàn)問(wèn)題及注意事項(xiàng)

    可編程USB轉(zhuǎn) UART/I2C /SMBusS/SPI/CAN/1 -Wire適配器USB2S 常見(jiàn)問(wèn)題及注意事項(xiàng)
    的頭像 發(fā)表于 08-23 14:38 ?1412次閱讀

    I2C介紹及應(yīng)用注意事項(xiàng)

    中微愛(ài)芯電子有限公司的許多顯示驅(qū)動(dòng)芯片采用了類I2C接口,客戶可通過(guò)MCU與我司的顯示驅(qū)動(dòng)芯片進(jìn)行通信,類I2C總線具有低功耗、抗干擾強(qiáng)、傳輸距離長(zhǎng)等優(yōu)點(diǎn),相比于標(biāo)準(zhǔn)I2C,不需要尋址操作,操作更加簡(jiǎn)單。下面將對(duì)我司類
    的頭像 發(fā)表于 03-07 17:57 ?2060次閱讀