一、源代码
6 W/ v+ ^3 P3 I8 z# [3 E9 K" |" [7 C3 z4 }3 D9 B
- void eeprom_init()' a/ ]7 T/ S9 G8 g2 V( z4 h
- {
$ A- s* i1 e9 v- l" b/ ^7 m - GPIO_InitTypeDef GPIO_InitStructure;
# f. _0 v* v7 w L( {+ p - SPI_InitTypeDef SPI_InitStructure;2 S9 J6 k5 a8 Z; x6 c$ j
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能
% |, n4 p9 Y+ w$ o v - ' `# ?' [$ S+ P7 }
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12; // PB12 推挽 7 R- F* x5 I; {$ u( R3 V9 P
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出2 ]( B- z/ ]6 N2 d
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;1 z8 j: A: a5 k! g8 u: W
- GPIO_Init(GPIOB, &GPIO_InitStructure);7 F9 y/ S% X) q4 [, t4 m) \
- GPIO_SetBits(GPIOB,GPIO_Pin_11|GPIO_Pin_12);/ H* U, v O' X5 h& L8 V
- $ M7 D& S/ O) o6 @6 z8 X2 m( @+ R
- 4 @8 L* R- U \6 ~' E: l
- 8 y/ X$ V* P, y- ?
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能
p% o0 O% V w" L6 Q+ ^: L# f - RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );//SPI2时钟使能 4 Y- ^# j6 Y; W3 t
- 0 D. c1 K: q; N3 G8 D: r
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;9 D7 D. ~' G" m+ D0 M* u$ O; m
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15复用推挽输出 2 O- z3 O/ r, A9 c
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
) d1 ~% Q+ S& z; H; N& O) z e - GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
* b% K- a2 l0 f# L1 Z/ K - $ @) z) q O- i* Y `2 l
- GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //PB13/14/15上拉
7 K, t! V$ o9 r. m
: I8 ~8 g- J0 I& M' |$ j- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工' h' M! h& U) e L$ K
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI( c" f2 z# {, p
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构! p5 l7 v) H* B% f% S6 K( E+ E
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为高电平
: j" P% j. X/ y) j* k - SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样9 r+ C0 k1 J# z
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制# g, k# P6 Q" R' i- D4 s
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定义波特率预分频的值:波特率预分频值为256
$ |7 O. b6 u* R4 v' w% O3 B - SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始) v- i$ Q$ v; }: W4 _9 x
- SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
3 S# p8 m5 P( U, g$ {: ~2 S: h1 {9 U - SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
& V+ w1 k, b5 `- w8 M - 4 `" w8 L9 i9 F+ z
- SPI_Cmd(SPI2, ENABLE); //使能SPI外设
$ v6 c7 e$ v$ ^5 s) p% x; | -
, K! d% m) z. K q$ o2 o+ M - eeprom_read_write_byte(0xff);//启动传输
7 O: c' O8 z3 l( C' y - }+ @/ G+ Z2 j$ v$ L# @% J3 K
- //SPI 速度设置函数) l: i& U$ |, L# _, n
- //SpeedSet:
! r# G. M% v! ~4 }+ C - //SPI_BaudRatePrescaler_2 2分频 + o, |2 g8 B! e( S$ A: G( h
- //SPI_BaudRatePrescaler_8 8分频
3 B+ f v# ^7 G/ u$ T# w - //SPI_BaudRatePrescaler_16 16分频 1 f, z7 @9 ^" c3 `; _
- //SPI_BaudRatePrescaler_256 256分频 + Q( d+ u5 j* E6 \8 ?6 R
1 h# X2 M* \2 v2 L8 X" o- void eeprom_set_speed(u8 SPI_BaudRatePrescaler)% y2 p0 [7 w' H0 s) @
- {& c6 J/ u- `8 ^( A0 I2 [
- assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
' v/ `; Z# u D( k2 C - SPI2->CR1&=0XFFC7;
: s x8 o! d. B' P - SPI2->CR1|=SPI_BaudRatePrescaler; //设置SPI2速度 , g6 Q! _! ^+ p
- SPI_Cmd(SPI2,ENABLE);
" z5 `& q0 m2 f
: a! T) g. c! Z- }
复制代码- //SPIx 读写一个字节
/ h }$ M S3 N( ? - //TxData:要写入的字节
/ C+ @% \ f3 h8 t& s) S - //返回值:读取到的字节
0 z9 o! g6 q' ~. H - u8 eeprom_read_write_byte(u8 TxData)
N1 V! x& j a( Q+ g( x, A" Y; L - {
1 ^+ _& p8 e" _7 o2 a - u8 retry=0;
) v$ J+ B# X# Z0 Q5 ?. g& S - while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
/ s0 V: k4 a9 \. ?# o7 T - {
* ?5 t5 s1 U9 P" t* b# P0 y) D - retry++;: ? l* U; j, J" B
- if(retry>200)return 0;/ F9 n& ]' m: M+ {( |+ w" ^
- } 1 z9 u* k7 U3 G) t/ ^+ i8 ^; [
- SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据, f' q! l4 B; d4 S) P
- retry=0;; N" v1 Z: ?) {5 m( c
- 1 c' B! t% a2 `! W5 g5 s
- while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位6 }: }, s; s. S
- {
* p0 R; }; m- _/ O; t- g4 D - retry++;( A4 D8 R; B6 X6 C
- if(retry>200)return 0;6 G) A v) M8 ^2 c0 {. G2 i
- } ; Y* h4 U0 ?% V7 Q: T% n4 h
- return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据 ( G* @1 p6 U8 G" ^" f3 {
- }
复制代码- //==============================================================================& o6 F7 S' F7 C$ p; K# O
- // 描述: 在AT25读状态寄存器
6 r+ n( o" }8 a - // 输入: 无( A D4 g% k1 e0 c& s# P
- // 返回: unsigned char dat 状态寄存器数据
; l* p$ j4 B% j/ R - //==============================================================================
( I' ?: D i- ]; O# i% g$ m" m
' d) I8 G7 y. ^
& ~, w: t1 q5 G5 v$ l l. I8 D7 f- u8 eeprom_read_sr(void)
$ ^9 S: M7 i' T$ F - { . B% j! k( I' Q- q; f1 m2 W! q
- u8 dat; A# z' _1 e' T; G
- eeprom_cs=0; 9 J0 m% b3 Y4 I+ K) T
- eeprom_read_write_byte(RDSR); // 定入指令0x055 C: c* `" f: \, A, M4 [2 a
- dat = eeprom_read_write_byte(0xff); // 读回数据
3 m. i+ l: {& c" a# t" I0 c - eeprom_cs=1;) M; `3 `9 m. a
- return dat;
3 O, t6 ?. s9 g) B! p& G+ \! J( O - }
$ L2 J( F- \' N" X! Y, O. p, R" d
8 G/ i @6 D0 L: G& m5 X0 J7 z2 n8 P( @- //==============================================================================$ \" y( N8 P3 G9 S: |/ A
- // 描述: 向AT25写入一个数据
& Q# k) p' }1 M) V& e1 L - // 输入: unsigned char Dat 字符数据
! }! X2 {) W8 K, N6 r% R9 w - // unsigned int addr 写入的地址+ c5 U8 U# e5 c2 S8 N9 L0 }
- // 返回: 无+ a4 D8 S6 A& Y S
- //==============================================================================
$ C) ?( m/ f0 d: s0 W7 h7 H - void eeprom_write_byte(u16 addr,u8 Dat)
* J& Q1 F# x# ~. n - { # z4 R5 X( P# X
- unsigned char Add; 7 r+ d) n0 J% a- V3 Y- l9 H
- while(eeprom_read_sr()&RDY); // 读状态寄存器
4 W4 Q9 C7 Q" G" J/ ^. r -
! p' k6 w- k* P - eeprom_cs=0;
, n" ?; q T# g' O- N3 M$ e! U - eeprom_read_write_byte(WREN); // 写使能锁存
, v# O2 G$ ^) e( H7 b - eeprom_cs=1;1 ^; E; w8 m: ^% B0 V
- 4 B* `( ?/ e- y; D$ U
- eeprom_cs=0; // 芯片使能
8 y* ? ~- L- d, b1 z - // 写入写操作指令 2 W9 h4 m. ^4 }' V& w$ }
- if(addr>0x00ff)
4 y8 l- \1 X5 R L0 M$ y( z - eeprom_read_write_byte((WRITE|0x08)); // 地址大于255- }/ h. s% q4 J7 X8 U" X/ @
- else8 h8 [8 H! k# S1 x
- eeprom_read_write_byte(WRITE); // 地址小于255
7 Q2 B8 K$ ^2 \# ^8 H% Z
W$ Y# Y O* C/ }; T5 ~- // 写入地址3 K' k1 \. O8 t9 x, d
- Add = (unsigned char)(addr & 0xff); // 将地址换成8位. }" B+ B6 P1 H! {* \' @7 r4 s- e
- eeprom_read_write_byte(Add);
* e! T: g, C% R; v- ? - / W; g* c! f% t. j3 n
- // 写入数据
, z+ Q7 a( W1 S- `4 z, C - eeprom_read_write_byte(Dat);! h0 A6 K/ i3 x% ^5 Z( L. S2 r& f$ l
- eeprom_cs=1; // 芯片关闭
& N6 _. L9 o4 l* [ - }
1 v2 Z: w1 ?% Z# B) S" V, U - //==============================================================================7 _% q! K; c5 n( p8 _# E
- // 描述: 在AT25读一个字节操作0 i6 c1 x) s- b( y2 T
- // 输入: 无# d2 e7 @+ D" y( w. j
- // 返回: unsigned char dat 读出一个字符数据) S5 e2 K' Z' @) h
- //==============================================================================7 s2 I+ I7 x9 |6 @2 ]$ O
- u8 eeprom_read_byte(u16 addr)1 _( U# N4 g9 `9 i8 ~, V* u
- {
) C# K' b; M- S. L' _ - u8 dat,add;0 ~$ R( q" @; u w3 K) O
- while(eeprom_read_sr()&RDY); // 读状态寄存器
6 | q$ Q- X, i: i6 Z% Q - eeprom_cs=0;, `/ w5 p4 L0 j& A: z P
- // 写入写操作指令 " f- ^* I9 @ l7 c) P+ r
- if(addr>0x00ff)
. [ ~ j; U7 O6 J5 q0 q- K - eeprom_read_write_byte((READ | 0x08)); // 地址大于2553 _ ^7 V1 E! h7 N- S4 I l0 x4 z0 C
- else; g4 Z o$ M2 R% A' ~
- eeprom_read_write_byte(READ); // 地址小于255
& z+ E4 H! s1 c( F6 ]: Q; e - ; f7 ^# e. @& N
- // 写入地址
5 k* B; M+ {: P# ^$ K - add = (unsigned char)(addr & 0xff); // 将地址换成8位
& i$ p) o" s. K* g2 j1 z - eeprom_read_write_byte(add); + g4 @! }1 v- S3 W+ t- s% E- ?
- $ r) ^* a) H* T* ^# _) u
- // 读出一个数据+ y1 t. _% Y- c5 X8 y3 a
- dat=eeprom_read_write_byte(0xff);4 ^- s9 B8 N: j& I
- eeprom_cs=1;$ h5 H- I1 U5 T! o- Y: M7 L. p9 r
- return dat;% O& y) R; d& w" T
- }
% ^ l0 k6 C4 R1 F- o7 O - //==============================================================================
" e3 d4 i5 E& o+ ^. q4 |+ x! R - // 描述: 向AT25连续写入数据
/ d$ }. f7 x9 J, q2 P+ ? - // 输入: unsigned char *PC 写入数据指针. k9 X; G! ]* Y* D( s
- // unsigned int count 写入数量计数 . Z+ M: k) z' Q, J$ b6 ~* u
- // unsigned int SatAddr 写入起始地址
% s f2 F/ K. U/ O+ i2 s0 n8 G" | - // 返回: 无' a) b% J+ @ K0 w! } W
- //==============================================================================
. g5 @0 x- s: w( v) R7 i6 S - void eeprom_write_buf(u16 startAddr,u8 *buf,u16 count)
) z) R2 l( ~: e9 H* [7 I - {
' o+ k/ H' \& U& H( E7 G" e - u8 Add;
8 M% g9 t! H6 M$ R - u16 i;7 Z1 y. p6 a+ q9 s
- while(eeprom_read_sr()&RDY); // 读状态寄存器
! b) t8 T% O2 \2 M
1 p- h% _9 |8 R* K& o; r% K7 u% g- eeprom_cs=0;
, g6 _6 c( U2 I1 _* z/ I# u - eeprom_read_write_byte(WREN); // 写使能锁存
M9 Z& |8 R8 F: [ - eeprom_cs=1;
. N( ^1 @6 ^4 j - eeprom_cs=0;
/ h* j( M1 |$ M1 H5 P) @ - // 写入写操作指令 8 B" n) w$ D3 K: n
- if(startAddr>0x00ff)4 S- s( _ Y; i
- eeprom_read_write_byte((WRITE|0x08)); // 地址大于255( E' E2 X f" D1 B' c3 D
- else
! l5 \" g V- M8 l: a$ X% k7 F6 ? - eeprom_read_write_byte(WRITE); // 地址小于2551 f8 J, `) i; v9 _2 b2 k6 J
- 9 E$ J" C) N! @9 }& I4 B
- // 写入地址, S" w0 Y& {7 ~- s2 b; B, Z
- Add = (unsigned char)(startAddr & 0xff); // 将地址换成8位* i: k* T$ p% T3 V7 d2 ~4 R% F& h
- eeprom_read_write_byte(Add);
% M% b W T) y - ! f5 x8 X2 P7 Z" B5 }! \3 w
- for(i=0;i<count;i++)// 写入数据6 ?+ C- Z4 J' ?# _
- {
/ X, ^( k. \0 U! F, x - eeprom_read_write_byte(*buf++);/ C! V1 g. z; ~# Z
- }- g8 |( v* r9 U6 Q( ^
- eeprom_cs=1; // 芯片关闭 {/ U, |( z6 p$ _, d5 X
- }
: V: w3 m: \% c1 r" i - //==============================================================================3 I4 j# Y _& k8 x3 ~' g) l) J: h* G
- // 描述: 在AT25连续读数据& B: W& L. c) z9 S4 ^
- // 输入: unsigned char *PC 读出数据指针
) X! }9 \4 N' V$ A - // unsigned int count 读出数量计数 6 j# @: P2 g3 M; q9 P5 V* ~! U! V
- // unsigned int SatAddr 读出起始地址
& l& `7 H, m1 G( t2 p, { - // 返回: 无3 b# B4 v* T* R% C4 B1 q
- //==============================================================================' u# H7 s3 K. N" X0 o l ]! o
- void eeprom_read_buf(u16 startAddr,u8 *buf,u16 count)( }5 S0 _. N. _- v" w, ]
- { ( I: P2 g' j( e6 w! J6 B7 s8 B
- unsigned char Add; - C* e( D6 u+ I- G5 o
- unsigned int i;( w- x- ~& s9 T5 t
- while(eeprom_read_sr()&RDY); // 读状态寄存器
) n) }' X" a5 _+ o3 g) U, e. z0 _ - eeprom_cs=0;
0 s) b( A) F/ u6 P- H$ _ - // 写入写操作指令 # N1 K4 ]2 c q, |6 b+ |4 b2 Y
- if(startAddr>0x00ff): \, ?! s: a6 M( ?- D& m- S
- eeprom_read_write_byte((READ | 0x08)); // 地址大于255
q- s& ?+ N$ X! i2 S& k - else
y- `. V+ p8 r& [0 C& P - eeprom_read_write_byte(READ); // 地址小于255
: l* k3 U5 q3 S- ?$ i
# R( o# ~, q( @: n* b* [9 Q4 b5 J- // 写入地址4 T# A& F9 l* D: \4 | M! }; a
- Add = (unsigned char)(startAddr & 0xff); // 将地址换成8位
% q5 W: e0 K& s0 K - eeprom_read_write_byte(Add); , w4 f: ]2 I- V+ L" f1 f& F
- 2 ]8 S* t& ^( T3 S, W9 y
- // 读出n个数据6 S/ F( r" a+ ~) E d! `3 X
- for(i=0;i<count;i++)
4 L& i6 I$ U$ C+ O9 g( F! G - {
6 L; {6 f6 K& Y% d) C - *buf++ = eeprom_read_write_byte(0xff);
2 }- c6 i5 X$ q N - }' }5 X3 {/ f; y; {# b0 a
- eeprom_cs=1;
t+ @7 Z% {- s& Q - }
复制代码 / r; b/ P( R5 U3 _' ~2 t$ J* ]0 N! q
二、测试
/ Q' o, m5 _2 b* u
4 T2 |" W/ x! i: E, W5 \- int main(void)
& d0 n1 V' W& o) \+ F - {
! G. L) G. C$ @2 {8 G - u8 buf[5]={0x01,0x02,0x03,0x04,0x05},i;
1 w$ U8 n# ?1 Y" v/ h - uart_init(115200);8 c! d- y+ ~- y" u2 p& P
- delay_init(); 7 g; V/ K2 n3 z: f* X6 n
- program_led_init();
3 x. U B/ J. K. u6 C0 I' G* i& d -
5 ?7 M8 U4 k. Y% T' F" k - eeprom_wp=1;
. A1 b" F+ \& y5 I - eeprom_init();
& U: {4 Q1 X5 B$ q6 Q - eeprom_write_buf(0x0000,buf,sizeof(buf));/ `2 u) p$ |! U2 n% F( N
- // eeprom_write_byte(0x0000,0x08);( K+ i" t) B& r& `* @( ]" B1 d
- memset(buf,0x00,sizeof(buf)); x" I* F) Z/ d/ @# P
- eeprom_wp=0;
2 M( X4 l- m, k1 G - while(1)' F! o6 C5 ]& f" I+ I+ e' I
- {
3 y5 H& L2 n1 C5 s! M# s U% r! G - : i1 k* S1 J( ? x" u" k
- eeprom_read_buf(0x0000,buf,sizeof(buf));
. v; L% ?, U& g6 B { - // buf[0]=eeprom_read_byte(0x0001);
6 |# r3 B1 x8 k6 E! T& L9 w - for(i=0;i<sizeof(buf);i++)
: ] G$ p+ b9 w% w" D' q - printf("0x%02x ",buf<i>);+ K7 R, j; Q2 u1 ~4 N4 A: q% i
- printf("\r\n");
5 a2 @: \% `# y4 P% v& g# f% j7 r - memset(buf,0x00,sizeof(buf));/ a) L9 `' [& u8 a7 k- I' ~
- 6 I+ O4 i0 Z ^
- program_led_data(0x10,0x10,0x10);
% P# z' y" v$ X; X - delay_ms(500);
9 _* K+ F a1 L
$ o4 ]+ W; u& }- program_led_data(0x00,0x00,0x00);. I* G+ M; s% u$ y! Z+ Y% X* u
- delay_ms(500);
/ S/ f/ Z: f4 | - ; i' |' B5 C! H# F
-
- h$ k8 S" f, ~* j8 ]8 m3 t - }3 G2 }: @ L4 s$ [) N8 X0 _# z& a
- }/ L I( { M1 Q6 w+ f3 N
- + v0 v" }$ g& x; e- R
2 [8 O' P, `* ~8 q- </i>
复制代码 8 }, \; Q* e& B% L* ^! i' o) R( ~
|