tft每日頭條

 > 圖文

 > STC8A8K64S4A12開發闆片外存儲器E2PROM講解

STC8A8K64S4A12開發闆片外存儲器E2PROM講解

圖文 更新时间:2025-01-18 04:35:58
文章目錄
  • 前言
  • 一、硬件設計
    • 1.E2PROM存儲器介紹
    • 2.開發闆DAC硬件電路介紹
      • 2.1.主要特征
      • 2.2.I2C地址
      • 2.3.I2C數據傳輸
      • 2.4.ACK和NACK
      • 2.5.從機地址和R/W位
    • 3.STC8A8K64S4A12系列單片機I2C介紹
  • 二、軟件設計
    • 1.I2C相關寄存器彙集
    • 2.寄存器解析
      • 2.1.I2C配置寄存器I2CCFG
      • 2.2.I2C主機控制寄存器I2CMSCR
      • 2.3.I2C主機輔助控制寄存器I2CMSAUX
      • 2.4.I2C主機狀态寄存器I2CMSST
      • 2.5.I2C從機控制寄存器I2CSLCR
      • 2.6.I2C從機狀态寄存器I2CSLST
      • 2.7.I2C從機地址寄存器I2CSLADR
    • 3.I2C配置步驟
    • 4.外部EEPROM存儲器讀寫單字節實驗(模拟I2C)
      • 4.1.工程需要用到的c文件
      • 4.2.頭文件引用和路徑設置
      • 4.3.編寫代碼
      • 4.4.硬件連接
    • 5.外部EEPROM存儲器讀寫多字節實驗(模拟I2C)
      • 5.1.編寫代碼
      • 5.2.硬件連接
    • 6.外部EEPROM存儲器讀寫單字節實驗(硬件I2C)
      • 6.1.工程需要用到的c文件
      • 6.2.頭文件引用和路徑設置
      • 6.3.編寫代碼
      • 6.4.硬件連接
    • 7.外部EEPROM存儲器讀寫多字節實驗(硬件I2C)
      • 7.1.編寫代碼
      • 7.2.硬件連接
  • 總結
前言

今天介紹下STC8A8K64S4A12系列單片機外部E2PROM存儲器原理和I2C總線的原理及工作模式,掌握STC8A8K64S4A12系列單片機I2C外設相關的寄存器配置及程序設計。

一、硬件設計1.E2PROM存儲器介紹

EEPROM(全稱是Electrically Erasable Programmable Read-Only Memory)帶電可擦除可編程隻讀存儲器,該類存儲器是用戶可更改的隻讀存儲器(ROM),其可通過高于普通電壓的作用來擦除和重編程(重寫)。EEPROM(常寫成E2PROM)是一種特殊形式的閃存,其應用通常是個人電腦中的電壓來擦寫和重編程。

E2PROM存儲器可分為片内E2PROM和片外E2PROM,片外E2PROM和單片機之間通過各種通信接口連接,而最為常見的通信接口即是I2C接口。一般情況下,E2PROM可寫入或擦除的次數是30~100萬次,而讀取次數是沒有限制的。

24C02芯片是一種常用的基于I2C通信協議的E2PROM元件,例如ATMEL公司的AT24C02、CATALYST公司的CAT24C02和ST公司的ST24C02等芯片。24C02芯片的存儲空間是256字節(2048位),當然如果需要更大存儲空間的存儲器可以選擇其他型号的,比如24C04芯片(512字節)、24C08芯片(1024字節)和24C16芯片(2048字節)。

24Cxx系列引腳定義是一緻的,這方便用戶在項目設計時,如遇到選擇的芯片的存儲空間不夠時,可在該系列中選擇存儲空間更大的芯片直接替換,而無需改動硬件部分。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)1

圖1:24C02芯片引腳

STC8A8K64S4A12開發闆上設計了可供用戶使用的AT24C02存儲器芯片,其中原理圖部分及硬件實物部分如下。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)2

圖2:開發闆外擴E2PROM存儲器

2.開發闆DAC硬件電路介紹

I2C總線(即IIC總線)是集成電路總線(Inter-Integrated Circuit)的縮寫,是一種簡單、雙向二線制同步串行總線。該I2C總線是1982年由荷蘭的Philips公司為了解決電視機内的CPU和外圍芯片之間連接而開發的,可以說電視機是最早的嵌入式系統之一。

I2C總線是一個真正的多主機總線,如果兩個或多個主機同時初始化數據傳輸,可以通過沖突檢測和仲裁防止數據破壞,每個連接到總線上的器件都有唯一的地址,任何器件既可以作為主機也可以作為從機,但同一時刻隻允許有一個主機。

2.1.主要特征

典型的I2C應用原理如下圖所示,I2C總線通信僅需兩根信号線,可以連接多個設備,從設備都有唯一的地址,主設備通過從設備的地址和不同的從設備通信。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)3

圖3:典型I2C總線結構

  1. I2C總線硬件結構簡單,僅需一根時鐘線(SCL)、一根數據線(SDA)和兩個上拉電阻即可實現通信。I2C總線的SCL和SDA均為開漏結構,開漏結構的電路隻能輸出“邏輯0”,無法輸出“邏輯1”,因此SCL和SDA需要連接上拉電阻。上拉電阻的阻值影響傳輸速率,阻值越大,由于RC影響,會帶來上升時間的增大,傳輸的速率慢,阻值小,傳輸的速率快,但是會增加電流的消耗,一般情況下,我們會選擇4.7K左右的阻值,在從機數量少,信号線短的情況下,可以适當增加阻值,如使用10K的阻值。
  2. I2C總線中的從設備必須有自己的地址,并且該地址在其所處的I2C總線中唯一,主設備通過此唯一的地址即可和該從設備進行數據傳輸。
  3. I2C總線支持多主機,但是同一時刻隻允許有一個主機。I2C總線中存在多個主機時,為了避免沖突,I2C總線通過總線仲裁決定由哪一個主機控制總線。
  4. I2C總線隻能傳輸8位的數據,數據速率在标準模式下可達100Kbit/s,快速模式下可達400Kbit/s,高速模式下可達3.4Mbit/s,另外一些變種實現了低速模式(10Kbps)和快速 模式(1Mbps)。
  5. 同時連接到同一個I2C總線上的設備數量受總線最大電容(400pF)的限制。
  6. I2C總線電流消耗很低,抗幹擾強,适合應用于低功耗的場合。
