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

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

3天內(nèi)不再提示

EEPROM存儲實驗

汽車電子技術(shù) ? 來源:滑小稽筆記 ? 作者:電子技術(shù)園地 ? 2023-03-01 14:54 ? 次閱讀

16.1 EEPROM概述

EEPROM(Electrically Erasable Programmable read only memory),稱為帶電可擦除可編程只讀存儲器,是一種可以斷電保存數(shù)據(jù)的存儲芯片,EEPROM可以在電腦上或?qū)S迷O(shè)備上擦除已有信息,重新編程,一般用在即插即用設(shè)備中,這種存儲芯片可以通過高于普通電壓的作用來擦除或重寫,EEPROM芯片一般用在需要頻繁存儲數(shù)據(jù),但是數(shù)據(jù)量不大的場合,本實驗以Atmel公司設(shè)計的AT24C02為例,來詳細描述EEPROM的基本操作。

AT24C02是一片存儲容量在2Kbit的的存儲芯片,即存儲容量512Byte,通過IIC總線協(xié)議進行數(shù)據(jù)通信STM32F1內(nèi)置的IIC模塊,但是由于當時設(shè)計的時候為了規(guī)避飛利浦關(guān)于IIC通信協(xié)議的專利技術(shù),將IIC設(shè)計的比較復雜,并且當操作不當?shù)臅r候容易鎖住總線,但是ST公司關(guān)于硬件IIC方面也提出了對應(yīng)的軟件解決方案,我們在這個存儲實驗中采用IO口模擬IIC協(xié)議與硬件IIC模塊兩種方式來實現(xiàn)EEPROM存儲。

IIC是一種只利用兩根線來進行數(shù)據(jù)交換的串行通信協(xié)議,IIC的電氣線路包括兩根線,即時鐘線SCL和數(shù)據(jù)線SDA,高速IIC總線一般可達400kbps以上,在傳送過程中一共有三種類型的信號,分別是開始信號,結(jié)束信號和應(yīng)答信號,我們在51單片機開發(fā)中曾將IIC協(xié)議通過端口模擬成功的控制了EEPROM的讀寫,現(xiàn)在只需要將之前的代碼移植過來修改一下底層寄存器即可使用。STM32F1系列的硬件IIC結(jié)構(gòu)框圖如下圖所示。

圖片

從結(jié)構(gòu)可以發(fā)現(xiàn),STM32的硬件IIC模塊我們只需要配置好寄存器,然后既可以不考慮具體的IIC協(xié)議,直接讀數(shù)據(jù)寄存器就可以獲取到總線上的數(shù)據(jù),這也是硬件IIC的優(yōu)勢所在。

16.2 AT24C02通信時序

16.2.1 寫時序

(1)寫1個字節(jié)

圖片

第1步:發(fā)送開始信號

第2步:發(fā)送器件7位地址+1位讀寫控制后等待芯片應(yīng)答

第3步:發(fā)送寫入的地址后等待芯片應(yīng)答

第4步:寫入需要存儲的數(shù)據(jù)后等待芯片應(yīng)答

第5步:發(fā)送結(jié)束信號

第6步:等待20ms左右

(2)寫n個字節(jié)

圖片

寫n個字節(jié)適用于在連續(xù)的n個地址上寫入n個數(shù)據(jù),當需要寫入n個數(shù)據(jù)的時候,這種連續(xù)寫的方式比單個寫的速度有顯著性優(yōu)勢,具體步驟如下。

第1步:發(fā)送開始信號

第2步:發(fā)送器件7位地址+1位讀寫控制后等待芯片應(yīng)答

第3步:發(fā)送寫入的地址后等待芯片應(yīng)答

第4步:寫入需要存儲的數(shù)據(jù)1后等待芯片應(yīng)答

……

第n+4步:寫入需要存儲的數(shù)據(jù)n后等待芯片應(yīng)答

第n+5步:發(fā)送結(jié)束信號

第n+6步:等待20ms左右

注:AT24C系列芯片進行1次完整的寫時序,必須等待5ms以上,手冊給出的典型值是5ms,一般默認20ms。

16.2.2 讀時序

(1)讀1個字節(jié)

圖片

第1步:發(fā)送開始信號

第2步:發(fā)送器件7位地址+1位讀寫控制后等待芯片應(yīng)答

第3步:發(fā)送寫入的地址后等待芯片應(yīng)答

第4步:重新發(fā)送開始信號

第5步:發(fā)送器件7位地址+1位讀寫控制(讀)后等待芯片應(yīng)答

第6步:開始接收返回的的數(shù)據(jù)

第7步:發(fā)送結(jié)束信號

(2)讀n個字節(jié)

圖片

寫n個字節(jié)適用于讀取存儲在連續(xù)的n個地址上寫入n個數(shù)據(jù),當需要寫入n個數(shù)據(jù)的時候,這種連續(xù)寫的方式比單個寫的速度有顯著性優(yōu)勢,具體步驟如下。

第1步:發(fā)送開始信號

第2步:發(fā)送器件7位地址+1位讀寫控制后等待芯片應(yīng)答

第3步:發(fā)送寫入的地址后等待芯片應(yīng)答

第4步:重新發(fā)送開始信號

第5步:發(fā)送器件7位地址+1位讀寫控制(讀)后等待芯片應(yīng)答

第6步:接收返回的的數(shù)據(jù)1后發(fā)送應(yīng)答信號

