51單片機 普通IO口模擬IIC(I2C)接口通訊的程序代碼

2021-01-17 電子產品世界

I2C總線是Philips公司提出的一種集成電路IC器件之間相連接的總線協議,其目的是使電子系統(不只 限於單片機系統)各個IC器件之間的連線變得容易。因為使用傳統的並行總線在IC器件之間連接,往往會使得IC之間連線較多,顯得非常複雜。而I2C總線 則使IC器件之間只需SDA、SCL兩條連線就可以傳送數據,因而十分方便。由於I2C在印刷體中不容易書寫(需要上標),所以實際書寫時,還常見到 IIC、I2C等書寫方法,本文採用IIC的寫法,敬請注意。關於IIC總線的知識,請參閱相關書籍,此處不再做進一步介紹。

本文引用地址:http://www.eepw.com.cn/article/201808/385451.htm

下面我們用一個使用IIC總線連接器件的例子來簡單說明IIC總線的仿真。

例.EEPROM24C02是採用IIC接口的一種常用2Kbit(256×8bit)的存儲器。編寫程序使用AT89C51的IO口模擬實現IIC總線協議進行通信,並向24C02存儲器內從字節0到字節FF寫入數字0到FF。

51系列單片機本身沒有IIC接口,但一些本身具有IIC接口的單片機往往是高端產品,一方面價格不菲,另一方面我們的系統也沒有必要使用之。通常我們就使用軟體通過51系列單片機的IO口來模擬實現IIC總線通信。

本例事實上比較簡單,但需要對IIC總線時序有較好的理解。源文件如下圖所示(採用C51語言編寫):




在Keil中編輯好源文件以後,接下來就可以建立工程文件並生成相應的原始碼了,然後我們來繪製電路圖。

此例的電路圖極其簡單。只需兩個IC,即AT89C51和24C02C,和兩個上拉電阻,而且上拉電阻還可以省略。至於連接,就更為簡單了。最後得到繪製好的電路圖如下圖所示:


繪製好電路圖,我們就可以將前面剛剛生成的程序原始碼裝入單片機了,裝入以後,下面我們就可以來進行仿真了。

首先點擊仿真按鈕,系統沒有什麼反映,只有高低電平變化的顏色。我們要想查看結果,還要用前文中仿真擴展 RAM存儲器的方法,先點擊暫停,然後點擊「Debug」菜單下的「I2C Memory Internal Memory – U2」子菜單來打開U2即EEPROM存儲器24C02C的內容窗口「I2C Memory Internal Memory – U2」,然後我們就看到了其中的內容,也就是我們仿真程序的結果。如下圖所示:


從圖中我們能清楚地看到我們的仿真結果,程序完全正確地執行了我們的命令。

當然,如果你過早地點擊了暫停按鈕,那麼你得到的結果可能和上圖略有不同,那可能是因為程序尚未執行完畢。此時你可以繼續點擊運行按鈕,或者點擊單步按鈕來仔細查看程序執行過程中24C02C存儲器內容的改變情況。

完整代碼如下:

/*----

Acess the eeprom--24c04

----*/

#include

#ifndef INT8U

#define INT8U unsigned char

#endif

#ifndef INT8S

#define INT8S signed char

#endif

#ifndef INT16U

#define INT16U unsigned int

#endif

#define I2C_DELAY; _nop_();_nop_();_nop_();_nop_();_nop_(); // >=4.7uS

//----

// delay 100us

//----

void mDelay(INT8U k)

{

INT16U i ;

for(; k>0; k--)

{

for(i=0; i93; i++)

;

}

}

//----

//OK

//----

void I2C_Start(void)

{

SDA = 1;

I2C_DELAY;

SCL = 1;

I2C_DELAY;

SDA = 0;

I2C_DELAY;

I2C_DELAY;

}

//----

//OK

//----

void I2C_Stop(void)

{

SDA = 0 ;

I2C_DELAY;

SCL = 1 ;

I2C_DELAY;

SDA = 1 ;

I2C_DELAY;

I2C_DELAY;

}