2.2.I2C地址

I2C總線中的設備必須要有唯一的地址,這意味着如果在總線中接入兩個相同的設備,該設備必須有配置地址的功能,這也是我們經常用的I2C接口的設備會有幾個引腳用來配置地址的原因。

對于I2C地址,我們經常看到有的I2C接口設備在規格書中描述的是7位地址,而有的I2C接口設備在規格書中描述的是8位地址,他們有什麼區别?(I2C也有10位地址,但用的較少,這裡不做介紹,本文檔中的内容不涉及到10位地址)。

7位地址和8位地址如下圖所示,他們結構上是一樣的,都是由7個地址位加一個用來表示讀寫的位組成,隻是描述上有所區别。

  • 規格書中描述I2C地址是7位地址的設備:給出的是7個地址位加R/W位,最低位(R/W位)為0時表示為寫地址,最低位為1時為讀地址。如果把0和1分别帶入R/W位,得到的地址就和8位地址一樣了。
  • 規格書中描述I2C地址是8位地址的設備:直接給出寫地址和讀地址,也就是最低位(R/W位)為0時的地址和最低位為1時的地址。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)4

圖4:I2C地址

☆注:PCF8563時鐘芯片手冊上給出其I2C從機地址是8位,讀地址為0xA3,寫地址為0xA2。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)5

圖5:PCF8563芯片手冊描述

由此可見,所謂的7位地址和8位地址實際上都是7位地址加上最低位的讀寫位,本質上是一樣的,隻是各個I2C接口設備的描述方式不一樣。

I2C保留了如下表所示的兩組I2C地址,這些地址用于特殊用途。

表1:保留地址

序号

從機地址

R/W位

描述

1

0000 000

0

廣播呼叫地址。

2

0000 000

1

起始字節。

3

0000 001

X

CBUS 地址。

4

0000 010

X

保留給不同的總線格式。

5

0000 011

X

保留到将來使用。

6

0000 1XX

X

Hs 模式主機碼。

7

1111 1XX

X

保留到将來使用。

8

1111 0XX

X

10 位從機尋址。

2.3.I2C數據傳輸

■ 起始和停止條件(START and STOP conditions)

所有的I2C事務都是以START開始、STOP結束,起始和停止條件總是由主機産生,如下圖所示,當SCL為高電平時,SDA從高電平向低電平轉換表示起始條件,當SCL是高電平時,SDA由低電平向高電平轉換表示停止條件。如果總線中存在多個主機,先将SDA拉低的主機獲得總線控制權。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)6

圖6:起始和停止條件

■ 字節格式(Byte format)

I2C總線發送到SDA上的數據必須為8位,即一次傳輸一個字節,每次傳輸可以發送的字節數量不受限制。每個字節後必須跟一個響應位,首先傳輸的是數據的最高位MSB,如果從機要完成一些其他功能後,例如一個内部中斷服務程序才能接收或發送下一個完整的數據字節,那麼從機可以将時鐘線SCL保持為低電平強制主機進入等待狀态,當從機準備好接收下一個字節數據并釋放時鐘線SCL後數據傳輸繼續。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)7

圖7:I2C總線數據傳輸

2.4.ACK和NACK

每個字節後會跟随一個ACK信号。接收者通過ACK位告知發送者已經成功接收一字節數據并準備好接收下一字節數據。所有的時鐘脈沖包括ACK信号的時鐘脈沖都是由主機産生的。

  1. ACK信号:發送者發送完8位數據後,在ACK時鐘脈沖期間釋放SDA線,接收者可以将SDA拉低并在時鐘信号為高時保持低電平,這樣就産生了ACK信号,從而使得主機知道從機已成功接收數據并且準備好了接收下一數據。
  2. NACK信号:當SDA在第9個時鐘脈沖的時候保持高電平,定義為NACK信号。這時,主機要麼産生STOP條件來放棄這次傳輸,要麼重複START條件來啟動一個新的傳輸。

下面的5種情況會導緻産生NACK信号:

  1. 發送方尋址的接收方在總線上不存在,因此總線上沒有設備應答。
  2. 接收方正在處理一些實時的功能,尚未準備好與主機通信,因此接收方不能執行收發。
  3. 在傳輸期間,接收方收到不能識别的數據或者命令。
  4. 在傳輸期間,接收方無法接收更多的數據字節。
  5. 主-接收器要通知從-發送器傳輸的結束。
2.5.從機地址和R/W位

I2C數據傳輸如下圖所示,在起始條件(S)後,發送從機地址,從機地址是7位,從機地址後緊跟着的第8位是讀寫位(R/W),讀寫位為0表示寫,讀寫位為1表示讀。數據傳輸一般由主機産生的停止位P 終止,但是,如果主機仍希望在總線上通信,他可以産生重複起始條件 S和尋址另一個從機而不是首先産生一個停止條件,在這種傳輸中可能有不同的讀寫格式結合。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)8