第7步:接收返回的的數(shù)據(jù)2后發(fā)送應(yīng)答信號

……

第n+6步:接收返回的的數(shù)據(jù)n

第n+7步:發(fā)送結(jié)束信號

16.3 STM32內(nèi)部IIC協(xié)議相關(guān)寄存器

16.3.1 控制寄存器1:I2Cx_CR1

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
SWRST - ALERT PEC POS ACK STOP START NOSTRETCH ENGC ENPEC ENAPR SMBTYPE - SMBUS PE

Bit 15:軟件復位

0:I2C模塊不處于復位

1:I2C模塊處于復位

Bit 13:SMBus提醒:軟件可以設(shè)置或清除該位,當PE=0時,由硬件清除

0:釋放SMBAlert引腳使其變高,提醒響應(yīng)地址頭緊跟在NACK信號后面

1:驅(qū)動SMBAlert引腳使其變低,提醒響應(yīng)地址頭緊跟在ACK信號后面

Bit 12:數(shù)據(jù)包出錯檢測

0:無PEC傳輸

1:PEC傳輸

Bit 11:應(yīng)答/PEC位置

0:ACK位控制當前移位寄存器內(nèi)正在接收的字節(jié)的ACK。PEC位表明當前移位寄存器內(nèi)的字節(jié)是PEC

1:ACK位控制在移位寄存器里接收的下一個字節(jié)的ACK。PEC位表明在移位寄存器里接收的下一個字節(jié)是PEC

注1:POS位只能用在2字節(jié)的接收配置中,必須在接收數(shù)據(jù)之前配置

注2:為了NACK第2個字節(jié),必須在清除ADDR為之后清除ACK位

注3:為了檢測第2個字節(jié)的PEC,必須在配置了POS位之后,拉伸ADDR事件時設(shè)置PEC位

Bit 10:應(yīng)答使能

0:無應(yīng)答返回

1:在接收到一個字節(jié)后返回一個應(yīng)答

Bit 9:停止條件產(chǎn)生

在主模式下:

0:無停止條件產(chǎn)生

1:在當前字節(jié)傳輸或在當前起始條件發(fā)出后產(chǎn)生停止條件

在從模式下:

0:無停止條件產(chǎn)生

1:在當前字節(jié)傳輸或釋放SCL和SDA線

Bit 8:起始條件產(chǎn)生

在主模式下:

0:無起始條件產(chǎn)生

1:重復產(chǎn)生起始條件

在從模式下:

0:無起始條件產(chǎn)生

1:當總線空閑時,產(chǎn)生起始條件

Bit 7:禁止時鐘延長

0:允許時鐘延長

1:禁止時鐘延長

Bit 6:廣播呼叫使能

0:禁止廣播呼叫,以非應(yīng)答響應(yīng)地址00h

1:允許廣播呼叫,以應(yīng)答響應(yīng)地址00h

Bit 5:PEC使能

0:禁止PEC計算

1:開啟PEC計算

Bit 4:ARP使能

0:禁止ARP

1:使能ARP

注1:如果SMBTYPE=0,使用SMBus設(shè)備的默認地址

注2:如果SMBTYPE=1,使用SMBus的主地址

Bit 3:SMBus類型

0:SMBus設(shè)備

1:SMBus主機

Bit 1:SMBus模式

0:I2C模式

1:SMBus模式

Bit 0:I2C模塊使能

0:禁用I2C模塊

1:啟用I2C模塊,根據(jù)SMBus位的設(shè)置,相應(yīng)的I/O口需配置為復用功能

注:在主模式下,通訊結(jié)束之前,絕不能清除該位

16.3.2 控制寄存器2:I2Cx_CR2

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
- LAST DMAEN ITBUFEN ITEVTEN ITERREN - FREQ[5:0]

Bit 12:DMA最后一次傳輸

0:下一次DMA的EOT不是最后的傳輸

1:下一次DMA的EOT是最后的傳輸

Bit 11:DMA請求使能

0:禁止DMA請求

1:當TxE=1或RxNE=1時,允許DMA請求

Bit 10:緩沖器中斷使能

0:當TxE=1或RxNE=1時,不產(chǎn)生任何中斷

1:當TxE=1或RxNE=1時,產(chǎn)生事件中斷

Bit 9:事件中斷使能

0:禁止事件中斷

1:允許事件中斷

在下列條件下,將產(chǎn)生該中斷:

SB=1(主模式)

ADDR=1(主/從模式)

ADD10=1(主模式)

STOPF=1(從模式)

BTF=1,但是沒有TxE或RxNE事件

如果ITBUFEN=1,TxE事件為1

如果ITBUFEN=1,RxNE事件為1

Bit 8:出錯中斷使能

0:禁止出錯中斷

1:允許出錯中斷

在下列條件下,將產(chǎn)生該中斷:

BERR=1

ARLO=1

AF=1

OVR=1

PECERR=1

TIMEOUT=1

SMBAlert=1

Bit 5~Bit 0:I2C模塊時鐘頻率,允許的范圍在2~36MHz之間

000000:禁用

000001:禁用

000010:2MHz

...

100100:36MHz

大于100100:禁用

16.3.3 上升時間寄存器:I2Cx_TRISE

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
- TRISE[5:0]

Bit 5~Bit 0:在快速/標準模式下的SCL最大上升時間(主模式)

