在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何根據時序圖編寫高效IO模擬I2C程序

電子Online ? 來源:21ic電子網 ? 2024-04-06 03:05 ? 次閱讀

很多人不知道怎么看著時序圖寫程序,下面結合一個非標準的I2C器件,教大家如何寫一個高效的IO模擬I2C時序。

8de2b62c-ee2d-11ee-a297-92fbcf53809c.png

觀察該時序,具備I2C的開始信號,I2C的結束信號,I2C的應答、非應答、響應應答,以及寫字節和讀字節的基本操作時序。

下面,我們一步一步分析。

1、I2C開始信號

觀察時序圖,在SCLK高電平的狀態下,在SDIO產生一個下降沿是為開始信號。

void I2C_Start()
{
  //設置I2C使用的兩個引腳為輸出模式
  pinMode(SCLK_PIN, OUTPUT);
  pinMode(SDIO_PIN, OUTPUT);


  //在SCL為高電平的時候讓SDA產生一個下降沿是為開始信號
  digitalWrite(SDIO_PIN, 1);
  digitalWrite(SCLK_PIN, 1);
  digitalWrite(SDIO_PIN, 0);
}

上述代碼即先將兩個引腳設置為輸出模式,然后在SCLK為高電平的時候在SDIO引腳輸出一個下降沿。

2、I2C停止信號

觀察時序圖,在SCLK為高電平的時候在SDIO引腳產生一個上升沿是為停止信號。

void I2C_Stop()
{
  pinMode(SDIO_PIN, OUTPUT);
  //在SCL為高電平的時候讓SDA產生一個上升沿是為停止信號
  digitalWrite(SDIO_PIN, 0);
  digitalWrite(SCLK_PIN, 1);
  digitalWrite(SDIO_PIN, 1);
}

這里采用的是Arduino編寫的IO基本操作,你可以替換成任意單片機的IO操作。

由于整個過程SCLK引腳一直是輸出狀態,所以僅在開始信號中對SCLK初始化為輸出模式,而過程中可能會修改SDIO的輸入輸出模式,所以其他的函數開頭都要根據情況對SDIO引腳的模式進行設置。

通過三行代碼實現在SCLK為高電平的時候在SDIO產生一個上升沿,實現停止信號。

3、寫字節操作

接下來,按照時序的順序編寫方便認讀

I2C的讀寫字節是這么定義的:當時鐘線為低電平的時候,允許修改數據線的電平狀態,在時鐘線為高電平的時候讀取數據線的狀態。

因為是寫操作,因此我們要先將時鐘線SCLK拉低,再修改SDIO的值,然后拉高時鐘。拉高后,從機就會從總線上讀取SDIO的狀態,接著一位一位的這么發送。

void I2C_Write(uint8_t dat)
{
  pinMode(SDIO_PIN, OUTPUT);
  //拉低時鐘線后可修改數據線的狀態
  digitalWrite(SCLK_PIN, 0); 
  for(int i=0;i<8;i++)
  {
    digitalWrite(SDIO_PIN, (bool)(dat&0x80)); 
    digitalWrite(SCLK_PIN, 1);//在高電平時候送出數據
    dat=dat<<1;
    digitalWrite(SCLK_PIN, 0);//拉低準備下一個位的數據發送
  }
}

上述代碼正描述了這一情況:為了保證最后是低電平,這里將SCLK的第一次拉低放到循環外面,這樣可以用最少的執行次數完成一個字節的寫任務;同時,結束完一個字節寫入后時鐘線是低電平狀態(時序圖中寫入的第一個字節為DeviceID,第二個字節為寄存器地址+讀寫位)。

寫完一個字節后,從機會對寫入事件進行應答,這個時候主級可以從總線上讀取應答信號。

4、讀取從機應答引號

應答信號在寫入完一個字節后的低電平后由從機送出,在時鐘為高電平的時候可以讀取出來,我們注意到寫入自己操作后時鐘線已經是低電平了,因此這個時候

只要拉高時鐘線,接下來就可以讀取應答信號,讀取完應答信號根據時序圖應該拉低時鐘準備下一個字節的寫入。

