久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

標題: [原創]STM32硬件I2C和軟件模擬I2C實現對比 [打印本頁]

作者: miniBoss    時間: 2021-6-29 12:09
標題: [原創]STM32硬件I2C和軟件模擬I2C實現對比
一、  概述
    I2C是一種占用管腳少、傳送可靠和傳輸速率較好的低速總線,在嵌入式設備中被廣泛使用到。I2C 接口接收和發送數據,并將數據從串行轉換成并,或并轉換成串行。可以開啟或禁止中斷。接口通過數據引腳(SDA)和時鐘引腳(SCL)連接到I2C總線。允許連接到標準(高至100 kHz)或快速(高至400 kHz) I2C總線。
    STM32一般有2-3組硬件I2C,以STM32F103CB為例,其硬件I2C情況如下——
  
I2C編號
  
I2C名稱
對應管腳
1
I2C1
PB6, PB7
2
I2C2
PB10, PB11
所謂硬件I2C,即STM32芯片設計了SDA/SCL兩個管腳內部已符合觸發I2C的時序、協議、仲裁和定時等功能塊,軟件開發人員只需調用簡單的API即可方便使用I2C功能了。
    此外,由于硬件設計的原因,需要使用很多個I2C或不巧硬件I2C管腳被占用,此時就需要通過GPIO軟件模擬I2C,它是通過軟件來實現I2C的時序、協議、仲裁和定時等完整的機制。
    原理和概念部分不再贅述,大家很容易在網上找到各類相關資料進行了解和學習,今天我們詳細陳述具體實現過程和比較兩者的一些差異,主要以代碼作為表述形式。
二、   硬件I2C的實現
       硬件I2C調用的api接口均在stm32f10x_i2c.c文件中,通過這些API,我們需要實現
(1)  I2C的初始化;
(2)  I2C讀和寫的接口函數,供外部調用。
初始化代碼如下——
  
#define  CPS1848_I2C                    I2C2
  
  
#define  CHECK_BUSY(checkflag,busyendflag,dwCnt, dwTimeOut) \
  
    for (dwCnt =0; dwCnt< dwTimeOut;  dwCnt++)  \
  
    {   \
  
        if((checkflag) == (busyendflag))\
  
        {\
  
            break;\
  
        }\
  
    }
  
  
#define  CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut)    \
  
    if (dwBusyCount >= dwTimeOut)   \
  
    {    \
  
        return ERR_WAIT_BUSY;   \
  
}
  
  
  
//  I2C 外設(CPS1848)初始化
  
void  I2C_CPS1848_Init(BYTE ucBoardAddr)
  
{
  
    //GPIO初始化
  
    GPIO_InitTypeDef  GPIO_InitStructure;
  
    I2C_InitTypeDef  I2C_InitStructure;
  
  
    /* 使能與 I2Cx 引腳的GPIO的時鐘 */
  
     RCC_APB2PeriphClockCmd(CPS1848_I2C_SCL_GPIO_CLK |  CPS1848_I2C_SDA_GPIO_CLK, ENABLE);
  
    /* 使能 I2Cx 外設時鐘 */
  
    RCC_APB1PeriphClockCmd(CPS1848_I2C_CLK,  ENABLE);
  
  
    /* Reset I2Cx IP */
  
    RCC_APB1PeriphResetCmd(CPS1848_I2C_CLK,  ENABLE);
  
  
    /* Release reset signal of I2Cx IP */
  
    RCC_APB1PeriphResetCmd(CPS1848_I2C_CLK,  DISABLE);
  
  
    /* I2Cx_SCL */
  
    GPIO_InitStructure.GPIO_Pin   = CPS1848_I2C_SCL_PIN;
  
    GPIO_InitStructure.GPIO_Speed =  GPIO_Speed_50MHz;
  
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_OD;
  
    GPIO_Init(CPS1848_I2C_SCL_PORT,  &GPIO_InitStructure);
  
  
    /* I2Cx_SDA*/
  
    GPIO_InitStructure.GPIO_Pin   = CPS1848_I2C_SDA_PIN;
  
    GPIO_InitStructure.GPIO_Speed =  GPIO_Speed_50MHz;
  
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_OD;
  
    GPIO_Init(CPS1848_I2C_SDA_PORT,  &GPIO_InitStructure);
  
  
    //模式初始化
  
    /* I2Cx 配置 */
  
    I2C_InitStructure.I2C_Mode =  I2C_Mode_SMBusHost/*I2C_Mode_I2C */;
  
    /* 高電平數據穩定,低電平數據變化 SCL 時鐘線的占空比 */
  
    I2C_InitStructure.I2C_DutyCycle =  I2C_DutyCycle_2;
  
    I2C_InitStructure.I2C_OwnAddress1 =  (ucBoardAddr << 1);
  
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable  ;
  
    /* I2Cx的尋址模式 */
  
    I2C_InitStructure.I2C_AcknowledgedAddress  = I2C_AcknowledgedAddress_7bit;
  
    /* 通信速率 */
  
    I2C_InitStructure.I2C_ClockSpeed =  100000;  //Standard-mode devices at 100  Kbps
  
  
    /* I2Cx 初始化 */
  
    I2C_Init(CPS1848_I2C, &I2C_InitStructure);
  
  
    /* 使能 I2Cx 外設*/
  
    I2C_Cmd(CPS1848_I2C, ENABLE);
  
  
    /*使能或者失能指定的I2C應答功能*/
  
    I2C_AcknowledgeConfig(CPS1848_I2C,  ENABLE);
  
}
  
       I2C的讀操作實現如下——
  