例如:標準模式中最大允許SCL上升時間為1000ns。如果在I2C_CR2寄存器中FREQ中的值等于0x08且TPCLK1=125ns,故TRISE中必須寫入09h(1000ns/125ns=8+1)

注:只有當PE=0時,才能設(shè)置TRISE

16.3.4 時鐘控制寄存器:I2Cx_CCR

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
F/S DUTY - CCR[11:0]

Bit 15:I2C主模式選項

0:標準模式的I2C

1:快速模式的I2C

Bit 14:快速模式時的占空比

0:快速模式下T low /T high =2

1:快速模式下T low /T high =16/9

Bit 11~Bit 0:快速/標準模式下的時鐘控制分頻系數(shù)(主模式)

在I2C標準模式或SMBus模式下:

T high =CCR×TPCLK1

T low =CCR×TPCLK1

在I2C快速模式下:

如果DUTY=0:

T high =CCR×TPCLK1

T low =2×CCR×TPCLK1

如果DUTY=1:

T high =9×CCR×TPCLK1

T low =16×CCR×TPCLK1

例如:在標準模式下,產(chǎn)生100kHz的SCL的頻率,如果FREQR=08,TPCLK1=125ns,則CCR必須寫入0x28(40×125ns=5000ns)

注1:允許設(shè)定的最小值為0x04,在快速DUTY模式下允許的最小值為0x01

注2:fCK應(yīng)當是10MHz的整數(shù)倍,這樣可以正確產(chǎn)生400kHz的快速時鐘

16.3.5 自身地址寄存器1:I2Cx_OAR1

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
ADDMODE - ADD[9:8] ADD[7:1] ADD0

Bit 15:尋址模式(從模式)

0:7位從地址(不響應(yīng)10位地址)

1:10位從地址(不響應(yīng)7位地址)

Bit 9~Bit 8:接口地址

7位地址模式時不用關(guān)心

10位地址模式時為地址的9~8位

Bit 7Bit 1:接口地址,地址的71位

Bit 0:接口地址

7位地址模式時不用關(guān)心

10位地址模式時為地址第0位

16.3.6 自身地址寄存器2:I2Cx_OAR2

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
- ADD2[7:1] ENDUAL

Bit 7Bit 1:接口地址,在雙地址模式下地址的71位

Bit 0:雙地址模式使能位

0:在7位地址模式下,只有OAR1被識別

1:在7位地址模式下,OAR1和OAR2都被識別

16.3.7 狀態(tài)寄存器1:I2Cx_SR1

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
SMBALERT TIMEOUT - PECERR OVR AF ARL0 BERR TXE RXNE - STOPF ADD10 BTF ADDR SB

Bit 15: SMBus提醒

在SMBus主機模式下:

0:無SMBus提醒

1:在引腳上產(chǎn)生SMBAlert提醒事件

在SMBus從機模式下:

0:沒有SMBAlert響應(yīng)地址頭序列

1:收到SMBAlert響應(yīng)地址頭序列至SMBAlert變低

Bit 14:超時或Tlow錯誤

0:無超時錯誤

1:SCL低電平達到25ms;或主機低電平累積時間超過10ms;或從設(shè)備低電平累積時間超過25ms

Bit 12:在接收時發(fā)生PEC錯誤

0:無PEC錯誤:接收到PEC后接收器返回ACK(如果ACK=1)

1:有PEC錯誤:接收到PEC后接收器返回NACK(不管ACK是什么值)

Bit 11:過載/欠載

0:無過載/欠載

1:出現(xiàn)過載/欠載

Bit 10:應(yīng)答失敗

0:沒有應(yīng)答失敗

1:應(yīng)答失敗

Bit 9:仲裁丟失(主模式)

0:沒有檢測到仲裁丟失

1:檢測到仲裁丟失

Bit 8:總線出錯

0:無起始或停止條件出錯

1:起始或停止條件出錯

Bit 7:數(shù)據(jù)寄存器為空(發(fā)送時)

0:數(shù)據(jù)寄存器非空

1:數(shù)據(jù)寄存器空

Bit 6:數(shù)據(jù)寄存器非空(接收時)

0:數(shù)據(jù)寄存器為空

1:數(shù)據(jù)寄存器非空

Bit 4:停止條件檢測位(從模式)

0:沒有檢測到停止條件

1:檢測到停止條件

Bit 3:10位頭序列已發(fā)送(主模式)

0:沒有ADD10事件發(fā)生

1:主設(shè)備已經(jīng)將第一個地址字節(jié)發(fā)送出去

Bit 2:字節(jié)發(fā)送結(jié)束

0:字節(jié)發(fā)送未完成

1:字節(jié)發(fā)送結(jié)束

Bit 1:地址已被發(fā)送(主模式)/地址匹配(從模式)

地址匹配(從模式)

0:地址不匹配或沒有收到地址

1:收到的地址匹配Bit 1:

地址發(fā)送標志(主模式)

0:地址發(fā)送沒有結(jié)束

1:地址發(fā)送結(jié)束

10位地址模式時,當收到地址的第二個字節(jié)的ACK后該位被置1

7位地址模式時,當收到地址的ACK后該位被置1

Bit 0:起始位(主模式)

0:未發(fā)送起始條件

1:起始條件已發(fā)送

16.3.8 狀態(tài)寄存器2:I2Cx_SR2

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
PEC[7:0] DUALF SMBHOST SMBDEFAULT GENCALL - TRA BUSY MSL