bool I2C_RACK()
{
  bool ack;
  pinMode(SDIO_PIN, INPUT);


  digitalWrite(SCLK_PIN, 1);//接收應答信號,當時鐘拉高時候,從機送出應答信號
  ack = digitalRead(SDIO_PIN);
  digitalWrite(SCLK_PIN, 0);//讀取完應答信號后拉低時鐘。
  return ack;
}

如上代碼所示,即為接收從機應答,拉高時鐘,讀取應答,再拉低,返回應答。如果從機應答了,這里會讀取到一個低電平。

后面就是再寫入一個寄存器+讀寫位的地址,參靠上面的寫入操作。

寫入寄存器地址后,緊跟著又一個接收從機應答信號,然后從機就會送出數據,送出的數據分高字節和低字節,高低字節間要有一個主機發送給從機的應答信號,這樣從機酒知道主機收到了數據,就會送出后面的低字節數據。

5、讀字節操作

注意,前面說過,讀寫都是總線在時鐘低電平時候修改數據線,在高電平送出。

因此,主機讀取從機送來的數據仍然是在高電平時候讀取。

uint8_t I2C_Read()
{
  uint8_t dat=0;
  pinMode(SDIO_PIN, INPUT);
  for(int i=0;i<8;i++)
  {
    digitalWrite(SCLK_PIN, 1);//讀取數據時候是在時鐘的高電平狀態讀取
    dat=dat<<1;
    if(digitalRead(SDIO_PIN))
    {
      dat=dat|1;
    }
    digitalWrite(SCLK_PIN, 0);//拉低時鐘線準備下一個位的讀取
  }
  return dat;
}

操作過程是將SDIO數據線的IO設置為輸入模式,準備讀取,然后拉高時鐘,讀取數據,移位,拉低循環讀取8位數據。

注意,操作完一個字節讀取任務后,時鐘線還是低電平。

讀取完一個字節后,主機要給從機發送一個應答信號,這樣從機會接著發低字節數據。

6、主機發送應答信號給從機

void I2C_ACK()
{
pinMode(SDIO_PIN, OUTPUT);
digitalWrite(SDIO_PIN, 0);//給從機發送應答信號,即拉低數據線,然后拉高時鐘讓從機讀取該應答
digitalWrite(SCLK_PIN, 1);
digitalWrite(SCLK_PIN, 0);//執行完應答后拉低時鐘線,準備下一步動作。
}

拉低數據線,然后在高電平的時候讓從機去讀取,之后拉低時鐘線準備下一步接收動作。

當再接收一個字節后,就讀取完成了,這個時候就是產生一個非應答信號,然后發給總線結束信號,告訴從機一個讀寫周期結束了。

7、主機非應答信號

什么是非應答信號呢?

就是接收完了數據,釋放數據線,不去拉低數據線。

void I2C_NACK()
{
  //非應答信號:即主機不再對從機進行應答,主機釋放數據線,即拉高數據線,然后給時鐘一個周期信號(拉高再拉低)
  pinMode(SDIO_PIN, OUTPUT);
  digitalWrite(SDIO_PIN, 1);
  digitalWrite(SCLK_PIN, 1);
  digitalWrite(SCLK_PIN, 0);
}

將SDIO引腳設置為輸出,拉高數據線,即為釋放數據線,然后拉高拉低時鐘,即在時鐘線產生一個時鐘周期信號。

然后發送結束信號。結束信號在開頭已經講明,即在時鐘線為高電平的狀態下,在數據線產生一個上升沿。

觀察以上代碼沒一個多余重復的操作動作,即完美的視線了時序圖上的所有操作。

接下來就是利用上述的I2C成分進行對寄存器的讀寫操作了。

8、讀寄存器

由于圖中設備的DeviceID 為0x80,即直接寫進來,從機判斷是讀還是寫的字節在寄存器地址。

因此,將寄存器的地址左移一位,在末尾補上是讀(1)還是寫(0)。

uint16_t read_reg(uint8_t reg)
{
  uint16_t dat=0;
  reg=(reg<<1)|1;
  I2C_Start();
  I2C_Write(0x80);
  I2C_RACK();
  I2C_Write(reg);
  I2C_RACK();
  dat=I2C_Read();
  dat=dat<<8;
  I2C_ACK();
  dat=dat|I2C_Read();
  I2C_NACK(); 
  I2C_Stop();
  return dat;
}