BYTE  I2C_CPS1848_Read(uint8_t cps1848_index, uint32_t RegAddr, uint32_t *pdwData)
  
{
  
    volatile uint32_t i2cdata = 0;
  
    uint16_t NumByteToRead = 4;
  
  
    DWORD dwBusyCount = 0;
  
    const DWORD dwTimeOut = 1000;
  
  
    CHECK_POINTER_RET_ERR(pdwData);
  
  
    /* 等待busy */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_GetFlagStatus(CPS1848_I2C,  I2C_FLAG_BUSY), RESET, dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
    /* Enable Acknowledgement to be ready for  another reception
  
       necessary...*/
  
    I2C_AcknowledgeConfig(CPS1848_I2C,  ENABLE);
  
  
    /* 發送開始信號 */
  
    I2C_GenerateSTART(CPS1848_I2C, ENABLE);
  
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_MODE_SELECT), SUCCESS, dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
    /* 發送目標地址 : Reset the address bit0 for  write*/
  
    I2C_Send7bitAddress(CPS1848_I2C,  ((CPS1848_I2C_ADDR+cps1848_index) << 1), I2C_Direction_Transmitter);
  
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED),
  
                         SUCCESS,  dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
  
    /* 發送寄存器地址--8bit */
  
    I2C_SendData(CPS1848_I2C, ((RegAddr>>18)  & 0xff));
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_BYTE_TRANSMITTED), SUCCESS, dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
    /* 發送寄存器地址--8bit */
  
    I2C_SendData(CPS1848_I2C,  ((RegAddr>>10) & 0xff));
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_BYTE_TRANSMITTED), SUCCESS, dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
    /* 發送寄存器地址--8bit */
  
     I2C_SendData(CPS1848_I2C, ((RegAddr>>2) & 0xff));
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_BYTE_TRANSMITTED), SUCCESS, dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
  
    /* 開始讀取數據 */
  
    I2C_GenerateSTART(CPS1848_I2C, ENABLE);
  
  
    /* Test on EV5 and clear it */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_MODE_SELECT), SUCCESS, dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
    /* 發送讀取的地址: Set the address bit0 for read*/
  
    I2C_Send7bitAddress(CPS1848_I2C,  ((CPS1848_I2C_ADDR+cps1848_index) << 1) | 0x01,  I2C_Direction_Receiver);
  
  
    /* Test on EV6 and clear it */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED), SUCCESS, dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
    while(NumByteToRead--)
  
    {
  
        if (0 == NumByteToRead)
  
        {
  
            /* 最后一個數據了,發送非應答信號(Disable Acknowledgement),結束傳輸;*/
  
             I2C_AcknowledgeConfig(CPS1848_I2C, DISABLE);
  
            /* 發送停止位 */
  
            I2C_GenerateSTOP(CPS1848_I2C,  ENABLE);
  
        }
  
  
        /* Test on EV7 and clear it */
  
        dwBusyCount = 0;
  
         CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_BYTE_RECEIVED), SUCCESS, dwBusyCount, dwTimeOut);
  
        CHECK_WAIT_BUSY(dwBusyCount,  dwTimeOut);
  
        i2cdata = (i2cdata<<8) |  (I2C_ReceiveData(CPS1848_I2C));
  
    }
  
  
    *pdwData = i2cdata;
  
  
    /* Enable Acknowledgement to be ready for  another reception */
  
    I2C_AcknowledgeConfig(CPS1848_I2C,  ENABLE);
  
  
    return ERR_SUCCESS;
  
}
  
       I2C的寫操作實現如下——
  
BYTE  I2C_CPS1848_Write(uint8_t cps1848_index, uint32_t RegAddr, uint32_t RegData)
  
