91视频丝瓜-91视频完整版高清-91视频网-91视频网店-91视频网或将从此无大神-91视频网入口

您好,歡迎訪問上海現易電子元器件有限公司網站!

021-51870898
021-51870898   18019251567
4新聞資訊
您的位置: 首頁 ->  新聞資訊 -> 單片機

?GPIO實現I2C從機的設計

文章出處:單片機 責任編輯:上海現易電子元器件有限公司 發表時間:2018-05-20

在本階段的工作中,需要實現一個由GPIO模擬的I2C從機工程設計,以前只使用GPIO模擬I2C設計過主機,對于從機的設計,還是首次。下面就講本次工作中從機設計思想做詳細記錄。

I2C的簡單總結

對于I2C信號,需要有START,STOP,ACK,NACK,以及接收DATA。接收DATA是在SCL的低電平可能發生跳變,START和STOP是在高電平跳變。當SCL保持高電平的時候,SDA從H跳變到L,即為START;當SCL保持高電平的時候,SDA從L跳變到H,即為STOP。

START信號: 
 
圖1

STOP信號 
 
圖2

ACK信號 
 
圖3

主機下發地址以及讀寫信號 

圖4

程序設計以及分析

//為所使用的硬件平臺的寄存器配置

#define WAIT_IIC_SCL_HIGH   while ( !GET_SCL_DAT )

#define WAIT_IIC_SCL_LOW    while ( GET_SCL_DAT )

#define WAIT_IIC_SDA_HIGH   while ( !GET_SDA_DAT )

#define WAIT_IIC_SDA_LOW    while ( GET_SDA_DAT )


#define IIC_WAIT_START      WAIT_IIC_SCL_HIGH;  WAIT_IIC_SDA_LOW    

#define IIC_WAIT_STOP       WAIT_IIC_SCL_LOW; SDA_IN; WAIT_IIC_SCL_HIGH; WAIT_IIC_SDA_HIGH 


#define IIC_SLAVE_SEND_LOW  WAIT_IIC_SCL_LOW; SDA_OUT; SET_SDA_LOW; WAIT_IIC_SCL_HIGH      

#define IIC_SLAVE_SEND_HIGH WAIT_IIC_SCL_LOW; SDA_OUT; SET_SDA_HIGH; WAIT_IIC_SCL_HIGH


#define IIC_SLAVE_SEND_ACK  IIC_SLAVE_SEND_LOW

#define IIC_SLAVE_SEND_NAK  IIC_SLAVE_SEND_HIGH


  • 初始化

void iic_init(void)  // 完成GPIO作為I2C的初始化

完成GPIO時鐘寄存機配置等功能。

  • 接收地址以及讀寫命令模塊

for(bitcount = 0; bitcount < 7; bitcount ++)

{

    WAIT_IIC_SCL_LOW;                   

    WAIT_IIC_SCL_HIGH;

    iic_slv_addr <<= 1;  //先移位,再讀數

    if(GET_SDA_DAT)

        iic_slv_addr |= 0x01;

    else

        iic_slv_addr |= 0x00;

}

iic_slv_addr <<= 1;

// 讀取7位地址


WAIT_IIC_SCL_LOW;

WAIT_IIC_SCL_HIGH;

if(GET_SDA_DAT)

    iic_master_rw = 1;

else

    iic_master_rw = 0;

// 讀寫標志位


if (iic_slv_addr == SLAVE_ADDR)

    IIC_SLAVE_SEND_ACK;    // 地址正確,從機發送ACK信號

從機接收接口定義以及說明


uint8_t L_i2c_rx( uint8_t xdata *pDestBuf, uint16_t *wRecLen);


pDestBuf:接收數據保存的目的地址 wRecLen:實際接收到的數據的長度


接收核心代碼分析



while(!recFinish)