9、寫寄存器操作

void write_reg(uint8_t reg, uint16_t dat)
{
  reg=(reg<<1);
  I2C_Start();
  I2C_Write(0x80);
  I2C_RACK();
  I2C_Write(reg);
  I2C_RACK();
  I2C_Write(dat>>8);
  I2C_RACK();
  I2C_Write(dat&0xFF);
  I2C_NACK();
  I2C_Stop();
}

最后,對寄存器讀寫函數測試。

void setup() 
{
  Serial.begin(115200);
  Serial.println("Hello I2C");
  write_reg(0x02,0x2250);
  Serial.println(read_reg(0x02),HEX);
  write_reg(0x02,0x2281);
  Serial.println(read_reg(0x02),HEX);
}


void loop() 
{


}

8df3bc56-ee2d-11ee-a297-92fbcf53809c.jpg

讀取的數值與寫入的是一樣的。

最后曬出完整的測試代碼:

#define SCLK_PIN 8
#define SDIO_PIN 9




void I2C_Start()
{
  //設置I2C使用的兩個引腳為輸出模式
  pinMode(SCLK_PIN, OUTPUT);
  pinMode(SDIO_PIN, OUTPUT);


  //在SCL為高電平的時候讓SDA產生一個下降沿是為開始信號
  digitalWrite(SDIO_PIN, 1);
  digitalWrite(SCLK_PIN, 1);
  digitalWrite(SDIO_PIN, 0);
}


void I2C_Stop()
{
  pinMode(SDIO_PIN, OUTPUT);
  //在SCL為高電平的時候讓SDA產生一個上升沿是為停止信號
  digitalWrite(SDIO_PIN, 0);
  digitalWrite(SCLK_PIN, 1);
  digitalWrite(SDIO_PIN, 1);
}


void I2C_Write(uint8_t dat)
{
  pinMode(SDIO_PIN, OUTPUT);
  //拉低時鐘線后可修改數據線的狀態
  digitalWrite(SCLK_PIN, 0); 
  for(int i=0;i<8;i++)
  {
    digitalWrite(SDIO_PIN, (bool)(dat&0x80)); 
    digitalWrite(SCLK_PIN, 1);//在高電平時候送出數據
    dat=dat<<1;
    digitalWrite(SCLK_PIN, 0);//拉低準備下一個位的數據發送
  }
}


uint8_t I2C_Read()
{
  uint8_t dat=0;
  pinMode(SDIO_PIN, INPUT);
  for(int i=0;i<8;i++)
  {
    digitalWrite(SCLK_PIN, 1);//讀取數據時候是在時鐘的高電平狀態讀取
    dat=dat<<1;
    if(digitalRead(SDIO_PIN))
    {
      dat=dat|1;
    }
    digitalWrite(SCLK_PIN, 0);//拉低時鐘線準備下一個位的讀取
  }
  return dat;
}




bool I2C_RACK()
{
  bool ack;
  pinMode(SDIO_PIN, INPUT);


  digitalWrite(SCLK_PIN, 1);//接收應答信號,當時鐘拉高時候,從機送出應答信號
  ack = digitalRead(SDIO_PIN);
  digitalWrite(SCLK_PIN, 0);//讀取完應答信號后拉低時鐘。
  return ack;
}


void I2C_ACK()
{
  pinMode(SDIO_PIN, OUTPUT);
  digitalWrite(SDIO_PIN, 0);//給從機發送應答信號,即拉低數據線,然后拉高時鐘讓從機讀取該應答
  digitalWrite(SCLK_PIN, 1);
  digitalWrite(SCLK_PIN, 0);//執行完應答后拉低時鐘線,準備下一步動作。
}


void I2C_NACK()
{
  //非應答信號:即主機不再對從機進行應答,主機釋放數據線,即拉高數據線,然后給時鐘一個周期信號(拉高再拉低)
  pinMode(SDIO_PIN, OUTPUT);
  digitalWrite(SDIO_PIN, 1);
  digitalWrite(SCLK_PIN, 1);
  digitalWrite(SCLK_PIN, 0);
}