Bit 15~Bit 8:數(shù)據(jù)包出錯檢測,當ENPEC=1時,PEC[7:0]存放內(nèi)部的PEC的值

Bit 7:雙標志(從模式)

0:接收到的地址與OAR1內(nèi)的內(nèi)容相匹配

1:接收到的地址與OAR2內(nèi)的內(nèi)容相匹配

Bit 6:SMBus主機頭系列(從模式)

0:未收到SMBus主機的地址

1:當SMBTYPE=1且ENARP=1時,收到SMBus主機地址

Bit 5:SMBus設(shè)備默認地址(從模式)

0:未收到SMBus設(shè)備的默認地址

1:當ENARP=1時,收到SMBus設(shè)備的默認地址

Bit 4:廣播呼叫地址(從模式)

0:未收到廣播呼叫地址

1:當ENGC=1時,收到廣播呼叫的地址

Bit 2:發(fā)送/接收

0:接收到數(shù)據(jù)

1:數(shù)據(jù)已發(fā)送

Bit 1:總線忙,在檢測到SDA或SCl為低電平時,硬件將該位1

0:在總線上無數(shù)據(jù)通訊

1:在總線上正在進行數(shù)據(jù)通訊

Bit 0:主從模式

0:從模式

1:主模式

16.3.9 數(shù)據(jù)寄存器:I2Cx_DR

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
- DR[7:0]

Bit 7~Bit 0:8位數(shù)據(jù)寄存器,用于存放接收到的數(shù)據(jù)或放置用于發(fā)送到總線的數(shù)據(jù)

發(fā)送器模式:當寫一個字節(jié)至DR寄存器時,自動啟動數(shù)據(jù)傳輸。一旦傳輸開始,如果能及時把下一個需傳輸?shù)臄?shù)據(jù)寫入DR寄存器,I2C模塊將保持連續(xù)的數(shù)據(jù)流

接收器模式:接收到的字節(jié)被拷貝到DR寄存器。在接收到下一個字節(jié)之前讀出數(shù)據(jù)寄存器,即可實現(xiàn)連續(xù)的數(shù)據(jù)傳送

注1:在從模式下,地址不會被拷貝進數(shù)據(jù)寄存器DR

注2:硬件不管理寫沖突(如果TxE=0,仍能寫入數(shù)據(jù)寄存器)

注3:如果在處理ACK脈沖時發(fā)生ARLO事件,接收到的字節(jié)不會被拷貝到數(shù)據(jù)寄存器里,因此不能讀到它

16.4 實驗例程

16.4.1 軟件模擬IIC控制

(1)創(chuàng)建at24cxx.h文件,并輸入以下代碼。

/*********************************************************************************************************
                EEPROM    驅(qū)    動    文    件
*********************************************************************************************************/
#ifndef _AT24Cxx_H_
#define _AT24Cxx_H_


#include "sys.h"
/*********************************************************************************************************
                硬    件    端    口    定    義
*********************************************************************************************************/
#define IIC_SCL      PBout( 6 )
#define IIC_SDA      PBout( 7 )
#define IIC_SDA_READ  PBin( 7 )
/*********************************************************************************************************
                    函    數(shù)    列    表
*********************************************************************************************************/
void AT24Cxx_Init( void ) ;                                        //AT24C初始化
void AT24Cxx_Write_Data( u16 Address, u8 Data ) ;                            //寫入1個數(shù)據(jù)
void AT24Cxx_Write_nData( u16 Address, u8 *Buffer, u16 Len ) ;                      //寫入n個數(shù)據(jù)
void AT24Cxx_Read_Data( u16 Address, u8 *Data ) ;                            //讀取1個數(shù)據(jù)
void AT24Cxx_Read_nData( u16 Address, u8 *Buffer, u16 Len ) ;                      //讀取n個數(shù)據(jù)


#endif

(2)創(chuàng)建at24cxx.c文件,并輸入以下代碼。