圖8:I2C總線傳輸時序

可能的數據傳輸格式有:

  1. 主機發送器發送到從機接收器,傳輸的方向不會改變,接收器應答每一個字節,如下圖所示。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)9

圖9:主機發送器7位地址尋址從機接收器(傳輸方向不改變)

  1. 在第一個字節後,主機立即讀從機,在第一次應答後,主機發送器變成主機接收器,從機接收器變成從機發送器。第一次應答仍由從機生成,主機生成後續應答。之前發送了一個非應答(A)的主機産生STOP條件。

圖10:主機發送第一個字節後立即讀取從機

  1. 複合格式,如下圖所示。傳輸改變方向的時侯,起始條件和從機地址都會被重複,但R/W位取反。如果主接收器發送重複START條件,他會在重複START條件之前發送一個非應答(A)。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)10

圖11:複合格式

3.STC8A8K64S4A12系列單片機I2C介紹

STC8A8K64S4A12系列單片機片内集成了1個I2C串行總線控制器,與标準I2C總線一樣,STC8A8K64S4A12系列單片機的I2C總線支持兩種操作模式:主模式和從模式。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)11

圖12:I2C總線工作模式

但需要知道STC8A8K64S4A12系列單片機的I2C協議與标準I2C協議相比較,有以下2種機制被忽略。

  1. 發送起始信号(START)後不進行仲裁。
  2. 時鐘信号(SCL)停留在低電平時不進行超時檢測。

STC8A8K64S4A12系列單片機的每一組I2C都有2個IO引腳供選擇使用,如下表所示。.

表2:單片機I2C外設引腳分配

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)12

☆注:獨立GPIO表示開發闆沒有其他的電路使用這個GPIO,非獨立GPIO說明開發闆有其他電路用到了該GPIO。須知同一時刻隻能使能一組IO口作為I2C使用。

STC8A8K64S4A12系列單片機I2C使用哪一組IO口由P_SW2外設端口切換寄存器2的B4、B5位決定,如下圖所示。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)13

圖13:外設端口切換寄存器2

☆注:一般P_SW2寄存器B4、B5位默認是0,即如果沒有對P_SW2寄存器進行操作,則默認選擇的I2C是P1.4、P1.5這一組。

二、軟件設計1.I2C相關寄存器彙集

STC8A8K64S4A12系列單片機使用I2C外設時會用到10個寄存器,如下表所示:

表3:STC8A8K64S4A12系列I2C使用寄存器彙總

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)14

2.寄存器解析2.1.I2C配置寄存器I2CCFG

I2C配置寄存器控制I2C外設使能選擇、工作模式、總線速度等,詳見下圖。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)15

圖14:I2C配置寄存器I2CCFG

2.2.I2C主機控制寄存器I2CMSCR

I2CMSCR主機控制寄存器的配置是針對I2C已配置為主機模式才有意義的,該寄存器的B7位用來控制主機模式的中斷是否打開,B0~B3位為主機模式下的命令,此部分是重點,詳見下圖。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)16

圖15:I2C主機控制寄存器I2CMSCR

2.3.I2C主機輔助控制寄存器I2CMSAUX

當配置I2C總線為主機模式時,雖然可以按照I2C标準協議,控制I2CMSCR寄存器發送主機命令,但很多場合還是希望可以簡化這個控制流程。I2CMSAUX寄存器的B0位可以幫助用戶實現I2C自動發送數據并接收ACK信号。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)17

圖16:I2C主機輔助控制寄存器I2CMSAUX

2.4.I2C主機狀态寄存器I2CMSST

I2C主機狀态寄存器B7位是可讀位,用來讀取I2C控制器是否處于忙狀态(BUSY),I2CMSST寄存器B6位是I2C控制器執行I2C主機命令後的中斷标志位,需軟件清零。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)18

圖17:I2C主機狀态寄存器I2CMSST

2.5.I2C從機控制寄存器I2CSLCR

I2CSLCR從機控制寄存器可控制處于從機模式下的I2C設備是否使能接收START信号、接收STOP信号、接收1字節數據、發送1字節數據等的中斷功能,詳見下圖。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)19

圖18:I2C從機控制寄存器I2CSLCR

2.6.I2C從機狀态寄存器I2CSLST

I2C從機控制寄存器使能了接收START信号、接收STOP信号、接收1字節數據、發送1字節數據等的中斷功能後,I2C從機狀态寄存器I2CSLST不僅可讀取I2C控制器是否處于忙狀态(BUSY),還可以對接收START信号、接收STOP信号、接收1字節數據、發送1字節數據等的中斷标志位進行讀取,但這些位需軟件清零。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)20

圖19:I2C從機狀态寄存器I2CSLST

2.7.I2C從機地址寄存器I2CSLADR

I2C從機地址寄存器B1~B7位是從機設備地址位,STC8A8K64S4A12系列單片機的I2C外設又配置有B0位(MA位),用來設置是否忽略對從機設備地址的匹配。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)21

圖20:I2C從機地址寄存器I2CSLADR

☆注:前面有介紹I2C設備的地址是7位,此處I2C從機設備地址即是7位。

3.I2C配置步驟

針對STC8A8K64S4A12系列單片機I2C,軟件的配置過程如下:

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)22

圖21:I2C中斷方式和非中斷方式軟件配置步驟

4.外部EEPROM存儲器讀寫單字節實驗(模拟I2C)

☆注:本節的實驗源碼是在“實驗2-8-1:串口1收發實驗(P3.0和P3.1)”的基礎上修改。本節對應的實驗源碼是:“實驗2-14-1:外部EEPROM存儲器讀寫單字節實驗(模拟I2C)”。

