TA的每日心情 | 开心 2022-12-9 15:13 |
---|
签到天数: 10 天 [LV.3]偶尔看看II
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本帖最后由 Heaven_1 于 2022-3-3 18:59 编辑
9 i& _( [2 N, ]' q7 l; Y H1 ]0 O* O7 V
为了像51单片机一样能够对某个管脚单独操作,引入了位带操作这样的操作机制。1 R0 {* ]7 V! f, q* f, o
* ^9 J+ t/ T; Q- ^+ Z0 @如下图,位带(Bit band)区就是就是你想单独操作的IO的区域,比如PA1、PA2。而位带别名区就是你给每一位重新起了个名字的那一片地址区域。可以看下表,M3内核存储器映射表,你能看到1M内存的BitBand区,还有与之对应的32M内存的BitBand别名区,因为你将每一位膨胀成为了一个32位的地址,所以相应的别名区的内存也会是位带区的32倍。
4 L' f5 v# E! y8 Q- A% Z) E
, H4 j f8 I r6 G0 b1 Q& u- v
6 \' g0 h4 }$ N& T+ P& N, v" }/ @
) x) t+ M; p$ F: {7 }
想进行位带操作,应该先去找该位对应的别名区的地址,找到了这个地址,对这个地址进行操作,那么实际上也就是对该位进行操作了。- w+ _& ^3 o' k
+ G6 v; J) ?+ O1 k& p# P X
官方给出了如下相应的计算公式:$ n, {1 g+ c% v4 l5 L% H3 }
4 [$ w% P) F+ e! H6 R' F/ y! [AliasAddr, {+ y8 t8 z/ V% M% _; R
: S+ H, P6 P7 V=0x42000000+((A‐0x40000000)*8+n)*4
& k z3 P4 \$ w3 H) }! Y2 H2 {
" ]1 P! c, f8 @% n5 s5 N& N' \=0x42000000+ (A‐0x40000000)*32 + n*49 C$ R- f! Q9 D! i8 e% Y+ n
) X1 u) p9 P2 `- J* N3 G其中,AliasAddr是别名区的地址,A是GPIOA->ODR的地址,n是该端口的上的某一位。+ Y" r+ ^7 `* A; @* ?
8 M8 t% E& r( J0x42000000是位带别名区域的起始地址,A是输出数据寄存器GPIOA->ODR的地址,A的地址先减去位带区基地址,得到的是相对于位带区基地址的偏移地址,那么膨胀之后还是一个偏移地址,是相对于位带别名区基地址的偏移量,加上位带别名区域基地址,就得到了其对应的别名区地址。
" f5 y, [# m v" a+ Q
) u& I- H; V x1 C9 V1 Y: Y多数情况下,大家见到的代码,应该是以下这个样子,一共分为三步:
8 m& k. w7 e, R+ ?
3 ?3 [5 I' x4 K#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
6 x2 n& n1 k* X5 o6 W3 m, {7 [ n
. s5 u8 B P- q/ t#define MEM_ADDR(addr) *((volatile unsigned long *(addr))$ R* ^; [" i# d& v2 l; t- h% G3 s; r6 L
1 y1 K! V& {* s7 U
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
7 w) `: l# T$ v' d6 V T
, M- S3 j6 G @4 G3 J) M& W& d! P第一步,就是我们上面分析的,得到位带别名区域的32位地址。
# ]0 W, n$ Y6 t: w/ t9 T5 }
: d. X' x! ?* K! S第二步,就是将第一步得到的32位地址,给转换成一个指针变量,并且操作这个地址里的值,唯一的区别,就是由于安全的考虑,多加了一个volatile 这样的关键字。/ y4 F" {6 ]" k
q- T8 p4 }# _ h
举个例子
I! F( s. Q% m! Y" o& l) @- x+ D9 ^- K, m \( I
如下,想直接访问0x00000001这个地址,并且给这个地址写1,该怎么做呢?1 N& z. [* L E2 e3 d9 z. }
' `# w1 Y r+ D V0 v2 q
# define ADDR 0x00000001
5 I3 L9 m3 M- o* p. V, ^; V
6 q4 G- g3 d8 u7 g% X' E6 M*(int *)ADDR = 1;& D: H, n' V f) ~$ I& N
- f# e' c' ~7 Y- |6 R第三步,就是将前两部,结合在一起,根据传入的addr和bit计算得到32位的地址,然后强制类型转换,使得我们可以去操作这个地址里的值。2 R% G5 v" Z5 k* Z& S7 {
. z8 T$ ?) q$ J/ j- B* ~
提示:bitnum<<2相当于bitnum2乘以4,位运算相关文章:C语言操作寄存器的常见手法,实际上在计算机底层乘法也是基于位运算实现的。1 f! G5 J) a; \& m1 L8 ?
! s4 o ^9 ?/ Q i9 t
% s# M+ I1 ~$ t" l) j3 S
+ K4 t0 W1 n3 X! ^" a& E5 F6 s7 m) Q, e6 E8 D x1 W" i2 ?
|
|