uint16_t read_reg(uint8_t reg)
{
  uint16_t dat=0;
  reg=(reg<<1)|1;
  I2C_Start();
  I2C_Write(0x80);
  I2C_RACK();
  I2C_Write(reg);
  I2C_RACK();
  dat=I2C_Read();
  dat=dat<<8;
  I2C_ACK();
  dat=dat|I2C_Read();
  I2C_NACK(); 
  I2C_Stop();
  return dat;
}


void write_reg(uint8_t reg, uint16_t dat)
{
  reg=(reg<<1);
  I2C_Start();
  I2C_Write(0x80);
  I2C_RACK();
  I2C_Write(reg);
  I2C_RACK();
  I2C_Write(dat>>8);
  I2C_RACK();
  I2C_Write(dat&0xFF);
  I2C_NACK();
  I2C_Stop();
}




void setup() 
{
  Serial.begin(115200);
  Serial.println("Hello I2C");
  write_reg(0x02,0x2250);
  Serial.println(read_reg(0x02),HEX);
  write_reg(0x02,0x2281);
  Serial.println(read_reg(0x02),HEX);
}


void loop() 
{


}

看完這篇文章,你學會純手工擼IO模擬I2C時序的代碼了嗎?

審核編輯:黃飛

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 總線
    +關注

    關注

    10

    文章

    2881

    瀏覽量

    88085
  • 函數
    +關注

    關注

    3

    文章

    4331

    瀏覽量

    62618
  • 高電平
    +關注

    關注

    6

    文章

    149

    瀏覽量

    21385
  • I2C驅動
    +關注

    關注

    0

    文章

    9

    瀏覽量

    7058
  • 時鐘線
    +關注

    關注

    0

    文章

    6

    瀏覽量

    3617

原文標題:看時序圖寫I2C驅動,教你如何自己手擼非標I2C驅動函數

