16.1 EEPROM概述
EEPROM(Electrically Erasable Programmable read only memory),稱(chēng)為帶電可擦除可編程只讀存儲(chǔ)器,是一種可以斷電保存數(shù)據(jù)的存儲(chǔ)芯片,EEPROM可以在電腦上或?qū)S迷O(shè)備上擦除已有信息,重新編程,一般用在即插即用設(shè)備中,這種存儲(chǔ)芯片可以通過(guò)高于普通電壓的作用來(lái)擦除或重寫(xiě),EEPROM芯片一般用在需要頻繁存儲(chǔ)數(shù)據(jù),但是數(shù)據(jù)量不大的場(chǎng)合,本實(shí)驗(yàn)以Atmel公司設(shè)計(jì)的AT24C02為例,來(lái)詳細(xì)描述EEPROM的基本操作。
AT24C02是一片存儲(chǔ)容量在2Kbit的的存儲(chǔ)芯片,即存儲(chǔ)容量512Byte,通過(guò)IIC總線協(xié)議進(jìn)行數(shù)據(jù)通信,STM32F1內(nèi)置的IIC模塊,但是由于當(dāng)時(shí)設(shè)計(jì)的時(shí)候?yàn)榱艘?guī)避飛利浦關(guān)于IIC通信協(xié)議的專(zhuān)利技術(shù),將IIC設(shè)計(jì)的比較復(fù)雜,并且當(dāng)操作不當(dāng)?shù)臅r(shí)候容易鎖住總線,但是ST公司關(guān)于硬件IIC方面也提出了對(duì)應(yīng)的軟件解決方案,我們?cè)谶@個(gè)存儲(chǔ)實(shí)驗(yàn)中采用IO口模擬IIC協(xié)議與硬件IIC模塊兩種方式來(lái)實(shí)現(xiàn)EEPROM存儲(chǔ)。
IIC是一種只利用兩根線來(lái)進(jìn)行數(shù)據(jù)交換的串行通信協(xié)議,IIC的電氣線路包括兩根線,即時(shí)鐘線SCL和數(shù)據(jù)線SDA,高速I(mǎi)IC總線一般可達(dá)400kbps以上,在傳送過(guò)程中一共有三種類(lèi)型的信號(hào),分別是開(kāi)始信號(hào),結(jié)束信號(hào)和應(yīng)答信號(hào),我們?cè)?a href="http://www.194w.cn/v/tag/1052/" target="_blank">51單片機(jī)開(kāi)發(fā)中曾將IIC協(xié)議通過(guò)端口模擬成功的控制了EEPROM的讀寫(xiě),現(xiàn)在只需要將之前的代碼移植過(guò)來(lái)修改一下底層寄存器即可使用。STM32F1系列的硬件IIC結(jié)構(gòu)框圖如下圖所示。
從結(jié)構(gòu)可以發(fā)現(xiàn),STM32的硬件IIC模塊我們只需要配置好寄存器,然后既可以不考慮具體的IIC協(xié)議,直接讀數(shù)據(jù)寄存器就可以獲取到總線上的數(shù)據(jù),這也是硬件IIC的優(yōu)勢(shì)所在。
16.2 AT24C02通信時(shí)序
16.2.1 寫(xiě)時(shí)序
(1)寫(xiě)1個(gè)字節(jié)
第1步:發(fā)送開(kāi)始信號(hào)
第2步:發(fā)送器件7位地址+1位讀寫(xiě)控制后等待芯片應(yīng)答
第3步:發(fā)送寫(xiě)入的地址后等待芯片應(yīng)答
第4步:寫(xiě)入需要存儲(chǔ)的數(shù)據(jù)后等待芯片應(yīng)答
第5步:發(fā)送結(jié)束信號(hào)
第6步:等待20ms左右
(2)寫(xiě)n個(gè)字節(jié)
寫(xiě)n個(gè)字節(jié)適用于在連續(xù)的n個(gè)地址上寫(xiě)入n個(gè)數(shù)據(jù),當(dāng)需要寫(xiě)入n個(gè)數(shù)據(jù)的時(shí)候,這種連續(xù)寫(xiě)的方式比單個(gè)寫(xiě)的速度有顯著性?xún)?yōu)勢(shì),具體步驟如下。
第1步:發(fā)送開(kāi)始信號(hào)
第2步:發(fā)送器件7位地址+1位讀寫(xiě)控制后等待芯片應(yīng)答
第3步:發(fā)送寫(xiě)入的地址后等待芯片應(yīng)答
第4步:寫(xiě)入需要存儲(chǔ)的數(shù)據(jù)1后等待芯片應(yīng)答
……
第n+4步:寫(xiě)入需要存儲(chǔ)的數(shù)據(jù)n后等待芯片應(yīng)答
第n+5步:發(fā)送結(jié)束信號(hào)
第n+6步:等待20ms左右
注:AT24C系列芯片進(jìn)行1次完整的寫(xiě)時(shí)序,必須等待5ms以上,手冊(cè)給出的典型值是5ms,一般默認(rèn)20ms。
16.2.2 讀時(shí)序
(1)讀1個(gè)字節(jié)
第1步:發(fā)送開(kāi)始信號(hào)
第2步:發(fā)送器件7位地址+1位讀寫(xiě)控制后等待芯片應(yīng)答
第3步:發(fā)送寫(xiě)入的地址后等待芯片應(yīng)答
第4步:重新發(fā)送開(kāi)始信號(hào)
第5步:發(fā)送器件7位地址+1位讀寫(xiě)控制(讀)后等待芯片應(yīng)答
第6步:開(kāi)始接收返回的的數(shù)據(jù)
第7步:發(fā)送結(jié)束信號(hào)
(2)讀n個(gè)字節(jié)
寫(xiě)n個(gè)字節(jié)適用于讀取存儲(chǔ)在連續(xù)的n個(gè)地址上寫(xiě)入n個(gè)數(shù)據(jù),當(dāng)需要寫(xiě)入n個(gè)數(shù)據(jù)的時(shí)候,這種連續(xù)寫(xiě)的方式比單個(gè)寫(xiě)的速度有顯著性?xún)?yōu)勢(shì),具體步驟如下。
第1步:發(fā)送開(kāi)始信號(hào)
第2步:發(fā)送器件7位地址+1位讀寫(xiě)控制后等待芯片應(yīng)答
第3步:發(fā)送寫(xiě)入的地址后等待芯片應(yīng)答
第4步:重新發(fā)送開(kāi)始信號(hào)
第5步:發(fā)送器件7位地址+1位讀寫(xiě)控制(讀)后等待芯片應(yīng)答
第6步:接收返回的的數(shù)據(jù)1后發(fā)送應(yīng)答信號(hào)
第7步:接收返回的的數(shù)據(jù)2后發(fā)送應(yīng)答信號(hào)
……
第n+6步:接收返回的的數(shù)據(jù)n
第n+7步:發(fā)送結(jié)束信號(hào)
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:軟件復(fù)位
0:I2C模塊不處于復(fù)位
1:I2C模塊處于復(fù)位
Bit 13:SMBus提醒:軟件可以設(shè)置或清除該位,當(dāng)PE=0時(shí),由硬件清除
0:釋放SMBAlert引腳使其變高,提醒響應(yīng)地址頭緊跟在NACK信號(hào)后面
1:驅(qū)動(dòng)SMBAlert引腳使其變低,提醒響應(yīng)地址頭緊跟在ACK信號(hào)后面
Bit 12:數(shù)據(jù)包出錯(cuò)檢測(cè)
0:無(wú)PEC傳輸
1:PEC傳輸
Bit 11:應(yīng)答/PEC位置
0:ACK位控制當(dāng)前移位寄存器內(nèi)正在接收的字節(jié)的ACK。PEC位表明當(dāng)前移位寄存器內(nèi)的字節(jié)是PEC
1:ACK位控制在移位寄存器里接收的下一個(gè)字節(jié)的ACK。PEC位表明在移位寄存器里接收的下一個(gè)字節(jié)是PEC
注1:POS位只能用在2字節(jié)的接收配置中,必須在接收數(shù)據(jù)之前配置
注2:為了NACK第2個(gè)字節(jié),必須在清除ADDR為之后清除ACK位
注3:為了檢測(cè)第2個(gè)字節(jié)的PEC,必須在配置了POS位之后,拉伸ADDR事件時(shí)設(shè)置PEC位
Bit 10:應(yīng)答使能
0:無(wú)應(yīng)答返回
1:在接收到一個(gè)字節(jié)后返回一個(gè)應(yīng)答
Bit 9:停止條件產(chǎn)生
在主模式下:
0:無(wú)停止條件產(chǎn)生
1:在當(dāng)前字節(jié)傳輸或在當(dāng)前起始條件發(fā)出后產(chǎn)生停止條件
在從模式下:
0:無(wú)停止條件產(chǎn)生
1:在當(dāng)前字節(jié)傳輸或釋放SCL和SDA線
Bit 8:起始條件產(chǎn)生
在主模式下:
0:無(wú)起始條件產(chǎn)生
1:重復(fù)產(chǎn)生起始條件
在從模式下:
0:無(wú)起始條件產(chǎn)生
1:當(dāng)總線空閑時(shí),產(chǎn)生起始條件
Bit 7:禁止時(shí)鐘延長(zhǎng)
0:允許時(shí)鐘延長(zhǎng)
1:禁止時(shí)鐘延長(zhǎng)
Bit 6:廣播呼叫使能
0:禁止廣播呼叫,以非應(yīng)答響應(yīng)地址00h
1:允許廣播呼叫,以應(yīng)答響應(yīng)地址00h
Bit 5:PEC使能
0:禁止PEC計(jì)算
1:開(kāi)啟PEC計(jì)算
Bit 4:ARP使能
0:禁止ARP
1:使能ARP
注1:如果SMBTYPE=0,使用SMBus設(shè)備的默認(rèn)地址
注2:如果SMBTYPE=1,使用SMBus的主地址
Bit 3:SMBus類(lèi)型
0:SMBus設(shè)備
1:SMBus主機(jī)
Bit 1:SMBus模式
0:I2C模式
1:SMBus模式
Bit 0:I2C模塊使能
0:禁用I2C模塊
1:?jiǎn)⒂肐2C模塊,根據(jù)SMBus位的設(shè)置,相應(yīng)的I/O口需配置為復(fù)用功能
注:在主模式下,通訊結(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請(qǐng)求使能
0:禁止DMA請(qǐng)求
1:當(dāng)TxE=1或RxNE=1時(shí),允許DMA請(qǐng)求
Bit 10:緩沖器中斷使能
0:當(dāng)TxE=1或RxNE=1時(shí),不產(chǎn)生任何中斷
1:當(dāng)TxE=1或RxNE=1時(shí),產(chǎn)生事件中斷
Bit 9:事件中斷使能
0:禁止事件中斷
1:允許事件中斷
在下列條件下,將產(chǎn)生該中斷:
SB=1(主模式)
ADDR=1(主/從模式)
ADD10=1(主模式)
STOPF=1(從模式)
BTF=1,但是沒(méi)有TxE或RxNE事件
如果ITBUFEN=1,TxE事件為1
如果ITBUFEN=1,RxNE事件為1
Bit 8:出錯(cuò)中斷使能
0:禁止出錯(cuò)中斷
1:允許出錯(cuò)中斷
在下列條件下,將產(chǎn)生該中斷:
BERR=1
ARLO=1
AF=1
OVR=1
PECERR=1
TIMEOUT=1
SMBAlert=1
Bit 5~Bit 0:I2C模塊時(shí)鐘頻率,允許的范圍在2~36MHz之間
000000:禁用
000001:禁用
000010:2MHz
...
100100:36MHz
大于100100:禁用
16.3.3 上升時(shí)間寄存器: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:在快速/標(biāo)準(zhǔn)模式下的SCL最大上升時(shí)間(主模式)
例如:標(biāo)準(zhǔn)模式中最大允許SCL上升時(shí)間為1000ns。如果在I2C_CR2寄存器中FREQ中的值等于0x08且TPCLK1=125ns,故TRISE中必須寫(xiě)入09h(1000ns/125ns=8+1)
注:只有當(dāng)PE=0時(shí),才能設(shè)置TRISE
16.3.4 時(shí)鐘控制寄存器: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主模式選項(xiàng)
0:標(biāo)準(zhǔn)模式的I2C
1:快速模式的I2C
Bit 14:快速模式時(shí)的占空比
0:快速模式下T low /T high =2
1:快速模式下T low /T high =16/9
Bit 11~Bit 0:快速/標(biāo)準(zhǔn)模式下的時(shí)鐘控制分頻系數(shù)(主模式)
在I2C標(biāo)準(zhǔn)模式或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
例如:在標(biāo)準(zhǔn)模式下,產(chǎn)生100kHz的SCL的頻率,如果FREQR=08,TPCLK1=125ns,則CCR必須寫(xiě)入0x28(40×125ns=5000ns)
注1:允許設(shè)定的最小值為0x04,在快速DUTY模式下允許的最小值為0x01
注2:fCK應(yīng)當(dāng)是10MHz的整數(shù)倍,這樣可以正確產(chǎn)生400kHz的快速時(shí)鐘
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位地址模式時(shí)不用關(guān)心
10位地址模式時(shí)為地址的9~8位
Bit 7Bit 1:接口地址,地址的71位
Bit 0:接口地址
7位地址模式時(shí)不用關(guān)心
10位地址模式時(shí)為地址第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被識(shí)別
1:在7位地址模式下,OAR1和OAR2都被識(shí)別
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主機(jī)模式下:
0:無(wú)SMBus提醒
1:在引腳上產(chǎn)生SMBAlert提醒事件
在SMBus從機(jī)模式下:
0:沒(méi)有SMBAlert響應(yīng)地址頭序列
1:收到SMBAlert響應(yīng)地址頭序列至SMBAlert變低
Bit 14:超時(shí)或Tlow錯(cuò)誤
0:無(wú)超時(shí)錯(cuò)誤
1:SCL低電平達(dá)到25ms;或主機(jī)低電平累積時(shí)間超過(guò)10ms;或從設(shè)備低電平累積時(shí)間超過(guò)25ms
Bit 12:在接收時(shí)發(fā)生PEC錯(cuò)誤
0:無(wú)PEC錯(cuò)誤:接收到PEC后接收器返回ACK(如果ACK=1)
1:有PEC錯(cuò)誤:接收到PEC后接收器返回NACK(不管ACK是什么值)
Bit 11:過(guò)載/欠載
0:無(wú)過(guò)載/欠載
1:出現(xiàn)過(guò)載/欠載
Bit 10:應(yīng)答失敗
0:沒(méi)有應(yīng)答失敗
1:應(yīng)答失敗
Bit 9:仲裁丟失(主模式)
0:沒(méi)有檢測(cè)到仲裁丟失
1:檢測(cè)到仲裁丟失
Bit 8:總線出錯(cuò)
0:無(wú)起始或停止條件出錯(cuò)
1:起始或停止條件出錯(cuò)
Bit 7:數(shù)據(jù)寄存器為空(發(fā)送時(shí))
0:數(shù)據(jù)寄存器非空
1:數(shù)據(jù)寄存器空
Bit 6:數(shù)據(jù)寄存器非空(接收時(shí))
0:數(shù)據(jù)寄存器為空
1:數(shù)據(jù)寄存器非空
Bit 4:停止條件檢測(cè)位(從模式)
0:沒(méi)有檢測(cè)到停止條件
1:檢測(cè)到停止條件
Bit 3:10位頭序列已發(fā)送(主模式)
0:沒(méi)有ADD10事件發(fā)生
1:主設(shè)備已經(jīng)將第一個(gè)地址字節(jié)發(fā)送出去
Bit 2:字節(jié)發(fā)送結(jié)束
0:字節(jié)發(fā)送未完成
1:字節(jié)發(fā)送結(jié)束
Bit 1:地址已被發(fā)送(主模式)/地址匹配(從模式)
地址匹配(從模式)
0:地址不匹配或沒(méi)有收到地址
1:收到的地址匹配Bit 1:
地址發(fā)送標(biāo)志(主模式)
0:地址發(fā)送沒(méi)有結(jié)束
1:地址發(fā)送結(jié)束
10位地址模式時(shí),當(dāng)收到地址的第二個(gè)字節(jié)的ACK后該位被置1
7位地址模式時(shí),當(dāng)收到地址的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ù)包出錯(cuò)檢測(cè),當(dāng)ENPEC=1時(shí),PEC[7:0]存放內(nèi)部的PEC的值
Bit 7:雙標(biāo)志(從模式)
0:接收到的地址與OAR1內(nèi)的內(nèi)容相匹配
1:接收到的地址與OAR2內(nèi)的內(nèi)容相匹配
Bit 6:SMBus主機(jī)頭系列(從模式)
0:未收到SMBus主機(jī)的地址
1:當(dāng)SMBTYPE=1且ENARP=1時(shí),收到SMBus主機(jī)地址
Bit 5:SMBus設(shè)備默認(rèn)地址(從模式)
0:未收到SMBus設(shè)備的默認(rèn)地址
1:當(dāng)ENARP=1時(shí),收到SMBus設(shè)備的默認(rèn)地址
Bit 4:廣播呼叫地址(從模式)
0:未收到廣播呼叫地址
1:當(dāng)ENGC=1時(shí),收到廣播呼叫的地址
Bit 2:發(fā)送/接收
0:接收到數(shù)據(jù)
1:數(shù)據(jù)已發(fā)送
Bit 1:總線忙,在檢測(cè)到SDA或SCl為低電平時(shí),硬件將該位1
0:在總線上無(wú)數(shù)據(jù)通訊
1:在總線上正在進(jìn)行數(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ā)送器模式:當(dāng)寫(xiě)一個(gè)字節(jié)至DR寄存器時(shí),自動(dòng)啟動(dòng)數(shù)據(jù)傳輸。一旦傳輸開(kāi)始,如果能及時(shí)把下一個(gè)需傳輸?shù)臄?shù)據(jù)寫(xiě)入DR寄存器,I2C模塊將保持連續(xù)的數(shù)據(jù)流
接收器模式:接收到的字節(jié)被拷貝到DR寄存器。在接收到下一個(gè)字節(jié)之前讀出數(shù)據(jù)寄存器,即可實(shí)現(xiàn)連續(xù)的數(shù)據(jù)傳送
注1:在從模式下,地址不會(huì)被拷貝進(jìn)數(shù)據(jù)寄存器DR
注2:硬件不管理寫(xiě)沖突(如果TxE=0,仍能寫(xiě)入數(shù)據(jù)寄存器)
注3:如果在處理ACK脈沖時(shí)發(fā)生ARLO事件,接收到的字節(jié)不會(huì)被拷貝到數(shù)據(jù)寄存器里,因此不能讀到它
16.4 實(shí)驗(yàn)例程
16.4.1 軟件模擬IIC控制
(1)創(chuàng)建at24cxx.h文件,并輸入以下代碼。
/*********************************************************************************************************
EEPROM 驅(qū) 動(dòng) 文 件
*********************************************************************************************************/
#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 ) ; //寫(xiě)入1個(gè)數(shù)據(jù)
void AT24Cxx_Write_nData( u16 Address, u8 *Buffer, u16 Len ) ; //寫(xiě)入n個(gè)數(shù)據(jù)
void AT24Cxx_Read_Data( u16 Address, u8 *Data ) ; //讀取1個(gè)數(shù)據(jù)
void AT24Cxx_Read_nData( u16 Address, u8 *Buffer, u16 Len ) ; //讀取n個(gè)數(shù)據(jù)
#endif
(2)創(chuàng)建at24cxx.c文件,并輸入以下代碼。
/*********************************************************************************************************
EEPROM 驅(qū) 動(dòng) 程 序
*********************************************************************************************************/
#include "at24cxx.h"
#include "delay.h"
/***************************************************
Name :IIC_Start
Function :IIC起始信號(hào)
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停止信號(hào)
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ā)送一個(gè)字節(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讀取一個(gè)字節(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 :寫(xiě)入1個(gè)數(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ā)送器件地址,寫(xiě)數(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)生一個(gè)停止條件
delay_ms( 10 ) ; //EEPROM的寫(xiě)入速度比較慢
}
/***************************************************
Name :AT24Cxx_Write_nData
Function :寫(xiě)入n個(gè)數(shù)據(jù)
Paramater :
Address:地址
*Buffer:數(shù)據(jù)緩存
Len:數(shù)據(jù)長(zhǎng)度
Return :None
***************************************************/
void AT24Cxx_Write_nData( u16 Address, u8 *Buffer, u16 Len )
{
u16 i ;
for( i=0; iAPB2ENR |= 1<<3 ; //先使能外設(shè)GPIOB時(shí)鐘
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時(shí)鐘初始化
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個(gè)地址處開(kāi)始寫(xiě)入
AT24Cxx_Read_nData( 0, datatemp, 18 ) ; //從第0個(gè)地址處開(kāi)始讀出
LCD_ShowString( 0, 0, datatemp ) ; //顯示讀到的字符串
while( 1 )
{
}
}
16.4.2 硬件IIC控制
注:由于STM32的硬件IIC總是容易卡死(這也是為什么網(wǎng)絡(luò)上幾乎沒(méi)有硬件IIC通訊的例子的原因),所以這里采用了ST內(nèi)部提供的通訊機(jī)制來(lái)保證IIC的正常使用。
(1)創(chuàng)建at24cxx.h文件并輸入以下代碼。
/*********************************************************************************************************
EEPROM 驅(qū) 動(dòng) 文 件
*********************************************************************************************************/
#ifndef _AT24Cxx_H_
#define _AT24Cxx_H_
#include "sys.h"
/*********************************************************************************************************
函 數(shù) 列 表
*********************************************************************************************************/
void AT24Cxx_Init( void ) ; //AT24C初始化
void IIC_Write_Data( u8 Address, u8 Data ) ; //寫(xiě)入1個(gè)數(shù)據(jù)
void AT24Cxx_Write_nData( u16 Address, u8 *Buffer, u16 Len ) ; //寫(xiě)入n個(gè)數(shù)據(jù)
void AT24Cxx_Read_Data( u16 Address, u8 *Data ) ; //讀取1個(gè)數(shù)據(jù)
void AT24Cxx_Read_nData( u16 Address, u8 *Buffer, u16 Len ) ; //讀取n個(gè)數(shù)據(jù)
#endif
(2)創(chuàng)建at24cxx.c文件并輸入以下代碼。
/*********************************************************************************************************
EEPROM 驅(qū) 動(dòng) 程 序
*********************************************************************************************************/
#include "at24cxx.h"
#include "delay.h"
/***************************************************
Name :IIC_Write_Data
Function :寫(xiě)入1個(gè)數(shù)據(jù)
Paramater :
Address:地址
Byte:讀取的字節(jié)
Return :None
***************************************************/
void IIC_Write_Data( u8 Address, u8 Byte )
{
u16 Time, tmpreg ;
tmpreg = tmpreg ;
//等待BUSY標(biāo)志置0
Time = 0 ;
while( ( ( I2C1->SR2&0x02 )==0x02 )&&( Time<65535 ) )
Time ++ ;
I2C1->CR1 &= ~( 1<<11 ) ; //禁用Pos
I2C1->CR1 |= 1<<8 ; //開(kāi)始信號(hào)
//等待SB標(biāo)志置1
Time = 0 ;
while( ( ( I2C1->SR1&0x01 )==0 )&&( Time<65535 ) )
Time ++ ;
I2C1->DR = 0xA0 ; //發(fā)送從機(jī)地址
//等待地址發(fā)送結(jié)束
Time = 0 ;
while( ( ( I2C1->SR1&0x02 )==0 )&&( Time<65535 ) )
{
Time ++ ;
if( ( I2C1->SR1&0x400 )==0x400 )
{
I2C1->SR1 &= ~( 1<<10 ) ; //清除AF標(biāo)志
I2C1->CR1 |= 1<<9 ; //結(jié)束信號(hào)
break ;
}
}
tmpreg = I2C1->SR1 ; //清除地址標(biāo)志
tmpreg = I2C1->SR2 ;
//等待TXE標(biāo)志置0
Time = 0 ;
while( ( ( I2C1->SR2&0x04)==0 )&&( Time<65535 ) )
{
Time ++ ;
//檢查是否檢測(cè)到NACK
if( ( I2C1->SR1&0x400 )==0x400 )
{
I2C1->SR1 &= ~( 1<<10 ) ;
I2C1->CR1 |= 1<<9 ; //結(jié)束信號(hào)
break ;
}
}
I2C1->DR = Address ; //發(fā)送寄存器地址
//等待TXE標(biāo)志置1
Time = 0 ;
while( ( ( I2C1->SR1&0x80 )==0 )&&( Time<65535 ) )
{
Time ++ ;
//檢查是否檢測(cè)到NACK
if( ( I2C1->SR1&0x400 )==0x400 )
{
I2C1->SR1 &= ~( 1<<18 ) ; //清除NACKF標(biāo)志
I2C1->CR1 |= 1<<9 ; //結(jié)束信號(hào)
break ;
}
}
I2C1->DR = Byte ; //發(fā)送數(shù)據(jù)
//等待BTF標(biāo)志被置1
Time = 0 ;
while( ( ( I2C1->SR1&0x04 )==0 )&&( Time<65535 ) )
{
Time ++ ;
//檢查是否檢測(cè)到NACK
if( ( I2C1->SR1&0x400 )==0x400 )
{
I2C1->SR1 &= ~( 1<<10 ) ; //清除NACKF標(biāo)志
I2C1->CR1 |= 1<<9 ; //結(jié)束信號(hào)
break ;
}
}
I2C1->CR1 |= 1<<9 ; //結(jié)束信號(hào)
delay_ms( 10 ) ;
}
/***************************************************
Name :IIC_Read_Data
Function :讀取1個(gè)數(shù)據(jù)
Paramater :
Address:地址
Return :讀取的數(shù)據(jù)
***************************************************/
void IIC_Read_Data( u8 Address, u8 *Data )
{
u16 tmpreg, Time;
tmpreg = tmpreg ;
//等待BUSY標(biāo)志置0
Time = 0 ;
while( ( ( I2C1->SR1&0x02 )==0x02 )&&( Time<65535 ) )
Time ++ ;
I2C1->CR1 &= ~( 1<<11 ) ; //禁用Pos
//發(fā)送從機(jī)地址
I2C1->CR1 |= 1<<8 ; //開(kāi)始信號(hào)
Time = 0 ;
//等待SB標(biāo)志置1
while( ( ( I2C1->SR1&0x01 )==0 )&&( Time<65535 ) )
Time ++ ;
I2C1->DR = 0xA0 ; //發(fā)送從機(jī)地址
//等待地址發(fā)送結(jié)束
while( ( ( I2C1->SR1&0x02 )==0 )&&( Time<65535 ) )
{
if( ( I2C1->SR1&0x400 )==0x400 )
{
I2C1->SR1 &= ~( 1<<10 ) ; //清除AF標(biāo)志
I2C1->CR1 |= 1<<9 ; //停止信號(hào)
break ;
}
}
tmpreg = I2C1->SR1; //清除ADDR標(biāo)志
tmpreg = I2C1->SR2;
//等待TXE標(biāo)志置1
while( ( ( I2C1->SR1&0x80 )==0 )&&( Time<65535 ) )
{
//檢查是否檢測(cè)到NACK
if( ( I2C1->SR1&0x400)==0x400 )
{
I2C1->SR1 &= ~( 1<<10 ) ; //清除NACKF標(biāo)志
I2C1->CR1 |= 1<<9 ; //通用結(jié)束
break ;
}
}
I2C1->DR = Address ; //寫(xiě)入數(shù)據(jù)
//等待BTF標(biāo)志置1
while( ( ( I2C1->SR1&0x04 )==0 )&&( Time<65535 ) )
{
//檢查是否檢測(cè)到NACK
if( ( I2C1->SR1&0x400)==0x400 )
{
I2C1->SR1 &= ~( 1<<10 ) ; //清除NACKF標(biāo)志
I2C1->CR1 |= 1<<9 ; //通用結(jié)束
break ;
}
}
I2C1->CR1 |= 1<<9 ; //通用結(jié)束
//等待忙標(biāo)志退出
Time = 0 ;
while( ( ( I2C1->SR1&0x02 )==0x02 )&&( Time<65535 ) )
Time ++ ;
I2C1->CR1 &= ~( 1<<11 ) ; //禁用Pos
//發(fā)送從機(jī)地址
I2C1->CR1 |= 1<<10 ; //開(kāi)啟應(yīng)答信號(hào)
I2C1->CR1 |= 1<<8 ; //開(kāi)始信號(hào)
//等待SB標(biāo)志置1
Time = 0 ;
while( ( ( I2C1->SR1&0x01 )==0 )&&( Time<65535 ) )
Time ++ ;
I2C1->DR = 0xA1 ; //發(fā)送從機(jī)地址
//等待地址標(biāo)志置1
while( ( ( I2C1->SR1&0x02 )==0 )&&( Time<65535 ) )
{
Time ++ ;
//檢查是否檢測(cè)到STOPF
if( ( I2C1->SR1&0x10 )==0x10 )
{
I2C1->SR1 &= ~( 1<<4 ) ; //清除停止標(biāo)志
break ;
}
}
I2C1->CR1 &= ~( 1<<10 ) ; //禁止應(yīng)答
tmpreg = I2C1->SR1; //清除ADDR標(biāo)志
tmpreg = I2C1->SR2;
I2C1->CR1 |= 1<<9 ; //通用應(yīng)答
//等待直到RXNE標(biāo)志置1
Time = 0 ;
while( ( ( I2C1->SR1&0x40 )==0 )&&( Time<65535 ) )
{
Time ++ ;
//檢查是否檢測(cè)到STOPF
if( ( I2C1->SR1&0x10 )==0x10 )
{
I2C1->SR1 &= ~( 1<<4 ) ; //清除停止標(biāo)志
break ;
}
}
*Data = I2C1->DR ; //從DR讀取數(shù)據(jù)
}
/***************************************************
Name :AT24Cxx_Write_nData
Function :寫(xiě)入n個(gè)數(shù)據(jù)
Paramater :
Address:地址
*Buffer:數(shù)據(jù)緩存
Len:數(shù)據(jù)長(zhǎng)度
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時(shí)鐘初始化
SysTick_Init( 72 ) ; //SysTick初始化
USART1_Init( 72, 115200 ) ; //初始化串口1波特率115200
AT24Cxx_Init() ; //AT24C初始化
AT24Cxx_Write_nData( 0, TEXT_Buffer, 18 ) ; //從第0個(gè)地址處開(kāi)始寫(xiě)入
AT24Cxx_Read_nData( 0, datatemp, 18 ) ; //從第0個(gè)地址處開(kāi)始讀出
while( 1 )
{
}
}
-
存儲(chǔ)器
+關(guān)注
關(guān)注
38文章
7653瀏覽量
167426 -
EEPROM
+關(guān)注
關(guān)注
9文章
1086瀏覽量
83775 -
存儲(chǔ)芯片
+關(guān)注
關(guān)注
11文章
935瀏覽量
44151
發(fā)布評(píng)論請(qǐng)先 登錄
如何使用Flash模擬EEPROM存儲(chǔ)參數(shù)

EEPROM的存儲(chǔ)原理/選型/特點(diǎn)/應(yīng)用
EEPROM掉電存儲(chǔ)實(shí)驗(yàn)過(guò)程
EEPROM開(kāi)機(jī)記憶存儲(chǔ)實(shí)驗(yàn)
EEPROM的存儲(chǔ)原理以及EEPROM特點(diǎn)的介紹
STM32入門(mén)學(xué)習(xí)筆記之EEPROM存儲(chǔ)實(shí)驗(yàn)1

評(píng)論