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

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 5959|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

[原創(chuàng)]STM32硬件I2C和軟件模擬I2C實(shí)現(xiàn)對(duì)比

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
一、  概述
    I2C是一種占用管腳少、傳送可靠和傳輸速率較好的低速總線,在嵌入式設(shè)備中被廣泛使用到。I2C 接口接收和發(fā)送數(shù)據(jù),并將數(shù)據(jù)從串行轉(zhuǎn)換成并,或并轉(zhuǎn)換成串行。可以開啟或禁止中斷。接口通過數(shù)據(jù)引腳(SDA)和時(shí)鐘引腳(SCL)連接到I2C總線。允許連接到標(biāo)準(zhǔn)(高至100 kHz)或快速(高至400 kHz) I2C總線。
    STM32一般有2-3組硬件I2C,以STM32F103CB為例,其硬件I2C情況如下——
  
I2C編號(hào)
  
I2C名稱
對(duì)應(yīng)管腳
1
I2C1
PB6, PB7
2
I2C2
PB10, PB11
所謂硬件I2C,即STM32芯片設(shè)計(jì)了SDA/SCL兩個(gè)管腳內(nèi)部已符合觸發(fā)I2C的時(shí)序、協(xié)議、仲裁和定時(shí)等功能塊,軟件開發(fā)人員只需調(diào)用簡(jiǎn)單的API即可方便使用I2C功能了。
    此外,由于硬件設(shè)計(jì)的原因,需要使用很多個(gè)I2C或不巧硬件I2C管腳被占用,此時(shí)就需要通過GPIO軟件模擬I2C,它是通過軟件來實(shí)現(xiàn)I2C的時(shí)序、協(xié)議、仲裁和定時(shí)等完整的機(jī)制。
    原理和概念部分不再贅述,大家很容易在網(wǎng)上找到各類相關(guān)資料進(jìn)行了解和學(xué)習(xí),今天我們?cè)敿?xì)陳述具體實(shí)現(xiàn)過程和比較兩者的一些差異,主要以代碼作為表述形式。
二、   硬件I2C的實(shí)現(xiàn)
       硬件I2C調(diào)用的api接口均在stm32f10x_i2c.c文件中,通過這些API,我們需要實(shí)現(xiàn)
(1)  I2C的初始化;
(2)  I2C讀和寫的接口函數(shù),供外部調(diào)用。
初始化代碼如下——
  
#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 外設(shè)(CPS1848)初始化
  
void  I2C_CPS1848_Init(BYTE ucBoardAddr)
  
{
  
    //GPIO初始化
  
    GPIO_InitTypeDef  GPIO_InitStructure;
  
    I2C_InitTypeDef  I2C_InitStructure;
  
  
    /* 使能與 I2Cx 引腳的GPIO的時(shí)鐘 */
  
     RCC_APB2PeriphClockCmd(CPS1848_I2C_SCL_GPIO_CLK |  CPS1848_I2C_SDA_GPIO_CLK, ENABLE);
  
    /* 使能 I2Cx 外設(shè)時(shí)鐘 */
  
    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 */;
  
    /* 高電平數(shù)據(jù)穩(wěn)定,低電平數(shù)據(jù)變化 SCL 時(shí)鐘線的占空比 */
  
    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 外設(shè)*/
  
    I2C_Cmd(CPS1848_I2C, ENABLE);
  
  
    /*使能或者失能指定的I2C應(yīng)答功能*/
  
    I2C_AcknowledgeConfig(CPS1848_I2C,  ENABLE);
  
}
  
       I2C的讀操作實(shí)現(xiàn)如下——
  
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);
  
  
    /* 發(fā)送開始信號(hào) */
  
    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);
  
  
    /* 發(fā)送目標(biāo)地址 : 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);
  
  
  
    /* 發(fā)送寄存器地址--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);
  
    /* 發(fā)送寄存器地址--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);
  
    /* 發(fā)送寄存器地址--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);
  
  
  
    /* 開始讀取數(shù)據(jù) */
  
    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);
  
  
    /* 發(fā)送讀取的地址: 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)
  
        {
  
            /* 最后一個(gè)數(shù)據(jù)了,發(fā)送非應(yīng)答信號(hào)(Disable Acknowledgement),結(jié)束傳輸;*/
  
             I2C_AcknowledgeConfig(CPS1848_I2C, DISABLE);
  
            /* 發(fā)送停止位 */
  
            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的寫操作實(shí)現(xiàn)如下——
  
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);
  
  
  
    /* 發(fā)送開始信號(hào) */
  
    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);
  
  
  
    /* 發(fā)送目標(biāo)地址 */
  
    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);
  
  
  
    /* 發(fā)送寄存器地址--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);
  
    /* 發(fā)送寄存器地址--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);
  
    /* 發(fā)送寄存器地址--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);
  
  
    /* 發(fā)送數(shù)據(jù) */
  
    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);
  
  
    /* 發(fā)送數(shù)據(jù) */
  
    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);
  
  
    /* 發(fā)送數(shù)據(jù) */
  
    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);
  
  
    /* 發(fā)送數(shù)據(jù) */
  
    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);
  
  
  
    /* 發(fā)送停止位 */
  
    I2C_GenerateSTOP(CPS1848_I2C, ENABLE);
  
  
    return ERR_SUCCESS;
  
}
  
  


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

四、  兩者的差異
       硬件I2C實(shí)現(xiàn)很簡(jiǎn)潔,且流程中延時(shí)、應(yīng)答等機(jī)制都無需軟件參與,只需做好正確配置和調(diào)用即可;軟件模擬I2C的實(shí)現(xiàn)需要非常完備,且需要嚴(yán)格按照I2C協(xié)議進(jìn)行編寫,嚴(yán)格控制延時(shí)、應(yīng)答、判定等。
       了解兩者之間的差異,并且能夠?qū)崿F(xiàn)兩種I2C的使用,會(huì)極大加深我們對(duì)于I2C的理解和熟練程度,非常有益。


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

評(píng)分

參與人數(shù) 1黑幣 +90 收起 理由
admin + 90 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏2 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:946578 發(fā)表于 2021-6-29 12:13 | 只看該作者
由于篇幅緣故,沒有將所有代碼貼在文中,而放在附件中了。
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 91资源在线 | 日韩在线视频免费观看 | 日韩在线免费视频 | 久久久久久久综合 | 黄色大全免费看 | 天天操综合网站 | h视频在线免费 | 精品国产一区二区 | 国产视频福利 | 精品国产一区二区三区免费 | 99精品在线 | 中国一级特黄真人毛片免费观看 | 岛国精品 | 神马影院一区二区三区 | 日韩精品a在线观看图片 | 国产精品一区二区久久 | 国产精品伦理一区二区三区 | av在线成人| 国产激情一区二区三区 | 艹逼网 | 国产一区二区在线免费 | 欧美老少妇一级特黄一片 | 视频一区二区在线 | 久久久精品日本 | 国产精品久久久久久久久久久久冷 | 国产精品久久久久一区二区三区 | 精品一区二区三区在线观看 | ww 255hh 在线观看| 国产成人叼嘿视频在线观看 | 天天干天天爽 | 日韩精品一区二区三区高清免费 | 国产亚洲精品综合一区 | 在线看国产 | 91色视频在线观看 | 国产精品99久久久久久动医院 | 亚洲精品久久久久中文字幕欢迎你 | 精品香蕉一区二区三区 | 亚洲精品一区二区三区 | 国产日韩一区二区三区 | 超碰国产在线 | 91精品久久|