/*********************************************************************************************************
                EEPROM    驅(qū)    動    程    序
*********************************************************************************************************/
#include "at24cxx.h"
#include "delay.h"
/***************************************************
Name    :IIC_Start
Function  :IIC起始信號
Paramater  :None
Return    :None
***************************************************/
void IIC_Start()
{
  GPIOB->CRL &= 0x0FFFFFFF ;                                      //PB7推挽輸出
  GPIOB->CRL |= 0x30000000 ;
  IIC_SDA = 1 ;
  IIC_SCL = 1 ;
  delay_us( 4 ) ;
  IIC_SDA = 0 ;
  delay_us( 4 ) ;
  IIC_SCL = 0 ;
}
/***************************************************
Name    :IIC_Stop
Function  :IIC停止信號
Paramater  :None
Return    :None
***************************************************/
void IIC_Stop()
{
  GPIOB->CRL &= 0x0FFFFFFF ;                                      //PB7推挽輸出
  GPIOB->CRL |= 0x30000000 ;
  IIC_SCL = 0 ;
  IIC_SDA = 0 ;
   delay_us( 4 ) ;
  IIC_SCL = 1 ;
  IIC_SDA = 1 ;
  delay_us( 4 ) ;
}
/***************************************************
Name    :IIC_Wait_Ack
Function  :IIC等待應(yīng)答
Paramater  :None
Return    :
      0:成功
      1:失敗
***************************************************/
void IIC_Wait_Ack()
{
  u8 Time = 0 ;
  GPIOB->CRL &= 0x0FFFFFFF ;
  GPIOB->CRL |= 0x80000000 ;
  IIC_SDA = 1 ;
  delay_us( 1 ) ;
  IIC_SCL = 1 ;
  delay_us( 1 ) ;
  while( IIC_SDA_READ )
  {
    Time ++ ;
    if( Time>250 )
    {
      IIC_Stop() ;
      break ;
    }
  }
  IIC_SCL = 0 ;
}
/***************************************************
Name    :IIC_Send_Byte
Function  :IIC發(fā)送一個字節(jié)
Paramater  :
      ack:應(yīng)答使能
        0:不應(yīng)答
        1:應(yīng)答
Return    :None
***************************************************/
void IIC_Send_Byte( u8 Byte )
{
  u8 i;
  GPIOB->CRL &= 0x0FFFFFFF ;                                      //PB7推挽輸出
  GPIOB->CRL |= 0x30000000 ;
  IIC_SCL = 0 ;
  for( i=0; i<8; i++ )
  {
    if( ( Byte&0x80 )==0x80 )
      IIC_SDA = 1 ;
    else
      IIC_SDA = 0 ;
    Byte <<= 1 ;
    delay_us( 2 ) ;
    IIC_SCL = 1 ;
    delay_us( 2 ) ;
    IIC_SCL = 0 ;
    delay_us( 2 ) ;
  }
}
/***************************************************
Name    :IIC_Read_Byte
Function  :IIC讀取一個字節(jié)
Paramater  :
      ack:應(yīng)答使能
        0:不應(yīng)答
        1:應(yīng)答
Return    :None
***************************************************/
u8 IIC_Read_Byte( u8 Ack )
{
  u8 i,Byte=0;
  GPIOB->CRL &= 0x0FFFFFFF ;
  GPIOB->CRL |= 0x80000000 ;
  for( i=0; i<8; i++ )
  {
    IIC_SCL = 0 ;
    delay_us( 2 ) ;
    IIC_SCL = 1 ;
    Byte <<= 1 ;
    if( IIC_SDA_READ )
      Byte |= 0x01 ;
    delay_us( 1 ) ;
  }
  IIC_SCL = 0 ;
  GPIOB->CRL &= 0x0FFFFFFF ;                                      //PB7推挽輸出
  GPIOB->CRL |= 0x30000000 ;
  IIC_SDA = 1 - Ack ;
  delay_us( 2 ) ;
  IIC_SCL = 1 ;
  delay_us( 2 ) ;
  IIC_SCL = 0 ;
  return Byte ;
}
/***************************************************
Name    :AT24Cxx_Write_Data
Function  :寫入1個數(shù)據(jù)
Paramater  :
      Address:地址
      Data:數(shù)據(jù)
Return    :讀到的數(shù)據(jù)
***************************************************/
void AT24Cxx_Write_Data( u16 Address, u8 Data )
{                                                      
  IIC_Start() ;
  IIC_Send_Byte( 0xA0|( Address/256 )<<1 ) ;                              //發(fā)送器件地址,寫數(shù)據(jù)
  IIC_Wait_Ack() ;
  IIC_Send_Byte( Address%256 ) ;                                    //發(fā)送低地址
  IIC_Wait_Ack() ;
  IIC_Send_Byte( Data ) ;                                        //發(fā)送字節(jié)
  IIC_Wait_Ack() ;
  IIC_Stop() ;                                            //產(chǎn)生一個停止條件
  delay_ms( 10 ) ;                                          //EEPROM的寫入速度比較慢
}
/***************************************************
Name    :AT24Cxx_Write_nData
Function  :寫入n個數(shù)據(jù)
Paramater  :
      Address:地址
      *Buffer:數(shù)據(jù)緩存
      Len:數(shù)據(jù)長度
Return    :None
***************************************************/
void AT24Cxx_Write_nData( u16 Address, u8 *Buffer, u16 Len ) 
{
  u16 i ;
  for( i=0; iAPB2ENR |= 1<<3 ;                                        //先使能外設(shè)GPIOB時鐘
  GPIOB->CRL &= 0x00FFFFFF ;                                      //PB6和PB7推挽輸出
  GPIOB->CRL |= 0x33000000 ;
  GPIOB->ODR |= 3<<6 ;                                        //PB6和PB7輸出高
  while( AT24Cxx_Check()==0 ) ;
}

(3)創(chuàng)建1.c文件并輸入以下代碼。

#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "at24cxx.h"


u8 TEXT_Buffer[] = "STM32F103 IIC Test" ;
int main()
{
  u8 datatemp[ 17 ] ;
  STM32_Clock_Init( 9 ) ;                                        //STM32時鐘初始化
  SysTick_Init( 72 ) ;                                        //SysTick初始化
  USART1_Init( 72, 115200 ) ;                                      //初始化串口1波特率115200
  LCD_Init() ;                                            //LCD初始化
  AT24Cxx_Init() ;                                          //AT24C初始化
   POINT_COLOR = RED ;                                          //設(shè)置字體為紅色
  AT24Cxx_Write_nData( 0, TEXT_Buffer, 18 ) ;                              //從第0個地址處開始寫入
  AT24Cxx_Read_nData( 0, datatemp, 18 ) ;                                //從第0個地址處開始讀出
  LCD_ShowString( 0, 0, datatemp ) ;                                  //顯示讀到的字符串
  while( 1 )
  {

  }
}

16.4.2 硬件IIC控制

注:由于STM32的硬件IIC總是容易卡死(這也是為什么網(wǎng)絡(luò)上幾乎沒有硬件IIC通訊的例子的原因),所以這里采用了ST內(nèi)部提供的通訊機制來保證IIC的正常使用。

(1)創(chuàng)建at24cxx.h文件并輸入以下代碼。

/*********************************************************************************************************
                EEPROM    驅(qū)    動    文    件
*********************************************************************************************************/
#ifndef _AT24Cxx_H_
#define _AT24Cxx_H_


#include "sys.h"
/*********************************************************************************************************
                    函    數(shù)    列    表
*********************************************************************************************************/
void AT24Cxx_Init( void ) ;                                        //AT24C初始化
void IIC_Write_Data( u8 Address, u8 Data ) ;                              //寫入1個數(shù)據(jù)
void AT24Cxx_Write_nData( u16 Address, u8 *Buffer, u16 Len ) ;                      //寫入n個數(shù)據(jù)
void AT24Cxx_Read_Data( u16 Address, u8 *Data ) ;                            //讀取1個數(shù)據(jù)
void AT24Cxx_Read_nData( u16 Address, u8 *Buffer, u16 Len ) ;                      //讀取n個數(shù)據(jù)


#endif

(2)創(chuàng)建at24cxx.c文件并輸入以下代碼。

/*********************************************************************************************************
                EEPROM    驅(qū)    動    程    序
*********************************************************************************************************/
#include "at24cxx.h"
#include "delay.h"
/***************************************************
Name    :IIC_Write_Data
Function  :寫入1個數(shù)據(jù)
Paramater  :
      Address:地址
      Byte:讀取的字節(jié)
Return    :None
***************************************************/
void IIC_Write_Data( u8 Address, u8 Byte )
{
  u16 Time, tmpreg ;
  tmpreg = tmpreg ;
  //等待BUSY標志置0
  Time = 0 ;
  while( ( ( I2C1->SR2&0x02 )==0x02 )&&( Time<65535 ) )
    Time ++ ;
  I2C1->CR1 &= ~( 1<<11 ) ;                                      //禁用Pos
  I2C1->CR1 |= 1<<8 ;                                          //開始信號
  //等待SB標志置1
  Time = 0 ;
  while( ( ( I2C1->SR1&0x01 )==0 )&&( Time<65535 ) )
    Time ++ ;
  I2C1->DR = 0xA0 ;                                          //發(fā)送從機地址
  //等待地址發(fā)送結(jié)束
  Time = 0 ;
  while( ( ( I2C1->SR1&0x02 )==0 )&&( Time<65535 ) )
  {
    Time ++ ;
    if( ( I2C1->SR1&0x400 )==0x400 )
    {
      I2C1->SR1 &= ~( 1<<10 ) ;                                  //清除AF標志
      I2C1->CR1 |= 1<<9 ;                                      //結(jié)束信號
      break ;
    }
  }
  tmpreg = I2C1->SR1 ;                                        //清除地址標志
  tmpreg = I2C1->SR2 ;
  //等待TXE標志置0
  Time = 0 ;
  while( ( ( I2C1->SR2&0x04)==0 )&&( Time<65535 ) )
  {
    Time ++ ;
    //檢查是否檢測到NACK
    if( ( I2C1->SR1&0x400 )==0x400 )
    {
      I2C1->SR1 &= ~( 1<<10 ) ;
      I2C1->CR1 |= 1<<9 ;                                      //結(jié)束信號
      break ;
    }
  }
  I2C1->DR = Address ;                                        //發(fā)送寄存器地址
  //等待TXE標志置1
  Time = 0 ;
  while( ( ( I2C1->SR1&0x80 )==0 )&&( Time<65535 ) )
  {
    Time ++ ;
    //檢查是否檢測到NACK
    if( ( I2C1->SR1&0x400 )==0x400 )
    {
      I2C1->SR1 &= ~( 1<<18 ) ;                                  //清除NACKF標志
      I2C1->CR1 |= 1<<9 ;                                      //結(jié)束信號
      break ;
    }
  }
  I2C1->DR = Byte ;                                          //發(fā)送數(shù)據(jù)
  //等待BTF標志被置1
  Time = 0 ;
  while( ( ( I2C1->SR1&0x04 )==0 )&&( Time<65535 ) )
  {
    Time ++ ;
    //檢查是否檢測到NACK
    if( ( I2C1->SR1&0x400 )==0x400 )
    {
      I2C1->SR1 &= ~( 1<<10 ) ;                                  //清除NACKF標志
      I2C1->CR1 |= 1<<9 ;                                      //結(jié)束信號
      break ;
    }
  }
  I2C1->CR1 |= 1<<9 ;                                          //結(jié)束信號
  delay_ms( 10 ) ;
}
/***************************************************
Name    :IIC_Read_Data
Function  :讀取1個數(shù)據(jù)
Paramater  :
      Address:地址
Return    :讀取的數(shù)據(jù)
***************************************************/
void IIC_Read_Data( u8 Address, u8 *Data )
{
  u16 tmpreg, Time;
  tmpreg = tmpreg ;
    //等待BUSY標志置0
  Time = 0 ;
  while( ( ( I2C1->SR1&0x02 )==0x02 )&&( Time<65535 ) )
    Time ++ ;
  I2C1->CR1 &= ~( 1<<11 ) ;                                      //禁用Pos
    //發(fā)送從機地址
  I2C1->CR1 |= 1<<8 ;                                          //開始信號
  Time = 0 ;
  //等待SB標志置1
  while( ( ( I2C1->SR1&0x01 )==0 )&&( Time<65535 ) )
    Time ++ ;
  I2C1->DR = 0xA0 ;                                          //發(fā)送從機地址
  //等待地址發(fā)送結(jié)束
  while( ( ( I2C1->SR1&0x02 )==0 )&&( Time<65535 ) )
  {
    if( ( I2C1->SR1&0x400 )==0x400 )
    {
      I2C1->SR1 &= ~( 1<<10 ) ;                                  //清除AF標志
      I2C1->CR1 |= 1<<9 ;                                      //停止信號
      break ;
    }
  }
  tmpreg = I2C1->SR1;                                          //清除ADDR標志
  tmpreg = I2C1->SR2;
  //等待TXE標志置1
  while( ( ( I2C1->SR1&0x80 )==0 )&&( Time<65535 ) )
  {
    //檢查是否檢測到NACK
    if( ( I2C1->SR1&0x400)==0x400 )
    {
      I2C1->SR1 &= ~( 1<<10 ) ;                                  //清除NACKF標志
      I2C1->CR1 |= 1<<9 ;                                      //通用結(jié)束
      break ;
    }
  }
  I2C1->DR = Address ;                                        //寫入數(shù)據(jù)
  //等待BTF標志置1
  while( ( ( I2C1->SR1&0x04 )==0 )&&( Time<65535 ) )
  {
    //檢查是否檢測到NACK
    if( ( I2C1->SR1&0x400)==0x400 )
    {
      I2C1->SR1 &= ~( 1<<10 ) ;                                  //清除NACKF標志
      I2C1->CR1 |= 1<<9 ;                                      //通用結(jié)束
      break ;
    }
  }
  I2C1->CR1 |= 1<<9 ;                                          //通用結(jié)束
  //等待忙標志退出
  Time = 0 ;
  while( ( ( I2C1->SR1&0x02 )==0x02 )&&( Time<65535 ) )
    Time ++ ;
  I2C1->CR1 &= ~( 1<<11 ) ;                                      //禁用Pos
    //發(fā)送從機地址
  I2C1->CR1 |= 1<<10 ;                                        //開啟應(yīng)答信號
  I2C1->CR1 |= 1<<8 ;                                          //開始信號
  //等待SB標志置1
  Time = 0 ;
  while( ( ( I2C1->SR1&0x01 )==0 )&&( Time<65535 ) )
    Time ++ ;
  I2C1->DR = 0xA1 ;                                          //發(fā)送從機地址
  //等待地址標志置1
  while( ( ( I2C1->SR1&0x02 )==0 )&&( Time<65535 ) )
  {
    Time ++ ;
    //檢查是否檢測到STOPF
    if( ( I2C1->SR1&0x10 )==0x10 )
    {
      I2C1->SR1 &= ~( 1<<4 ) ;                                  //清除停止標志
      break ;
    }
  }
  I2C1->CR1 &= ~( 1<<10 ) ;                                      //禁止應(yīng)答
  tmpreg = I2C1->SR1;                                          //清除ADDR標志
  tmpreg = I2C1->SR2;
  I2C1->CR1 |= 1<<9 ;                                          //通用應(yīng)答
  //等待直到RXNE標志置1
  Time = 0 ;
  while( ( ( I2C1->SR1&0x40 )==0 )&&( Time<65535 ) )
  {
    Time ++ ;
    //檢查是否檢測到STOPF
    if( ( I2C1->SR1&0x10 )==0x10 )
    {
      I2C1->SR1 &= ~( 1<<4 ) ;                                  //清除停止標志
      break ;
    }
  }
  *Data = I2C1->DR ;                                          //從DR讀取數(shù)據(jù)
}
/***************************************************
Name    :AT24Cxx_Write_nData
Function  :寫入n個數(shù)據(jù)
Paramater  :
      Address:地址
      *Buffer:數(shù)據(jù)緩存
      Len:數(shù)據(jù)長度
Return    :None
***************************************************/
void AT24Cxx_Write_nData( u16 Address, u8 *Buffer, u16 Len ) 
{
  u16 i ;
  for( i=0; i

(3)創(chuàng)建1.c文件并輸入以下代碼。

#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "at24cxx.h"


u8 TEXT_Buffer[] = "STM32F103 IIC Test" ;
int main()
{
  u8 datatemp[ 17 ] ;
  STM32_Clock_Init( 9 ) ;                                        //STM32時鐘初始化
  SysTick_Init( 72 ) ;                                        //SysTick初始化
  USART1_Init( 72, 115200 ) ;                                      //初始化串口1波特率115200
  AT24Cxx_Init() ;                                          //AT24C初始化
  AT24Cxx_Write_nData( 0, TEXT_Buffer, 18 ) ;                              //從第0個地址處開始寫入
  AT24Cxx_Read_nData( 0, datatemp, 18 ) ;                                //從第0個地址處開始讀出
  while( 1 )
  {

  }
}
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 存儲器
    +關(guān)注

    關(guān)注

    38

    文章

    7365

    瀏覽量

    163085
  • EEPROM
    +關(guān)注

    關(guān)注

    9

    文章

    1002

    瀏覽量

    81053
  • 存儲芯片
    +關(guān)注

    關(guān)注

    11

    文章

    874

    瀏覽量

    42868
收藏 人收藏

    評論

    相關(guān)推薦

    如何使用Flash模擬EEPROM存儲參數(shù)

    概述在MCU的使用中,經(jīng)常遇到需要存儲參數(shù)或掉電保持數(shù)據(jù)等功能。其中,F(xiàn)lash和EEPROM是常見的非易失性存儲器,都可以做到設(shè)備掉電重啟后,數(shù)據(jù)還會保留。但二者有明顯的區(qū)別:EEPROM
    的頭像 發(fā)表于 09-22 08:19 ?1410次閱讀
    如何使用Flash模擬<b class='flag-5'>EEPROM</b><b class='flag-5'>存儲</b>參數(shù)

    EEPROM存儲原理/選型/特點/應(yīng)用

    非易失性存儲器主要是用來存放固定數(shù)據(jù)、固件程序等一般不需要經(jīng)常改動的數(shù)據(jù)。目前主流非易失性存儲器主要有EEPROM、MRAM、FLASH、FRAM。EEPROM
    發(fā)表于 12-16 16:27

    EEPROM掉電存儲實驗過程

    一、實驗任務(wù)EEPROM掉電存儲二、原理分析在這里不多做介紹,如果需要理解原理可以移步,單片機復習篇。三、實驗過程1、搭好框架(這里加入了absacc頭文件,簡單框架,可跳過
    發(fā)表于 02-18 06:29

    EEPROM開機記憶存儲實驗

    EEPROM開機記憶存儲實驗
    發(fā)表于 07-13 18:10 ?25次下載

    串行EEPROM存儲器及應(yīng)用

    串行EEPROM存儲器及應(yīng)用
    發(fā)表于 12-11 23:41 ?0次下載

    EEPROM存儲原理以及EEPROM特點的介紹

    非易失性存儲器主要是用來存放固定數(shù)據(jù)、固件程序等一般不需要經(jīng)常改動的數(shù)據(jù)。目前主流非易失性存儲器主要有EEPROM、MRAM、FLASH、FRAM。 EEPROM
    發(fā)表于 12-11 15:04 ?1w次閱讀

    STM32入門學習筆記之EEPROM存儲實驗1

    EEPROM(Electrically Erasable Programmable read only memory),稱為帶電可擦除可編程只讀存儲器,是一種可以斷電保存數(shù)據(jù)的存儲芯片,EEP
    的頭像 發(fā)表于 02-16 14:22 ?2215次閱讀
    STM32入門學習筆記之<b class='flag-5'>EEPROM</b><b class='flag-5'>存儲</b><b class='flag-5'>實驗</b>1

    STM32入門學習筆記之EEPROM存儲實驗2

    EEPROM(Electrically Erasable Programmable read only memory),稱為帶電可擦除可編程只讀存儲器,是一種可以斷電保存數(shù)據(jù)的存儲芯片,EEP
    的頭像 發(fā)表于 02-16 14:22 ?856次閱讀

    STM32入門學習筆記之EEPROM存儲實驗3

    EEPROM(Electrically Erasable Programmable read only memory),稱為帶電可擦除可編程只讀存儲器,是一種可以斷電保存數(shù)據(jù)的存儲芯片,EEP
    的頭像 發(fā)表于 02-16 14:22 ?1011次閱讀

    STM32入門學習筆記之EEPROM存儲實驗4

    EEPROM(Electrically Erasable Programmable read only memory),稱為帶電可擦除可編程只讀存儲器,是一種可以斷電保存數(shù)據(jù)的存儲芯片,EEP
    的頭像 發(fā)表于 02-16 14:22 ?1435次閱讀

    STM32入門學習筆記之EEPROM存儲實驗5

    EEPROM(Electrically Erasable Programmable read only memory),稱為帶電可擦除可編程只讀存儲器,是一種可以斷電保存數(shù)據(jù)的存儲芯片,EEP
    的頭像 發(fā)表于 02-16 14:23 ?531次閱讀

    科普EEPROM 科普 EVASH Ultra EEPROM?科普存儲芯片

    科普EEPROM 科普 EVASH Ultra EEPROM?科普存儲芯片
    的頭像 發(fā)表于 06-25 17:14 ?320次閱讀

    eeprom是指什么存儲

    EEPROM(Electrically Erasable Programmable Read-Only Memory,電可擦可編程只讀存儲器)是一種非易失性存儲器,具有電可擦寫、可編程和只讀的特性
    的頭像 發(fā)表于 08-05 16:53 ?777次閱讀

    eeprom存儲原理、存儲結(jié)構(gòu)及讀寫操作

    EEPROM(Electrically Erasable Programmable Read-Only Memory,電可擦可編程只讀存儲器)是一種非易失性存儲器,可以在不移除電源的情況下進行讀寫
    的頭像 發(fā)表于 08-05 17:03 ?945次閱讀

    EEPROM存儲器如何加密

    EEPROM(Electrically Erasable Programmable Read-Only Memory,電可擦可編程只讀存儲器)是一種非易失性存儲器,它在斷電后仍能保持數(shù)據(jù)。由于其可
    的頭像 發(fā)表于 08-05 18:05 ?867次閱讀