//----

//

//----

void sendAck(void)

{

SCL = 0;

I2C_DELAY;

SDA = 0;

I2C_DELAY;

SCL = 1;

I2C_DELAY;

}

//----

//

//----

void sendNoAck(void)

{

SCL = 0;

I2C_DELAY;

SDA = 1;

I2C_DELAY;

SCL = 1;

I2C_DELAY;

}

//----

// 0 = noACK; 1 = ACK ;

//----

bit checkAck()

{

bit tempbit;

/*發送完一個字節後檢驗設備的應答信號*/

SDA = 1;

I2C_DELAY;

SCL = 0;

I2C_DELAY;

tempbit = SDA;

SCL = 1;

I2C_DELAY;

if(tempbit==1)

{

return 0; //noACK

}

else

{

return 1; //ACK

}

}

//----

//OK

// a positive clock edge clock a bit into the ROM

//----

void writeByte(INT8U datum)

{

INT8U bitCnt = 0 ;

for(bitCnt=0; bitCnt8; bitCnt++)

{

SCL = 0 ;

I2C_DELAY;

if ((datum0x80) == 0x80) //if the MSb is 1

SDA = 1 ;

else

SDA = 0 ;

I2C_DELAY;

SCL = 1 ;

I2C_DELAY;

datum=1 ;

}

}

//----

//OK

//----

INT8U readByte(void)

{

bit tempbit = 1 ;

INT8U temp = 0 ;

INT8U bitCnt ;

SDA = 1 ; // release the bus,ready to receive byte??????????????

I2C_DELAY;

for(bitCnt=0; bitCnt8; bitCnt++)

{

SCL = 0; //?????????????????????????huan???????????????

I2C_DELAY;

tempbit = SDA ;

if (tempbit)

temp |= 0x01 ;

else

temp = 0xfe ;

SCL = 1 ;

I2C_DELAY;

if(bitCnt7)

temp = 1 ;

}

return(temp) ;

}

/*~~~~~~~~~~~~~~~~~~~~~~~ API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

/*

write some bytes to sequential address

*/

void writeToROM(INT8U datum[], INT8U address, INT8U num)