4.1.工程需要用到的c文件

本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。

表4:實驗需要用到的c文件

序号

文件名

後綴

功能描述

1

uart

.c

包含與用戶uart有關的用戶自定義函數。

2

i2c

.c

包含與用戶i2c通信有關的用戶自定義函數。

3

at24cxx

.c

操作AT24C系列存儲器相關的用戶自定義函數。

4

delay

.c

包含用戶自定義延時函數。

4.2.頭文件引用和路徑設置

■ 需要引用的頭文件

#include "delay.h" #include "at24cxx.h" #include "uart.h"

■ 需要包含的頭文件路徑

本例需要包含的頭文件路徑如下表:

表5:頭文件包含路徑

序号

路徑

描述

1

…\ Source

uart.h、i2c.h、at24cxx.h和delay.h頭文件在該路徑,所以要包含。

2

…\Use

STC8.h頭文件在該路徑,所以要包含。

MDK中點擊魔術棒,打開工程配置窗口,按照下圖所示添加頭文件包含路徑。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)23

圖22:添加頭文件包含路徑

4.3.編寫代碼

首先,在i2c.c文件中編寫模拟i2c總線通信的基本函數,如下表所示。

表6:模拟i2c總線通信的相關函數彙集

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)24

關于每個模拟i2c總線通信的相關函數,下面給出詳細代碼。

程序清單:模拟I2C總線産生啟動信号