文章出處:【微信號:電子Online,微信公眾號:電子Online】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    利用IO模擬I2C時序進而實現I2C通訊的步驟

    模擬I2C時序進而實現I2C通訊的。給很多想學習硬件I2C通訊的小伙伴帶來了困難。下面先介紹一下配置步驟1.E
    發表于 01-24 08:22

    I2C總線驅動程序

    1 /**————————————————————2 〖說明〗I2C總線驅動程序(用兩個普通IO模擬I2
    發表于 08-13 17:04 ?64次下載

    I2C總線驅動程序的實現

    I2C總線驅動程序的實現 I2C 驅動程序的簡介本驅動程序為標準的51 系列CPU 編寫,讓C
    發表于 09-26 17:25 ?5749次閱讀
    <b class='flag-5'>I2C</b>總線驅動<b class='flag-5'>程序</b>的實現

    基于GAL的I2C總線時序模擬

    本文給出了用可編程邏輯器件GAL配合ISA總線模擬I2C總線時序來對FI1256 MK2進行控制的方法。該方法與PCI總線進行模擬的方法相類
    發表于 03-27 11:33 ?2896次閱讀
    基于GAL的<b class='flag-5'>I2C</b>總線<b class='flag-5'>時序模擬</b>

    I2C總線的結構、工作時序模擬編程

    I2C總線的結構、工作時序模擬編程
    發表于 10-24 14:34 ?13次下載
    <b class='flag-5'>I2C</b>總線的結構、工作<b class='flag-5'>時序</b>和<b class='flag-5'>模擬</b>編程

    軟件模擬i2c實現io時序電路的技巧

    關于 Bit Bang 的解釋:Use software to control serial communication at general-purpose I/O pins,簡單來講就是使用軟件通過 IO 腳去實現 I2C
    的頭像 發表于 11-06 09:32 ?1.5w次閱讀
    軟件<b class='flag-5'>模擬</b><b class='flag-5'>i2c</b>實現<b class='flag-5'>io</b>腳<b class='flag-5'>時序</b>電路的技巧

    深度解析IO模擬時序(SPI)的注意事項

    有硬件I2C、SPI時盡量用硬件操作,省去IO模擬繁瑣的時序調試。但在內部資源不夠時就要用IO模擬
    的頭像 發表于 01-17 09:37 ?1.6w次閱讀
    深度解析<b class='flag-5'>IO</b><b class='flag-5'>模擬</b><b class='flag-5'>時序</b>(SPI)的注意事項

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

    I2C總線協議程序 在使用的過程中一定要注意時序、時間的問題。 i2c.c /* I2C.c 標準80
    發表于 12-05 15:39 ?3453次閱讀
    80<b class='flag-5'>C</b>51單片機<b class='flag-5'>模擬</b><b class='flag-5'>I2C</b>總線的主機<b class='flag-5'>程序</b>分享

    使用51單片機IO模擬I2C程序免費下載

    本文檔的主要內容詳細介紹的是使用51單片機IO模擬I2C程序免費下載。
    發表于 08-02 17:34 ?5次下載
    使用51單片機<b class='flag-5'>IO</b><b class='flag-5'>模擬</b><b class='flag-5'>I2C</b>的<b class='flag-5'>程序</b>免費下載

    DSP配置I2C通訊(非IO口軟件模擬時序

    TMS320F28377D為例,使用ti公司dsp開發工具ccs10.1配置i2c模塊。寫這篇文章的緣由,因為市面上很多DSP其實內部是具有硬件I2C接口的,但由于網絡上大部分資料和例程都是利用IO
    發表于 11-29 14:06 ?16次下載
    DSP配置<b class='flag-5'>I2C</b>通訊(非<b class='flag-5'>IO</b>口軟件<b class='flag-5'>模擬</b><b class='flag-5'>時序</b>)

    嵌入式內核及驅動開發-09IIC子系統框架使用(I2C協議和時序I2C驅動框架,I2C從設備驅動開發,MPU6050硬件連接

    從設備adapter i2c 控制器對象數據包對象讀寫數據設備樹中添加MPU6050信息內核選配添加設備樹節點編寫驅動程序 mpu6050_i2c_drv.cI2c協議和
    發表于 12-06 14:06 ?17次下載
    嵌入式內核及驅動開發-09IIC子系統框架使用(<b class='flag-5'>I2C</b>協議和<b class='flag-5'>時序</b>,<b class='flag-5'>I2C</b>驅動框架,<b class='flag-5'>I2C</b>從設備驅動開發,MPU6050硬件連接

    硬件I2C模擬I2C

    硬件I2C對應芯片上的I2C外設,有相應I2C驅動電路,其所使用的I2C管腳也是專用的,因而效率要遠高于軟件模擬
    發表于 12-28 19:14 ?81次下載
    硬件<b class='flag-5'>I2C</b>與<b class='flag-5'>模擬</b><b class='flag-5'>I2C</b>

    經過驗證的GPIO模擬I2C時序代碼

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

    ESP 12E I2c基卡的I2C IO卡設計

    電子發燒友網站提供《ESP 12E I2c基卡的I2C IO卡設計.zip》資料免費下載
    發表于 08-15 09:27 ?3次下載
    ESP 12E <b class='flag-5'>I2c</b>基卡的<b class='flag-5'>I2C</b> <b class='flag-5'>IO</b>卡設計

    STC單片機IO模擬I2C(主從)文件資料

    STC單片機IO模擬I2C(主從)文件資料免費下載。
    發表于 08-29 10:13 ?14次下載
    主站蜘蛛池模板: 国产日韩精品欧美一区色| 国产欧美日韩在线人成aaaa| 成人拍拍视频| 激情五月网站| 又污又黄的网站| 久久综合丁香| 理论在线看| 在线天堂bt种子| 精品久久久久久中文字幕欧美| 日日操夜夜| 黄视频免费在线看| 久久视频精品线视频在线网站| 日韩夜夜操| 曰韩一级| 国产成人精品曰本亚洲 | 天天干天天骑| 午夜爽视频| 免费人成网址在线观看国内| 日韩成人免费观看| 伊人男人天堂| 国产大乳喷奶水在线看| 视频在线观看网站免费| 四虎国产精品永久在线| 午夜官网| 最新毛片网| 成人a一级毛片免费看| xxxx日本xx| 免费黄色地址| аⅴ天堂中文在线网| 色老头综合| 免费鲁丝片一级观看| 亚洲丁香| 五月天婷婷综合网| 99热.com| 永久视频在线观看| 久久国产精品无码网站| 国产色婷婷精品免费视频| 视频在线免费看| 久久香蕉综合色一综合色88| q2002韩国理论| 欧美高清在线观看视频|