位带操作也叫原子操作,也称别名。起作用直接进行位带操作,即直接读取寄存器的X位,或直接写寄存器的X位。
& I$ v1 |" w7 d0 W4 H STM32的寄存器为32位的,在写入寄存器的x位中,通常操作为;排除寄存器除x外的其它位,在进行赋值。而位带操作可直接写寄存器的x位,使位操作更为便捷。3 m2 ^) ~- k. C2 F/ p/ c: p1 C4 _
& [/ }& _. T9 R1. 实验内容及步骤:
* `: h) G* c# u( f实验内容:
, ?$ x, S0 y3 s, s' N3 J" \, u( ~$ r
: Y0 {1 p% K, J1 C9 j8 ^4 H 通过位带操作实现LED灯的翻转,和按键的读取。
! |# ^( Z5 g! v9 d2 c, W: V! ]3 u, {+ t8 M$ ~
按键按下时,LED亮,松开按键时,LED灭;8 x/ S: j4 O* E7 D, ^3 k0 o
) b* m6 o) Z5 w: _/ V6 v
步骤:6 N* i7 q9 n" s1 e w
3 ?4 E) X7 |- X
根据原寄存器地址定位位带地址;) B( E' N% w# O: Q% W
% }. f8 D9 A# O+ n; ~2. 硬件说明
3 I; Z2 r3 f& c7 n0 n D
2 q c! c+ U+ a, }$ E9 q( i1 o/ Y0 K' A, t/ ~& _9 Q/ J
; K7 R7 D( \# a: `. x0 @% S! k
. R4 x0 M& e4 Q! ~8 B3 R
! {7 _% q" p& [! V6 E0 A- |1 J, s, |! I
按键与PE4相连接,按下时低电平(所以GPIOE4应该配置为上拉输入,按下:低电平;松开:高电平)2 P2 V A, e: v6 n8 W
8 |+ b5 ]0 y0 D$ Y0 t1 P LED与PB5相连,另一端接VCC,(所以GPIOB5应该配置为推挽输出,亮:低电平;灭:高电平)
- a5 [$ w) \: { @0 D; ^: ^# \& x; }0 D* ]4 Y4 \! _
3. 位带操作原理
% n6 g7 V* w+ ?$ l9 _; j STM32F1内部是有两个位带区的,如下图所示。
+ u! M% @" s5 @
$ |) E+ `4 S! x4 u5 B
! T ?. Y, w/ a: F6 C- m4 H( P, l7 v& h4 l9 @) q* ]0 P, f
位带操作分别有片上外设和片上SRAM。我们用的比较多的通常是片上外设的位带操作,一般用来控制GPIO的反转和读取。
% b* n, @5 e1 P5 C s' m- ?( p9 y l" _# ~" F9 p8 g
* M( R# B# p3 t) ~
0 r. C9 X' V, z4 n其膨胀对应关系图如下图所示,以SRAM位带操作位例,0x2000 0000地址的第一位,映射到0x2200 0000地址。其用法如下所示:
- }; I9 @" r5 D: h1 b
$ v: Z& K0 t2 {; A9 o% W 当0x2200 0000的内容=1时 => 0x2000 0000的内容=0x01
2 m( l4 z |/ I- \" P$ A8 R9 E+ L/ o" {9 g
当0x2200 0000的内容=0时 => 0x2000 0000的内容=0x00
+ t. Q* B% a, m# {# Q; `. w
. d& T, U/ w- E1 p( R, N ……………
8 ]# |: O6 {0 y3 y, S
$ l o8 P' m3 y+ Z& s2 `, M, f3 [ 当0x2200 0018的内容=1时 => 0x2000 0000的内容=0x40=(二进制)0100 0000/ @4 S4 V8 j4 R- x9 {1 X
. E) c% B$ G/ O3 P4 z( Y, G
当0x2200 0018的内容=0时 => 0x2000 0000的内容=0x00
3 Q, b2 ?) q/ ?" l$ H
3 m- c, C' ]. p0 T6 N- a- Z0 s4 O6 c- [ P X" |" r- T
' [! h4 e; m8 |9 k7 P4. 寄存器说明
# X2 Z( h% x, k5 i$ n+ K* W+ ~9 e 位带映射地址如下图所示。(中文STM32参考手册P29)5 D3 i7 @; ^ I6 p9 [, u: W% w
. c5 r$ K- _0 U* c# {; ~! A$ D3 u0 D d$ x4 F, M6 x6 {5 r8 P
9 I+ ^) N. S% R
位带操作的例子如下图所示(CM3权威指南CnR2)
, t8 \5 O4 h- c* d. S i' M- \: Z0 c# E$ x, l9 @3 b
5 E* V2 j. I# {2 e" W
$ z% j$ H( H* G8 w7 V- t 根据例子可写成通用的式子。1 Y# C' M% Q, x8 ?; E$ C
% T( v0 q5 q9 R5 G8 j$ L4 p9 o! ?* z
bit_word_addr = (IN_ADDR_BASR&0xF0000000|0x02000000)+ (IN_ADDR_BASR&0x000FFFFF)*32+Bit*4+ v" E: q6 D0 Q( M0 V( }, B
7 C+ ]6 R" l: B( Y6 a& E* R => , L& A6 l' M P
7 u. ]6 h, x# Y1 J- W+ e0 G" u
bit_word_addr = (IN_ADDR_BASR&0xF0000000|0x02000000)+ ((IN_ADDR_BASR&0x000FFFFF)<<5)+(Bit<<2)
+ T& Z5 h o/ T3 M0 w
+ L9 P' t0 z( q* v" n7 m 如要控制LED灯(PB5)
; t: v I' x$ r
3 n& X" A9 |. V; ` IN_ADDR_BASR = GPIOB的输出寄存器 = 0X4001 0C00 + 0x0C;
; T+ w+ t# x# [/ o) o8 n6 m* J' I8 x
Bit = 59 s( T6 G1 ?+ @) f/ j# v
8 C2 j' f8 }% s8 r
5. 程序设计
, c4 @3 X# I6 i9 d# K$ I& | 代码班的通用位带操作地址转换宏定义如下:
f; g0 f8 G. p* t- #define BIT_WORD_ADDR(IN_ADDR,BIT) *(__IO uint32_t*)((IN_ADDR&0xF0000000|0x02000000) +((IN_ADDR&0x000FFFFF)<<5) + (BIT<<2))
复制代码 % e+ m* ?6 n0 {% O u
GPIO的输出位带宏定义如下定义
, B, r5 X2 h2 P6 s+ T0 b+ {- #define BPB_OUT(BIT) BIT_WORD_ADDR((GPIOA_BASE+0x0C),BIT)
复制代码 BIT为要操作的位。6 D# F/ Z' b; f+ o, O0 A- a
在本实验中要操作LED(PB5),因此BIT=5;, l8 ]' f1 |7 V( ]. A2 @0 a
% r+ U& j1 o+ Z& w; a5 Y
GPIO的输入位带宏定义如下定义8 u! w2 R6 i# C; Z, o$ }7 T$ `8 O
& e3 I' R: a% h$ e* g+ y: y #define BPE_IN(BIT) BIT_WORD_ADDR((GPIOE_BASE+0x08),BIT)
2 ^: M) I% ~9 v BIT为要操作的位。
1 i1 l% e" O6 k' v L
Z7 M9 R% c/ k) @在本实验中要读取按键(PE4)的值,因此BIT=4;& T8 Z: {) M: B1 f" f
# i0 B9 Z; b, v
; r9 m# k( C' G; t/ w- N/ U* P" g
$ y7 |5 t9 [1 f: r
位带操作源码:
- C0 W$ C# B+ r }
" X1 X0 D4 Q3 b, S# M源码筛选了关键部分,详细看源码。
" o: z0 N& r5 H. U! S" l
, G. z" ?' F- |) ^$ Q$ v- #define BIT_WORD_ADDR(IN_ADDR,BIT) *(__IO uint32_t*)((IN_ADDR&0xF0000000|0x02000000) +\. Y$ z, ^ b* x; {" Y
- ((IN_ADDR&0x000FFFFF)<<5) +\
6 @% o Q# Q# p. b- h' T+ D. @$ s, [! A - (BIT<<2))1 a) \4 M, k/ {* p
; Y* k) V) S7 I0 ?- //GPIO_OUT: F0 q: [) m j. y T& J
- #define BPA_OUT(BIT) BIT_WORD_ADDR((GPIOA_BASE+0x0C),BIT)
: o. j6 _ r6 W( F1 ^0 ]6 k: u - #define BPB_OUT(BIT) BIT_WORD_ADDR((GPIOB_BASE+0x0C),BIT)7 ~. c! S8 B0 |: `. S
- #define BPC_OUT(BIT) BIT_WORD_ADDR((GPIOC_BASE+0x0C),BIT)9 z- N; L9 c; c5 A+ ]% f
- #define BPD_OUT(BIT) BIT_WORD_ADDR((GPIOD_BASE+0x0C),BIT)% [+ O, k) q9 a/ s
- #define BPE_OUT(BIT) BIT_WORD_ADDR((GPIOE_BASE+0x0C),BIT)
, x& z. V8 O: C7 R2 q - #define BPF_OUT(BIT) BIT_WORD_ADDR((GPIOF_BASE+0x0C),BIT)
8 Y0 A! E6 Q/ y: T+ A2 ]6 C - #define BPG_OUT(BIT) BIT_WORD_ADDR((GPIOG_BASE+0x0C),BIT). F) v! b: l6 U; ]5 R6 q) D0 }/ X$ C
- //GPIO_IN. c/ r$ t* _) I+ v7 ?
- #define BPA_IN(BIT) BIT_WORD_ADDR((GPIOA_BASE+0x08),BIT)
) O2 g9 l3 T, \. C - #define BPB_IN(BIT) BIT_WORD_ADDR((GPIOB_BASE+0x08),BIT)
" d7 J% r; N. v- J4 c" S - #define BPC_IN(BIT) BIT_WORD_ADDR((GPIOC_BASE+0x08),BIT)" n( I! u' I8 C0 `2 S
- #define BPD_IN(BIT) BIT_WORD_ADDR((GPIOD_BASE+0x08),BIT)# D6 l5 i1 t+ u
- #define BPE_IN(BIT) BIT_WORD_ADDR((GPIOE_BASE+0x08),BIT), o$ m, Z5 N* f; A
- #define BPF_IN(BIT) BIT_WORD_ADDR((GPIOF_BASE+0x08),BIT)) j3 Z1 i) W6 Q! Y
- #define BPG_IN(BIT) BIT_WORD_ADDR((GPIOG_BASE+0x08),BIT)
复制代码
4 [! G( J- o$ C. }1 \& }6. 实验结果
# ^9 B) M/ n, k( t; s5 Q 按键按下后,LED灯亮;
2 i& b0 E8 r8 `7 Q8 j; ?8 c- P
按键松开后,LED灯灭。/ @) J4 R* s' ?$ [% _
$ x9 C" k0 @3 D$ f
! ~. m! Y, ?! \6 U$ f5 O" \) ?( @- n
4 Z2 L6 v1 ]* ~/ |( E
|