位带操作也叫原子操作,也称别名。起作用直接进行位带操作,即直接读取寄存器的X位,或直接写寄存器的X位。
( g4 _" @- ~' g/ Q# g# r1 a STM32的寄存器为32位的,在写入寄存器的x位中,通常操作为;排除寄存器除x外的其它位,在进行赋值。而位带操作可直接写寄存器的x位,使位操作更为便捷。. M7 I( B2 d) n0 j$ W* A
4 o. Z Y9 c8 Y& v# T# l. G
1. 实验内容及步骤:) r3 v. z1 l3 D/ `) R$ k/ c
实验内容:
; t ]- ?# D: e1 J
% f: P9 N. m) R 通过位带操作实现LED灯的翻转,和按键的读取。; F D u; [) k" B6 v7 A9 t" l( _
" H: O$ X% o) \' Q, W5 D C
按键按下时,LED亮,松开按键时,LED灭;
( @* z# ~! S. J6 m; f& F/ w! J% Q) [3 M& g! j B
步骤:
, J% T" U' e& V. O( R, O* b9 E. v" ^) c- M
根据原寄存器地址定位位带地址;
W4 J: w6 [$ ]7 { E1 j# q$ J) p& a$ G3 k
2. 硬件说明& r" Q+ e7 S1 a
0 h: _* Y% K/ |' ], {0 |/ H" i7 n- B0 F- Y* I, ?. I
" P( C' ~5 b5 Q# T" M9 u1 h5 h4 L0 l# Y& x
( Z' Q8 b6 Q6 ?
6 T2 F) G& G$ \, R! [0 ? 按键与PE4相连接,按下时低电平(所以GPIOE4应该配置为上拉输入,按下:低电平;松开:高电平); t* S* Y4 j& m% H8 y
: m) P6 N5 n( ]
LED与PB5相连,另一端接VCC,(所以GPIOB5应该配置为推挽输出,亮:低电平;灭:高电平), S& R7 d" E* e4 J/ e" r: @
. Q; p7 \+ S# R6 E! @2 c3. 位带操作原理$ Z* ?: P* j3 Q: o
STM32F1内部是有两个位带区的,如下图所示。) x! q- M$ T! }# }1 d7 _ M+ q
5 z& p- w% c6 Y
9 f/ r% c; @ Z" i- [+ q/ n" U8 \7 W& O1 h
位带操作分别有片上外设和片上SRAM。我们用的比较多的通常是片上外设的位带操作,一般用来控制GPIO的反转和读取。 ( [8 X( B# J# j
% U# H( z2 I' @% l0 j# G. F
) \5 i, _* v! U5 E0 q# n7 e1 y: }
: A/ @4 y, }+ q/ H. W1 |其膨胀对应关系图如下图所示,以SRAM位带操作位例,0x2000 0000地址的第一位,映射到0x2200 0000地址。其用法如下所示:; N: V8 T- E6 ~( p
3 ^6 l5 A9 o7 f( v {- m8 B
当0x2200 0000的内容=1时 => 0x2000 0000的内容=0x01' |. f5 {) U! D" i5 n0 D
: `) A g" F( H& b 当0x2200 0000的内容=0时 => 0x2000 0000的内容=0x00' c8 }+ A* @0 N" B3 \8 ~
' X* [. g5 {6 z7 `' y# _ ……………
3 D7 B# a k. J9 ?* d0 J. U0 R, E. X ^9 x! |9 ~9 F( R
当0x2200 0018的内容=1时 => 0x2000 0000的内容=0x40=(二进制)0100 00006 b) N( V/ i% c1 w M- y2 l
0 H4 w9 m- _8 V+ _! y2 m- a
当0x2200 0018的内容=0时 => 0x2000 0000的内容=0x00: m( T5 Z4 K5 I: M
6 V' M& N$ E* p( x5 {) s0 X$ Q: x# @2 k3 p5 B! }
, o. D: X6 h2 \5 Y
4. 寄存器说明! [6 c/ I+ t1 y* s) G4 _# a) V; g
位带映射地址如下图所示。(中文STM32参考手册P29)
J/ u5 `9 X2 Q* ]+ K/ @# }0 h8 S
+ \4 |# L/ E$ ~6 G0 |) y
- R2 ~2 r7 p/ M) [9 F+ ?9 B1 I3 v5 M. R* q8 I
位带操作的例子如下图所示(CM3权威指南CnR2)
/ i; F9 U' v0 }7 v- b2 O3 O6 H- ^7 H9 e' @, @- P0 ~
0 r$ |* s. e/ a, j
: M" e6 b p: S" p/ j
根据例子可写成通用的式子。
' x7 I' I |, c$ ]; F
: Z' {% N; M) `- ]5 ] bit_word_addr = (IN_ADDR_BASR&0xF0000000|0x02000000)+ (IN_ADDR_BASR&0x000FFFFF)*32+Bit*46 p% ]' g( W$ o. s
$ `, x$ {, z T% {8 R3 i( D => 2 o9 h- i) V) c' {
# c$ }) U- \& t- y z/ G
bit_word_addr = (IN_ADDR_BASR&0xF0000000|0x02000000)+ ((IN_ADDR_BASR&0x000FFFFF)<<5)+(Bit<<2)9 @' r/ C2 r# H& M
7 C) W, q; T. q7 m% p+ ]! P, | 如要控制LED灯(PB5)
8 b: g. l( ^$ L1 ] |6 L0 k+ s) o# a' e
IN_ADDR_BASR = GPIOB的输出寄存器 = 0X4001 0C00 + 0x0C;1 H' O M5 W6 c% Y- ~ O
J% `. d3 B% u9 f1 q1 l Bit = 58 v" w: s+ c8 O% V& v
& I2 v6 D; B; |5 a T' |
5. 程序设计; p9 x0 H* I( B) {2 f, o
代码班的通用位带操作地址转换宏定义如下:
3 j+ J5 K# F: t R+ A- Q- #define BIT_WORD_ADDR(IN_ADDR,BIT) *(__IO uint32_t*)((IN_ADDR&0xF0000000|0x02000000) +((IN_ADDR&0x000FFFFF)<<5) + (BIT<<2))
复制代码 , i: }, d. J3 V! H$ _1 l
GPIO的输出位带宏定义如下定义% |- \3 k8 X, t( G+ b0 b' ^( g
- #define BPB_OUT(BIT) BIT_WORD_ADDR((GPIOA_BASE+0x0C),BIT)
复制代码 BIT为要操作的位。
4 x8 U3 y8 P8 c3 M A 在本实验中要操作LED(PB5),因此BIT=5;+ f& C8 x$ ]+ A5 v4 c
3 k8 n* a" R+ ~2 X W. U, g& D2 o GPIO的输入位带宏定义如下定义1 u+ `" w: h4 f( y: A7 Q6 { t
0 F% t w* ]8 @ #define BPE_IN(BIT) BIT_WORD_ADDR((GPIOE_BASE+0x08),BIT)
& E, \6 m: {( {. Q BIT为要操作的位。0 i7 z' Y' n; F- w3 x- O8 T" E
6 P2 L7 {. R; b' N+ c) j在本实验中要读取按键(PE4)的值,因此BIT=4;5 j' k8 U( a$ W# ^
! S$ y1 u4 w/ C. y2 e' U, ]5 x7 o9 m7 Q9 @. W8 |0 k. Q+ U
6 A" ?( s1 r4 F, e
位带操作源码:
4 ]# Y5 @$ c* x! F8 c' n3 E8 h8 V. a& M9 |2 o# Q% t
源码筛选了关键部分,详细看源码。8 ]) p/ w Z3 L5 z3 q" I( x* a
Y. V) M8 G+ R6 E/ x- #define BIT_WORD_ADDR(IN_ADDR,BIT) *(__IO uint32_t*)((IN_ADDR&0xF0000000|0x02000000) +\3 w3 \4 o6 M5 s9 X5 S) j e" T
- ((IN_ADDR&0x000FFFFF)<<5) +\
" T, h1 s: P1 L9 }' A J7 V2 Y" r - (BIT<<2))5 P2 i7 y+ Z; U' v0 O g
- 9 E% z9 K ?' c2 j. y( N4 ~
- //GPIO_OUT
% Z ]$ p5 L- o/ U - #define BPA_OUT(BIT) BIT_WORD_ADDR((GPIOA_BASE+0x0C),BIT)
4 @$ S8 z) v1 M - #define BPB_OUT(BIT) BIT_WORD_ADDR((GPIOB_BASE+0x0C),BIT)
; f9 C9 N, a2 i) \( D - #define BPC_OUT(BIT) BIT_WORD_ADDR((GPIOC_BASE+0x0C),BIT)& K# ~- H; p3 j
- #define BPD_OUT(BIT) BIT_WORD_ADDR((GPIOD_BASE+0x0C),BIT)
' k* S! i: m) [! S4 a - #define BPE_OUT(BIT) BIT_WORD_ADDR((GPIOE_BASE+0x0C),BIT)" J! ^; q6 f) Y: o* U, Q3 i
- #define BPF_OUT(BIT) BIT_WORD_ADDR((GPIOF_BASE+0x0C),BIT)8 O1 s3 @# ]* \
- #define BPG_OUT(BIT) BIT_WORD_ADDR((GPIOG_BASE+0x0C),BIT)3 X! o1 Z. _; E( W3 ]
- //GPIO_IN
: F( q8 A3 b3 C- ?' c - #define BPA_IN(BIT) BIT_WORD_ADDR((GPIOA_BASE+0x08),BIT); b1 j: d+ N! `6 T z
- #define BPB_IN(BIT) BIT_WORD_ADDR((GPIOB_BASE+0x08),BIT): N; |: N4 o, d( t" D' I
- #define BPC_IN(BIT) BIT_WORD_ADDR((GPIOC_BASE+0x08),BIT)
$ [; q3 \) M8 g; l6 G( k - #define BPD_IN(BIT) BIT_WORD_ADDR((GPIOD_BASE+0x08),BIT)* w6 \" n' t2 b
- #define BPE_IN(BIT) BIT_WORD_ADDR((GPIOE_BASE+0x08),BIT)
5 I2 n; {! F8 g6 b2 C - #define BPF_IN(BIT) BIT_WORD_ADDR((GPIOF_BASE+0x08),BIT)" T" S- n( ^, A4 B6 [
- #define BPG_IN(BIT) BIT_WORD_ADDR((GPIOG_BASE+0x08),BIT)
复制代码 + C3 m5 r0 r' p# u- N A$ F6 i1 p, A
6. 实验结果
; M( b% B3 {. L- J. { G2 J- U. q9 Q 按键按下后,LED灯亮;
* q; d1 g0 Z: S# S. g8 ^* w& J7 ]- y8 T7 k
按键松开后,LED灯灭。; A5 M9 H# D+ w. U, d& T
N4 Q* g2 h2 u/ m
0 [0 Y, o. S4 [% \# \
1 Q6 L& x6 ^3 z/ c p3 @: }1 O
5 a" B6 s5 J# \$ T |