{

bit tempbit ;

INT8U i ;

INT8U *datum_P ;

datum_P = datum ;

I2C_Start() ;

writeByte(0xa0) ;

tempbit = checkAck();

writeByte(address) ;

tempbit = checkAck();

for(i=0; i

{

writeByte(*(datum_P+i)) ;

if(!checkAck())

{

I2C_Stop() ;

mDelay(100) ;

}

}

I2C_Stop() ;

}

/*

read some bytes from ROM`s sequential address

*/

void readFromROM(INT8U datum[], INT8U address, INT8U num)

{

bit tempbit ;

INT8U i ;

INT8U *datum_P ;

datum_P = datum;

I2C_Start() ;

writeByte(0xa0) ;

tempbit = checkAck();

writeByte(address) ;

tempbit = checkAck();

I2C_Start() ;

writeByte(0xa1) ;

tempbit = checkAck();

for(i=0; i

{

*(datum_P+i) = readByte() ;

if(i!=num-1)

{

sendAck() ;

}

else

{

sendNoAck() ;

}

}

I2C_Stop() ;

}

/*

wirte one byte to ROM --random write

*/

void writeOneByte(INT8U addr, INT8U datum)

{

bit tempbit ;

/*write a byte to mem*/

I2C_Start();

writeByte(0xa0);

tempbit = checkAck();

writeByte(addr); /*address*/

tempbit = checkAck();

writeByte(datum); /*the data*/

tempbit = checkAck();

I2C_Stop();

mDelay(100) ;

}

/*

read one byte from rom --random read

*/

INT8U readOneByte(INT8U addr)

{

bit tempbit = 1;

INT8U mydata;

/*read a byte from mem*/

I2C_Start();

writeByte(0xa0);

tempbit = checkAck();

writeByte(addr); /*address*/

tempbit = checkAck();

I2C_Start();

writeByte(0xa1);

tempbit = checkAck();

mydata = readByte();

tempbit = checkAck();

return (mydata) ;

I2C_Stop();

}

『本文轉載自網絡,版權歸原作者所有,如有侵權請聯繫刪除』

相關焦點

  • 關於調試stm32和stm8(51單片機)的i2c和spi協議的之間的區別
    在調試STM32的i2c和io口模擬spi協議時發現時序是很關鍵的。stm32在72M運行下可以實現i2c或者spi協議,但並不代表把相同的代碼移植到51單片機上就會成功的跑起來,因為51單片機的速讀最塊8M,所以在時序上會產生很多大的區別。經過測試,在stm32上的spi協議時鐘線可達到20Khz,移植到51後,頻率會降到<10hz。
  • 單片機,硬體IIC和軟體IIC的區別
    所謂硬體I2C對應晶片上的I2C外設,有相應I2C驅動電路,其所使用的I2C管腳也是專用的;軟體I2C一般是用GPIO管腳,用軟體控制管腳狀態以模擬I2C通信波形。硬體I2C的效率要遠高於軟體的,而軟體I2C由於不受管腳限制,接口比較靈活。模擬I2C 是通過GPIO,軟體模擬寄存器的工作方式,而硬體(固件)I2C是直接調用內部寄存器進行配置。
  • S3C2440模擬IIC方式操作EEPROM
    先簡單介紹一下基本情況:在S3C2440下,編寫iic程序,可以有一下三種方法,其實就是2種:本文引用地址:http://www.eepw.com.cn/article/201612/325195.htm1.自己編寫模擬iic程序,控制IO口的變化。
  • 單總線、IIC、SPI接口詳解(一)
    關注「電子芯吧客」,每周都有精彩文章推薦相信大家在初次接觸到單片機的時候
  • I2C總線驅動程序
    linux/err.h"#include "linux/platform_device.h"#include "linux/pm_runtime.h"#include "linux/clk.h"#include "linux/cpufreq.h"#include "linux/slab.h"#include "linux/io.h
  • 51單片機與三菱PLC無協議通訊成功
    我用了兩個晚上的時間查閱一些資料,利用三菱PLC的擴展RS485通訊板與其51單片機連接通訊,可寫PLC任意的地址長度可達1000米,看見網上寫的都很煩且對三菱和單片機不是很熟的朋友來說有一定的閱讀難度,今天將它與大家分享。希望在此基礎上大家能擴展出自己想要的功能,過些時間有空我在寫個半雙工的程序。
  • 基於51單片機的異步串行接口鍵盤設計
    (2)擴展鍵盤與顯示處理機通訊通過其異步串行接口來完成,波特率為9600 b/s。 (3)擴展鍵盤與顯示處理機通訊的接口電平為RS232C標準。 (4)波特率相對誤差應小於2.5%。 (5)擴展鍵盤的電源要求:直流+5 V。 (6)擴展鍵盤的環境溫度要求:-100~+500°C。1.2 工作原理 擴展鍵盤工作原理如圖1所示。
  • pic單片機IIC通信讀24C02程序例 16F877A 主頻4M
    文本名為 iic.h #ifndef _iic_h_#define _iic_h_//pic單片機IIC通信初始化函數聲明void iiccsh(void
  • 51單片機IO口模擬串口的實現
    IO口模擬串口 1602顯示數據位內容程序可以實現一個51單片機有兩個串口
  • 基於I2C總線性能問答集錦
    [問:qihong] 請問lpc系列單片機的iic接口是否支持熱插拔?[答:Alex] 不支持,I2C總線上的熱插拔需要專門的器件支持,比如PCA9511[問:chenhezhi] I2C總線在連續寫EEPROM時容易出現什麼問題,100K的傳輸速率。
  • 基於proteus的51單片機開發實例37-DAC0832
    轉換晶片DAC0832,通過單片機輸出一系列的數位訊號到DAC0832,DAC0832把這些數位訊號轉換成模擬信號,以電流的形式輸出。IOUT2:模擬電流輸出端2.IOUT1:模擬電流輸出端1.RFB:反饋信號輸入端。VCC:電源端。VREF:基準電壓輸入端。AGND:模擬地。DGND:數字地。1.3.2.
  • 支持RS485接口的PLC與單片機的通訊
    打開APP 支持RS485接口的PLC與單片機的通訊 發表於 2019-10-13 16:11:00 1 引言
  • 51單片機程序下載、ISP及串口基礎知識
    本文詳細介紹了串口、51單片機的ISP下載等基礎知識,已經學過單片機的也可以看看,加強一下對這方面的了解。 串口 串行接口簡稱串口,也稱串行通信接口,是採用串行通信方式的擴展接口。一方面USB接口負責給單片機供電,另一方面,USB轉TTL或RS232轉TTL已經集成的學習板上。 51單片機程序的燒寫 我們最常見的51單片機是美國Atmel公司生產的AT系列單片機和中國宏晶公司生產的STC系列單片機。
  • STM32——硬體和軟體I2C協議
    對於通訊協議,我們以分層的方式來理解,最基本的是把它分為物理層和協議層。物理層規定通訊系統中具有機械、電子功能部分的特性,確保原始數據在物理媒體的傳輸。協議層主要規定通訊邏輯,統一收發雙方的數據打包、解包標準。
  • 帶詳細注釋的51單片機CS1237電子秤源程序
    工程硬體平臺:    1,51Core-V1.0(51單片機最小系統板)                2,差分ADC模塊-CS1237                3,稱重傳感器模塊                4,OLED顯示器0.96寸,4PIN工程程序版本:51單片機廚房(藥房)秤方案 V1.0.0.0
  • MCS_51單片機與8255A的接口設計
    所謂可編程的接口晶片是指其功能可由微處理機的指令來加以改變的接口晶片,利用編程的方法,可以使一個接口晶片執行不同的接口功能。目前,各生產廠家已提供了很多系列的可編程接口,MCS-51單片機常用的兩種接口晶片是8255以及8155。本文引用地址:http://www.eepw.com.cn/article/170507.htm8255和MCS-51相連,可以為外設提供三個8位的I/O埠:A口、B口和C口,三個埠的功能完全由編程來決定。
  • 51單片機擴展中斷的四種方法
    MCS—51系列單片機內部只有兩個外部中斷源輸入端,當外部中斷源多於兩個時,就必須進行擴展,下面介紹兩種簡單的擴展方法:一、採用硬體請求和軟體查詢的方法:這種方法是:把各個中斷源通過硬體
  • 基於51單片機的人體紅外模塊的自動門設計
    方案二:採用51系列單片機。系統的要求不高,程序的編寫也比較簡單,需要用到的I/O口的數量用該系列的單片機來操作完全能夠實現,無需再擴展,充分的利用了單片機資源。另外,經典的51系列單片機的處理速度也能夠滿足系統要求,性價比相對CPLD器件更高。綜合以上兩種方案,本系統選擇方案二,以AT89C51作為系統的微控制器。4.
  • 《電子發燒友網51單片機設計方案TOP10》
    該系統的核心是MCS-51多機半雙工通信,要求各子機僅能和主機通信,子機之間的通信要通過主機進行,不允許子機之間通信,主要由主機系統、分機系統、通信接口3部分組成。其系統結構框圖如圖1所示。   多路呼叫系統主要是根據MCS-51單片機的多機通信功能,將不同的床位編成有一定規律的代碼,主機根據接收到的代碼判斷床位的號碼,並向該床位發送指令,達到通信的目的。
  • 單片機程序怎麼燒寫?各種單片機程序燒寫方法,快來看看吧!
    單片機學習、使用非常重要的一個步驟就是把寫好的程序燒寫到單片機裡,好多初學者,好不容易才寫好一個程序,馬上想讓他跑起來,但是如何燒寫程序確犯難了!我把單片機常用的燒寫方法做了一下歸納,希望能夠幫到大家!