/*************************************************************************** * 描 述 : 模拟I2C總線産生啟動信号 * 入 參 : 無 * 返回值 : FALSE 報錯 TRUE 啟動成功 **************************************************************************/ bit I2C_Start(void) { SDA = 1; //I2C數據線置高電平 SCL = 1; //I2C時鐘線置高電平 Delay10us(); if(!SDA) return FALSE; //判斷SDA線為低電平則總線忙,退出 SDA = 0; //判斷SDA線為高電平則控制SDA為低,即SDA出現一個下降沿表示啟動I2C Delay10us(); if(SDA) return FALSE; //判斷SDA線為高電平則總線出錯,退出 SDA = 0; //判斷SDA線為低電平則依然拉低SDA Delay10us(); return TRUE; }

程序清單:模拟I2C總線産生停止信号

/*************************************************************************** * 描 述 : 模拟I2C總線産生停止信号 * 入 參 : 無 * 返回值 : 無 **************************************************************************/ void I2C_Stop(void) { SDA = 0; //I2C數據線置低電平 Delay10us(); SCL = 1; //I2C時鐘線置高電平 Delay10us(); SDA = 1; //當SCL線為高電平時則SDA出現一個上升沿表示停止I2C Delay10us(); }

程序清單:模拟I2C總線發送ACK命令

/*************************************************************************** * 描 述 : 模拟I2C總線發送ACK命令 * 入 參 : 無 * 返回值 : 無 **************************************************************************/ void I2C_Ack(void) { SCL = 0; //I2C時鐘線置低電平 Delay10us(); SDA = 0; //I2C數據線置低電平 Delay10us(); SCL = 1; //I2C時鐘線置高電平 Delay10us(); SCL = 0; //I2C時鐘線置低電平,完成了在SCL線上産生一個時鐘,此時SDA為低電平 Delay10us(); }

程序清單:模拟I2C總線發送NACK應答命令

/*************************************************************************** * 描 述 : 模拟I2C總線發送NACK應答命令 * 入 參 : 無 * 返回值 : 無 **************************************************************************/ void I2C_NoAck(void) { SCL = 0; //I2C時鐘線置低電平 Delay10us(); SDA = 1; //I2C數據線置高電平 Delay10us(); SCL = 1; //I2C時鐘線置高電平 Delay10us(); SCL = 0; //I2C時鐘線置低電平,完成了在SCL線上産生一個時鐘,此時SDA為高電平 Delay10us(); }

程序清單:模拟I2C總線接收ACK命令

/*************************************************************************** * 描 述 : 模拟I2C總線接收ACK命令 * 入 參 : 無 * 返回值 : FALSE 無ACK ; TRUE 有ACK **************************************************************************/ bit I2C_Check_ACK(void) { SCL = 0; //I2C時鐘線置低電平 Delay10us(); SDA = 1; //I2C數據線置高電平 Delay10us(); SCL = 1; //I2C時鐘線置高電平 Delay10us(); if(SDA) //判斷SDA線為高電平 { SCL = 0; //I2C時鐘線置低電平,完成了在SCL線上産生一個時鐘,此時SDA為高電平 return FALSE; } SCL = 0; //I2C時鐘線置低電平,完成了在SCL線上産生一個時鐘,此時SDA為低電平 return TRUE; }

程序清單:模拟I2C總線發送數據

/*************************************************************************** * 描 述 : 模拟I2C總線發送數據(數據從高位到低位) * 入 參 : 無 * 返回值 : FALSE 無ACK ; TRUE 有ACK **************************************************************************/ void I2C_SendByte(uint8 SendByte) { uint8 i=8; while(i--) { SCL = 0; Delay10us(); if(SendByte&0x80) SDA = 1; else SDA = 0; SendByte<<=1; Delay10us(); SCL = 1; Delay10us(); } SCL = 0; }

程序清單:模拟I2C總線接收數據

/*************************************************************************** * 描 述 : 模拟I2C總線接收數據 * 入 參 : 無 * 返回值 : I2C總線返回的數據 **************************************************************************/ uint8 I2C_ReceiveByte(void) { uint8 i=8; uint8 ReceiveByte=0; SDA = 1; while(i--) { ReceiveByte<<=1; SCL = 0; Delay10us(); SCL = 1; Delay10us(); if(SDA) { ReceiveByte|=0x01; } } SCL = 0; return ReceiveByte; }

然後,在at24cxx.c文件中編寫對E2PROM存儲器的基本操作函數,如下表所示。

序号

函數名

功能描述

1

AT24CXX_RcvOneByte

從E2PROM指定地址讀取單字節數據。

2

AT24CXX_SendOneByte

向E2PROM指定地址存入單字節數據。

3

AT24CXX_SendLenByte

向E2PROM指定地址存入多字節數據。

4

AT24CXX_RcvLenByte

從E2PROM指定地址讀取多字節數據。

5

AT24CXX_EraseOneByte

擦除E2PROM指定地址單字節數據。

6

AT24CXX_EraseAll

擦除整個E2PROM芯片。

關于每個操作外部E2PROM相關用戶函數,下面給出詳細代碼。

程序清單:從指定地址讀取單字節數據函數

/*********************************************************************************** * 描 述 : 從芯片AT24CXX指定地址讀取單字節數據 * 入 參 : 開始讀數據的地址 * 返回值 : 讀到的數據 ***********************************************************************************/ uint8 AT24CXX_RcvOneByte(uint16 Addr) { uint8 temp=0; I2C_Start(); //啟動總線 if(E2PROM_TYPE > AT24C16) { I2C_SendByte(SLAW); //發送寫命令 I2C_Check_ACK(); //等待應答 I2C_SendByte(Addr>>8); //發送高地址 I2C_Check_ACK(); //等待應答 }else I2C_SendByte(SLAW ((Addr/256)<<1)); //發送器件地址,寫數據 I2C_Check_ACK(); //等待應答 I2C_SendByte(Addr%6); //發送低地址 I2C_Check_ACK(); //等待應答 I2C_Start(); //啟動總線 I2C_SendByte(SLAR); //設置為讀模式 I2C_Check_ACK(); //等待應答 temp=I2C_ReceiveByte(); //讀字節 I2C_Stop(); //結束總線 return temp; }

程序清單:向指定地址存入單字節數據函數

/*********************************************************************************** * 描 述 : 向芯片AT24CXX指定地址寫入單字節數據 * 入 參 : Addr:寫入的目的起始地址 Data:要寫入的數據 * 返回值 : 無 ***********************************************************************************/ void AT24CXX_SendOneByte(uint16 Addr,uint8 Data) { I2C_Start(); //啟動總線 if(E2PROM_TYPE > AT24C16) { I2C_SendByte(SLAW); //發送寫命令 I2C_Check_ACK(); //等待應答 I2C_SendByte(Addr>>8); //發送高地址 }else I2C_SendByte(SLAW ((Addr/256)<<1)); //發送器件地址,寫數據 I2C_Check_ACK(); //等待應答 I2C_SendByte(Addr%6); //發送低地址 I2C_Check_ACK(); //等待應答 I2C_SendByte(Data); //發送字節數據 I2C_Check_ACK(); //等待應答 I2C_Stop(); //結束總線 delay_ms(10); //該延時保證連續發送字節的穩定性 }

程序清單:向指定地址存入多字節數據函數

/*********************************************************************************** * 描 述 : 向芯片AT24CXX裡面的指定地址開始寫入長度為Len的數據 * 入 參 : Addr:寫入的目的起始地址 Data:要寫入的數據 Len:要寫入數據的長度 * 返回值 : 無 ***********************************************************************************/ void AT24CXX_SendLenByte(uint16 Addr,uint8 *Data,uint16 Len) { while(Len--) { AT24CXX_SendOneByte(Addr,*Data); Addr ; Data ; } }

程序清單:從指定地址讀取多字節數據函數

/*********************************************************************************** * 描 述 : 從芯片AT24CXX裡面的指定地址開始讀出長度為Len的數據 * 入 參 : Addr:讀出的目的起始地址 Data:讀出的數據 Len:要讀出數據的長度 * 返回值 : 無 ***********************************************************************************/ void AT24CXX_RcvLenByte(uint16 Addr,uint8 *Data,uint16 Len) { while(Len) { *Data = AT24CXX_RcvOneByte(Addr ); Len--; } }

程序清單:從指定地址擦除單字節數據函數

/*********************************************************************************** * 描 述 : 擦除芯片AT24CXX指定地址數據 * 入 參 : Addr:要擦除的目的地址 * 返回值 : 無 ***********************************************************************************/ void AT24CXX_EraseOneByte(uint16 Addr) { AT24CXX_SendOneByte(Addr,0xFF); }

程序清單:擦除整片數據函數

/************************************************************************************ 功能描述:擦除整個芯片AT24CXX(即芯片存儲單元數據都是0xFF) 入口參數:無 返回值:無 備注: 不同的存儲芯片,存儲空間不同,AT24CXX_SIZE數值不同。 *************************************************************************************/ void AT24CXX_EraseAll(void) { uint16 i; // 填充緩沖區 for (i = 0; i < AT24CXX_SIZE; i ) { AT24CXX_SendOneByte(i,0xFF); } }

最後,在主函數中對串口1進行初始化,并通過串口1發送不同的命令實現對單片機片外E2PROM的單字節讀、寫及擦除等操作。

代碼清單:主函數

int main(void) uint8 Temp; P3M1 &= 0xFE; P3M0 &= 0xFE; //設置P3.0為準雙向口 P3M1 &= 0xFD; P3M0 |= 0x02; //設置P3.1為推挽輸出 Uart1_Init(); //串口1初始化 EA = 1; //使能總中斷 delay_ms(10); //初始化後延時 while(1) { if(WriteFLAG) //寫模式 { WriteFLAG=0; //寫标志變量清零,發送一次 AT24CXX_SendOneByte(0x0010,0x33); //在地址0x0010位置寫入1個字節數據0x33 SendDataByUart1(0x33); //串口1發送數據0x33表示寫操作完成 } if(ReadFLAG) //讀模式 { ReadFLAG=0; //讀标志變量清零,發送一次 Temp=AT24CXX_RcvOneByte(0x0010); //在地址0x0010位置處讀取1個字符 SendDataByUart1(Temp); //串口1發送讀取的字符 } if(ClearFLAG) //清除模式 { ClearFLAG=0; //清除标志變量清零,發送一次 AT24CXX_EraseOneByte(0x0010); //擦除地址0x0010位置處數據 SendDataByUart1(0x00); //串口1發送數據0x00表示擦除完成 } }

4.4.硬件連接

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)25

圖23:開發闆連接圖

5.外部EEPROM存儲器讀寫多字節實驗(模拟I2C)5.1.編寫代碼

首先,在at24cxx.c文件中編寫模拟I2C方式的讀寫字節函數和對E2PROM存儲器的基本操作函數。請參考“實驗2-14-1:外部EEPROM存儲器讀寫單字節實驗(模拟I2C)”部分。

然後,在主函數中對串口1進行初始化,并通過串口1發送不同的命令實現對單片機片外E2PROM的多字節讀、寫及擦除等操作。

代碼清單:主函數

int main(void) { P3M1 &= 0xFE; P3M0 &= 0xFE; //設置P3.0為準雙向口 P3M1 &= 0xFD; P3M0 |= 0x02; //設置P3.1為推挽輸出 Uart1_Init(); //串口1初始化 EA = 1; //使能總中斷 delay_ms(10); //初始化後延時 while(1) { if(WriteFLAG) //寫模式 { WriteFLAG=0; //寫标志變量清零,發送一次 AT24CXX_SendLenByte(0x0010,scan,E2PROM_Length); //向E2PROM起始地址0x0010中連續寫入scan數組中的E2PROM_Length個字節數據 SendDataByUart1(0x33); //串口1發送數據0x33表示寫操作完成 } if(ReadFLAG) //讀模式 { ReadFLAG=0; //讀标志變量清零,發送一次 AT24CXX_RcvLenByte(0x0010,buffer,E2PROM_Length); //從E2PROM地址0x0010開始連續讀取E2PROM_Length字節數據并存入到buffer數組中 SendStringByUart1_n(buffer,E2PROM_Length); //串口1發送數組buffer中的值(即讀取的多字節數據) } if(ClearFLAG) //清除模式 { ClearFLAG=0; //清除标志變量清零,發送一次 AT24CXX_EraseAll(); //擦除整片,需要一定的耗時 SendDataByUart1(0x00); //串口1發送數據0x00表示擦除完成 } } }

5.2.硬件連接

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)26

圖24:開發闆連接圖

6.外部EEPROM存儲器讀寫單字節實驗(硬件I2C)6.1.工程需要用到的c文件

本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。

表8:實驗需要用到的c文件

序号

文件名

後綴

功能描述

1

uart

.c

包含與用戶uart有關的用戶自定義函數

2

i2c

.c

包含與用戶i2c通信有關的用戶自定義函數

3

at24cxx

.c

操作AT24C系列存儲器相關的用戶自定義函數

4

delay

.c

包含用戶自定義延時函數

6.2.頭文件引用和路徑設置

■ 需要引用的頭文件

#include "delay.h" #include "at24cxx.h" #include "uart.h"

■ 需要包含的頭文件路徑

本例需要包含的頭文件路徑如下表:

表9:頭文件包含路徑

序号

路徑

描述

1

…\ Source

uart.h、i2c.h、at24cxx.h和delay.h頭文件在該路徑,所以要包含

2

…\User

STC8.h頭文件在該路徑,所以要包含

MDK中點擊魔術棒,打開工程配置窗口,按照下圖所示添加頭文件包含路徑。

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)27

圖25:添加頭文件包含路徑

6.3.編寫代碼

首先,在i2c.c文件中對硬件I2C進行初始化,并編寫硬件I2C總線通信的基本函數,如下表所示。

表8:實驗需要用到的c文件

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)28

關于每個硬件i2c總線通信的相關函數,下面給出詳細代碼。

程序清單:硬件I2C初始化函數

/*************************************************************************** * 描 述 : I2C初始化函數 * 入 參 : 無 * 返回值 : 無 **************************************************************************/ void I2C_init(void) { P_SW2 |= 0x80; //将EAXFR位置1,以訪問在XDATA區域的擴展SFR P_SW2 &= 0xCF; //将I2C_S[1:0]置10,以選擇I2C硬件功能腳為P7.6 P7.7 P_SW2 |= 0x20; //将I2C_S[1:0]置10,以選擇I2C硬件功能腳為P7.6 P7.7 I2CCFG=0xE0; //使能I2C主機模式,I2C總線速度為等待65個時鐘數 I2CMSST=0x00; //清零I2C主機狀态寄存器各标志位 // P_SW2 &= 0x7F; //将EAXFR位置0,恢複訪問XRAM }

程序清單:硬件I2C總線等待中斷标志位函數

/*************************************************************************** * 描 述 : I2C總線等待中斷标志位 * 入 參 : 無 * 返回值 : 無 **************************************************************************/ void I2C_Wait(void) { while(!(I2CMSST&0x40)); //等待I2C主機狀态寄存器的中斷标志位置1 I2CMSST &= 0xBF; //主機模式中斷标志位軟件清零 }

程序清單:硬件I2C總線産生啟動信号函數

/*************************************************************************** * 描 述 : I2C總線産生啟動信号 * 入 參 : 無 * 返回值 : 無 **************************************************************************/ void I2C_Start(void) { I2CMSCR=0x01; //關閉主機模式中斷并發送主機命令:0001(起始命令) I2C_Wait(); //等待中斷标志位置1 }

程序清單:硬件I2C總線産生停止信号函數

/*************************************************************************** * 描 述 : I2C總線産生停止信号 * 入 參 : 無 * 返回值 : 無 **************************************************************************/ void I2C_Stop(void) { I2CMSCR=0x06; //關閉主機模式中斷并發送主機命令:0110(發送STOP命令) I2C_Wait(); //等待中斷标志位置1 }

程序清單:硬件I2C總線發送ACK命令函數

/*************************************************************************** * 描 述 : I2C總線發送ACK命令 * 入 參 : 無 * 返回值 : 無 **************************************************************************/ void I2C_SendACK(void) { I2CMSST=0x00; //設置ACK信号 I2CMSCR=0x05; //關閉主機模式中斷并發送主機命令:0101(發送ACK命令) I2C_Wait(); //等待中斷标志位置1 }

程序清單:硬件I2C總線發送NACK應答命令函數

/*************************************************************************** * 描 述 : I2C總線發送NACK應答命令 * 入 參 : 無 * 返回值 : 無 **************************************************************************/ void I2C_SendNAK(void) { I2CMSST=0x01; //設置NACK信号 I2CMSCR=0x05; //關閉主機模式中斷并發送主機命令:0101(發送ACK命令) I2C_Wait(); //等待中斷标志位置1 }

程序清單:硬件I2C總線接收ACK命令函數

/*************************************************************************** * 描 述 : I2C總線接收ACK命令 * 入 參 : 無 * 返回值 : 無 **************************************************************************/ void I2C_RecvACK(void) { I2CMSCR=0x03; //關閉主機模式中斷并發送主機命令:0011(接收ACK命令) I2C_Wait(); //等待中斷标志位置1 }

程序清單:硬件I2C總線發送數據函數

/*************************************************************************** * 描 述 : I2C總線發送數據 * 入 參 : 無 * 返回值 : 無 **************************************************************************/ void I2C_SendData(uint8 dat) { I2CTXD=dat; //寫數據到數據緩沖區 I2CMSCR=0x02; //關閉主機模式中斷并發送主機命令:0010(發送數據命令) I2C_Wait(); //等待中斷标志位置1 }

程序清單:硬件I2C總線接收數據函數

/*************************************************************************** * 描 述 : I2C總線接收數據 * 入 參 : 無 * 返回值 : I2C總線返回的數據 **************************************************************************/ uint8 I2C_RecvData(void) { I2CMSCR=0x04; //關閉主機模式中斷并發送主機命令:0100(接收數據命令) I2C_Wait(); //等待中斷标志位置1 return I2CRXD; }

然後,在at24cxx.c文件中編寫對E2PROM存儲器的基本操作函數,如下表所示。

表11:E2PROM相關用戶函數彙集

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)29

關于每個操作外部E2PROM相關用戶函數,下面給出詳細代碼。

程序清單:從指定地址讀取單字節數據函數

/*********************************************************************************** * 描 述 : 在芯片AT24CXX指定地址讀出一個數據 * 入 參 : 開始讀數據的地址 * 返回值 : 讀到的數據 ***********************************************************************************/ uint8 AT24CXX_RcvOneByte(uint16 Addr) { uint8 temp=0; I2C_Start(); //啟動總線 if(E2PROM_TYPE > AT24C16) { I2C_SendData(SLAW); //發送寫命令 I2C_RecvACK(); //等待應答 I2C_SendData(Addr>>8); //發送高地址 I2C_RecvACK(); //等待應答 }else I2C_SendData(SLAW ((Addr/256)<<1)); //發送器件地址,寫數據 I2C_RecvACK(); //等待應答 I2C_SendData(Addr%6); //發送低地址 I2C_RecvACK(); //等待應答 I2C_Start(); //啟動總線 I2C_SendData(SLAR); //設置為讀模式 I2C_RecvACK(); //等待應答 temp=I2C_RecvData(); //讀字節 I2C_Stop(); //結束總線 return temp; }

程序清單:向指定地址存入單字節數據函數

/*********************************************************************************** * 描 述 : 在芯片AT24CXX指定地址寫入一個數據 * 入 參 : Addr:寫入的目的起始地址 Data:要寫入的數據 * 返回值 : 無 ***********************************************************************************/ void AT24CXX_SendOneByte(uint16 Addr,uint8 Data) { I2C_Start(); //啟動總線 if(E2PROM_TYPE > AT24C16) { I2C_SendData(SLAW); //發送寫命令 I2C_RecvACK(); //等待應答 I2C_SendData(Addr>>8); //發送高地址 I2C_RecvACK(); //等待應答 }else I2C_SendData(SLAW ((Addr/256)<<1)); //發送器件地址,寫數據 I2C_RecvACK(); //等待應答 I2C_SendData(Addr%6); //發送低地址 I2C_RecvACK(); //等待應答 I2C_SendData(Data); //發送字節數據 I2C_RecvACK(); //等待應答 I2C_Stop(); //結束總線 delay_ms(10); //該延時保證連續發送字節的穩定性 }

程序清單:向指定地址存入多字節數據函數

/*********************************************************************************** * 描 述 : 向芯片AT24CXX裡面的指定地址開始寫入長度為Len的數據 * 入 參 : Addr:寫入的目的起始地址 Data:要寫入的數據 Len:要寫入數據的長度 * 返回值 : 無 ***********************************************************************************/ void AT24CXX_SendLenByte(uint16 Addr,uint8 *Data,uint16 Len) { while(Len--) { AT24CXX_SendOneByte(Addr,*Data); Addr ; Data ; } }

程序清單:從指定地址讀取多字節數據函數

/*********************************************************************************** * 描 述 : 從芯片AT24CXX裡面的指定地址開始讀出長度為Len的數據 * 入 參 : Addr:讀出的目的起始地址 Data:讀出的數據 Len:要讀出數據的長度 * 返回值 : 無 ***********************************************************************************/ void AT24CXX_RcvLenByte(uint16 Addr,uint8 *Data,uint16 Len) { while(Len) { *Data = AT24CXX_RcvOneByte(Addr ); Len--; } }

程序清單:從指定地址擦除單字節數據函數

/*********************************************************************************** * 描 述 : 擦除芯片AT24CXX指定地址數據 * 入 參 : Addr:要擦除的目的地址 * 返回值 : 無 ***********************************************************************************/ void AT24CXX_EraseOneByte(uint16 Addr) { AT24CXX_SendOneByte(Addr,0xFF); }

程序清單:擦除整片數據函數

/*********************************************************************************** 功能描述:擦除整個芯片AT24CXX(即芯片存儲單元數據都是0xFF) 入口參數:無 返回值:無 備注: 不同的存儲芯片,存儲空間不同,AT24CXX_SIZE數值不同。 ************************************************************************************/ void AT24CXX_EraseAll(void) { uint16 i; // 填充緩沖區 for (i = 0; i < AT24CXX_SIZE; i ) { AT24CXX_SendOneByte(i,0xFF); } }

最後,在主函數中對串口1和I2C進行初始化,并通過串口1發送不同的命令實現對單片機片外E2PROM的單字節讀、寫及擦除等操作。

代碼清單:主函數

int main(void) { uint8 Temp; P3M1 &= 0xFE; P3M0 &= 0xFE; //設置P3.0為準雙向口 P3M1 &= 0xFD; P3M0 |= 0x02; //設置P3.1為推挽輸出 I2C_init(); //IIC初始化 Uart1_Init(); //串口1初始化 EA = 1; //使能總中斷 delay_ms(10); //初始化後延時 while(1) { if(WriteFLAG) //寫模式 { WriteFLAG=0; //寫标志變量清零,發送一次 AT24CXX_SendOneByte(0x0010,0x33); //在地址0x0010位置寫入1個字節數據0x33 SendDataByUart1(0x33); //串口1發送數據0x33表示寫操作完成 } if(ReadFLAG) //讀模式 { ReadFLAG=0; //讀标志變量清零,發送一次 Temp=AT24CXX_RcvOneByte(0x0010); //在地址0x0010位置處讀取1個字符 SendDataByUart1(Temp); //串口1發送讀取的字符 } if(ClearFLAG) //清除模式 { ClearFLAG=0; //清除标志變量清零,發送一次 AT24CXX_EraseOneByte(0x0010); //擦除地址0x0010位置處數據 SendDataByUart1(0x00); //串口1發送數據0x00表示擦除完成 } } }

6.4.硬件連接

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)30

圖26:開發闆連接圖

7.外部EEPROM存儲器讀寫多字節實驗(硬件I2C)7.1.編寫代碼

首先,在at24cxx.c文件中編寫硬件I2C方式的讀寫字節函數和對E2PROM存儲器的基本操作函數。請參考“實驗2-14-3:外部EEPROM存儲器讀寫單字節實驗(硬件I2C)”部分。

然後,在主函數中對串口1和I2C進行初始化,并通過串口1發送不同的命令實現對單片機片外EEPROM的多字節讀、寫及擦除等操作。

代碼清單:主函數

int main(void) P3M1 &= 0xFE; P3M0 &= 0xFE; //設置P3.0為準雙向口 P3M1 &= 0xFD; P3M0 |= 0x02; //設置P3.1為推挽輸出 I2C_init(); //IIC初始化 Uart1_Init(); //串口1初始化 EA = 1; //使能總中斷 delay_ms(10); //初始化後延時 while(1) { if(WriteFLAG) //寫模式 { WriteFLAG=0; //寫标志變量清零,發送一次 AT24CXX_SendLenByte(0x0010,scan,E2PROM_Length); //向E2PROM起始地址0x0010中連續寫入scan數組中的E2PROM_Length個字節數據 SendDataByUart1(0x33); //串口1發送數據0x33表示寫操作完成 } if(ReadFLAG) //讀模式 { ReadFLAG=0; //讀标志變量清零,發送一次 AT24CXX_RcvLenByte(0x0010,buffer,E2PROM_Length); //從E2PROM地址0x0010開始連續讀取E2PROM_Length字節數據并存入到buffer數組中 SendStringByUart1_n(buffer,E2PROM_Length); //串口1發送數組buffer中的值(即讀取的多字節數據) } if(ClearFLAG) //清除模式 { ClearFLAG=0; //清除标志變量清零,發送一次 AT24CXX_EraseAll(); //擦除整片,需要一定的耗時 SendDataByUart1(0x00); //串口1發送數據0x00表示擦除完成 } }

7.2.硬件連接

STC8A8K64S4A12開發闆片外存儲器E2PROM講解(STC8A8K64S4A12開發闆片外存儲器E2PROM講解)31

圖27:開發闆連接圖

總結

以上是今天要講的内容,希望對大家有幫助,如果有啥不明白的,歡迎讨論哦!

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关圖文资讯推荐

热门圖文资讯推荐

网友关注

Copyright 2023-2025 - www.tftnews.com All Rights Reserved