{

    for(bitcount=0; bitcount<8; bitcount++)

    {

        while(GET_SCL_DAT);

        SDA_IN;

        while(!GET_SCL_DAT);


    r0 = GET_SDA_DAT;

    while(GET_SCL_DAT)

    {

        r1 = GET_SDA_DAT;

        if((r0 == 0) && (r1 == 1))

        {

            recFinish = 1;

            return 0;

        }

    }


    rxbyte <<= 1;

    if(r1)

        rxbyte |= 0x01;

    else

        rxbyte |= 0x00; 

}

buf[len] = rxbyte;

len++;

IIC_SLAVE_SEND_ACK;


在從機接收完地址以后,如果讀寫標志位是寫(L),接下來,從機就會接收數據,接收數據完成的標志為接收到了STOP信號,就必須在從機發完ACK后的第一個SCL高電平時檢測是否有SDA從H跳轉到L,如果發生了,接收程序結束,如果沒有發生跳變,繼續接收數據的bit7,bit6,……bit0.

 
圖5

根據圖5,在時鐘節拍①中從機發送ACK信號以后,因為GPIO的采樣頻率遠大于I2C的始終頻率(設計中使用100K),所以需要在發送ACK后,要等待SCL變為L,在上面的代碼中體現在c點,在時鐘節拍②中,SDA可能會發生變化。最重要的時需要在時鐘節拍③內采樣SDA,判斷是否有變化(即從f到g中連續采樣SDA),如果發生了SDA從H到L,那么就認為接收到了STOP信號,跳出接收數據的函數;如果發生SDA從L到H,會被認為是一個異常的信號(START信號,但不應該在此時出現,上段代碼中沒有處理此異常情況,請注意),同樣也需要跳出接收數據的函數;如果SDA沒有發生任何變化,同時等待到SCL發生由H到L的變化,則意味著接收到了下一字節的bit7……

這樣最核心的問題就變為怎樣判斷在時鐘節拍③中SDA是否發生了變化,并且發生了怎樣的變化。設計的思想為:在f點(上升沿)后取第一個SDA的采樣值r0,遍歷時鐘節拍③直到g點(下降沿),連續采樣SDA的下一個采樣值r1,當在時鐘節拍③內,只要發生了r1 != r0的時候,馬上跳出接收數據程序。但如果r1 === r0,在檢測到h點的時候,才把r1賦值給接收字節rxbyte.

以上采樣能夠成功的一個前提是:SDA在SCL每一時鐘節拍的變化能夠被采樣到。

在此假設GPIO的時鐘為2MHz,SCL的傳輸速度為100KHz,時序關系如下圖所示:


圖6

上圖是比較理想的SCL的時鐘周期信號,在每半個SCL的時鐘周期中,有10個采樣點,這樣確保了SCL上升沿后的第一個GPIO采樣到了r0=0,也能在后5個采樣點中采到了r1=1,在這種情況下,不會發生任何錯誤。

但是,實際情況并非如此,在GPIO模擬I2C的SCL信號中,占空比并不是50%,如果此時SDA的變化在GPIO第一個采樣沿之前就發生了變化,那么就無法采樣到正確的電平變化信號。

所以,以上設計方法能夠成功的前提為:SDA并不會在緊靠著SCL的上升沿或者下降沿而變化,也就是說SDA的任何變化,都能被GPIO的時鐘采樣到。

  • 從機發送接口定義以及說明

uint8_t L_i2c_tx(const uint8_t xdata * pSendBuf, uint16_t wSendLen);


pSendBuf:發送數據緩存地址 wSendLen:發送數據的長度


發送核心代碼分析

for(bytecount = 0; bytecount < len; bytecount ++)

{        

    txmask = 0x80;

    txbyte = buf[bytecount];

    for(bitcount = 0; bitcount < 8; bitcount ++)

    {

        WAIT_IIC_SCL_LOW;

        SDA_OUT;

        if ( txbyte & txmask )

            SET_SDA_HIGH;   

        else    

            SET_SDA_LOW;  

        WAIT_IIC_SCL_HIGH;

        txmask = txmask >> 1;       

    }


    WAIT_IIC_SCL_LOW;                                               

    SDA_IN;

    WAIT_IIC_SCL_HIGH;

    if ( GET_SDA_DAT )  

        break;

}

return (bytecount);


for(bytecount = 0; bytecount < len; bytecount ++)

{        

    txmask = 0x80;

    txbyte = buf[bytecount];

    for(bitcount = 0; bitcount < 8; bitcount ++)

    {

        WAIT_IIC_SCL_LOW;

        SDA_OUT;

        if ( txbyte & txmask )

            SET_SDA_HIGH;   

        else    

            SET_SDA_LOW;  

        WAIT_IIC_SCL_HIGH;

        txmask = txmask >> 1;       

    }


    WAIT_IIC_SCL_LOW;                                               

    SDA_IN;

    WAIT_IIC_SCL_HIGH;

    if ( GET_SDA_DAT )  

        break;

}

return (bytecount);

 
流程圖

上海現易電子元器件有限公司 版權所有 未經授權禁止復制或鏡像

CopyRight 2020-2025 www.urqm.cn All rights reserved   滬ICP備2020031792號

友情鏈接:

電話

易經理

18019251567

微信

易經理

易經理

頂部

咨詢
主站蜘蛛池模板: 精品交小说合集500篇 | 麻豆传传媒久久久爱 | 狼人综合网 | 欧美精品一区二区少妇免费A片 | 伊人青青久久 | 日本高清二三四本2021第九页 | 亚洲精品AV无码永久无码 | 波多野结衣1区 | 日本毛片免费韩国 | 五月婷香 | 国产下药迷倒白嫩美女在线观看 | 真人性做爰88式免费视频 | 综合网伊人| 色络络中文网 | 伊人久久综在合线亚洲不卡 | 97在线人人 | 亚洲国产日韩视频观看 | 最新更新国内自拍视频 | 精品国产美女AV久久久久 | 国精产品一区二区三区 | 999国产高清在线精品 | 97国产精品视频在线观看 | 国精产品999永久中国有限 | 91孕妇精品一区二区三区 | 精品熟女少妇AV久久免费软件 | 91网站在线免费观看 | 国产一区中文字幕 | 成人国产精品视频频 | 欧美一级精品高清在线观看 | 嫩草国产露脸精品国产软件 | 免费成人在线电影 | 欧美乱码卡一卡二卡四卡免费 | 国产精品1卡二卡三卡四卡乱码 | 日韩A片无码一区二区三区电影 | 91po国产在线精品免费观看 | 三要四妾国语免费观看 | 国产在线高清不卡免费播放 | 美日韩一级 | 波多野结衣免费 | 久久精品国产福利 | 无限观看社区在线观看免费 |