{
  
    DWORD dwBusyCount = 0;
  
    const DWORD dwTimeOut = 10000;
  
  
    /* 等待busy */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_GetFlagStatus(CPS1848_I2C,  I2C_FLAG_BUSY),
  
                         RESET, dwBusyCount,  dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
  
    /* 發送開始信號 */
  
    I2C_GenerateSTART(CPS1848_I2C, ENABLE);
  
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_MODE_SELECT),
  
                         SUCCESS,  dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
  
    /* 發送目標地址 */
  
    I2C_Send7bitAddress(CPS1848_I2C,  ((CPS1848_I2C_ADDR+cps1848_index) << 1), I2C_Direction_Transmitter);
  
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED),
  
                         SUCCESS,  dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
  
    /* 發送寄存器地址--8bit */
  
    I2C_SendData(CPS1848_I2C,  ((RegAddr>>18) & 0xff));
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_BYTE_TRANSMITTED),
  
                         SUCCESS,  dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
    /* 發送寄存器地址--8bit */
  
    I2C_SendData(CPS1848_I2C,  ((RegAddr>>10) & 0xff));
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_BYTE_TRANSMITTED),
  
                         SUCCESS,  dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
    /* 發送寄存器地址--8bit */
  
    I2C_SendData(CPS1848_I2C,  ((RegAddr>>2) & 0xff));
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_BYTE_TRANSMITTED),
  
                         SUCCESS,  dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
    /* 發送數據 */
  
    I2C_SendData(CPS1848_I2C,  ((RegData>>24) & 0xff));
  
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_BYTE_TRANSMITTED),
  
                         SUCCESS,  dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
    /* 發送數據 */
  
    I2C_SendData(CPS1848_I2C,  ((RegData>>16) & 0xff));
  
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_BYTE_TRANSMITTED),
  
                         SUCCESS, dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
    /* 發送數據 */
  
    I2C_SendData(CPS1848_I2C,  ((RegData>>8) & 0xff));
  
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_BYTE_TRANSMITTED),
  
                         SUCCESS,  dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
    /* 發送數據 */
  
    I2C_SendData(CPS1848_I2C, ((RegData)  & 0xff));
  
  
    /* 等待握手 */
  
    dwBusyCount = 0;
  
    CHECK_BUSY(I2C_CheckEvent(CPS1848_I2C,  I2C_EVENT_MASTER_BYTE_TRANSMITTED),
  
                         SUCCESS,  dwBusyCount, dwTimeOut);
  
    CHECK_WAIT_BUSY(dwBusyCount, dwTimeOut);
  
  
  
    /* 發送停止位 */
  
    I2C_GenerateSTOP(CPS1848_I2C, ENABLE);
  
  
    return ERR_SUCCESS;
  
}
  
  


三、  軟件模擬I2C的實現
       GPIO軟件模擬I2C的實現中,首先是初始化;其次,由于沒有現存的I2C時序、協議、控制等API接口,這些就需要我們根據I2C協議進行嚴格實現,具體詳見附件。

四、  兩者的差異
       硬件I2C實現很簡潔,且流程中延時、應答等機制都無需軟件參與,只需做好正確配置和調用即可;軟件模擬I2C的實現需要非常完備,且需要嚴格按照I2C協議進行編寫,嚴格控制延時、應答、判定等。
       了解兩者之間的差異,并且能夠實現兩種I2C的使用,會極大加深我們對于I2C的理解和熟練程度,非常有益。


C文件51hei下載: gpio_i2c_bsp.rar (1.31 KB, 下載次數: 50)

作者: miniBoss    時間: 2021-6-29 12:13
由于篇幅緣故,沒有將所有代碼貼在文中,而放在附件中了。




歡迎光臨 (http://www.zg4o1577.cn/bbs/) Powered by Discuz! X3.1
主站蜘蛛池模板: 高清不卡毛片 | 日韩高清国产一区在线 | 亚洲国产欧美在线 | 亚洲视频一区二区 | 高清一区二区 | 一级黄色毛片免费 | 涩涩视频在线看 | 91在线观看免费视频 | 亚洲一区二区日韩 | 久久精品黄色 | 久久久久久电影 | aaaaaaa片毛片免费观看 | 成人av色| 五月激情婷婷六月 | 91精品国产乱码久久久久久 | 欧美在线视频网站 | 欧美极品在线视频 | 成人免费淫片aa视频免费 | 久久一 | 国产欧美精品一区二区三区 | 精品国产不卡一区二区三区 | 午夜码电影 | 国产在线精品一区二区三区 | 久久久激情视频 | 日韩欧美中文字幕在线观看 | 国产农村一级国产农村 | 亚洲国产福利视频 | 国产成人免费视频网站视频社区 | 欧美日韩一区二区电影 | 精品一区二区三区在线观看国产 | aacc678成免费人电影网站 | 久久久婷婷 | 一区二区三区四区不卡视频 | 婷婷综合激情 | 99国产精品久久久久老师 | 在线国产一区二区 | 国产在线中文字幕 | 伊大人久久 | 欧美在线a| 久久久久亚洲精品 | 日韩激情一区 |