找回密码
 注册
关于网站域名变更的通知
查看: 230|回复: 1
打印 上一主题 下一主题

STM32开发中的位运算以及位带操作

[复制链接]
  • TA的每日心情
    开心
    2022-12-9 15:13
  • 签到天数: 10 天

    [LV.3]偶尔看看II

    跳转到指定楼层
    1#
    发表于 2022-3-3 17:23 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

    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 ?

    该用户从未签到

    2#
    发表于 2022-3-3 19:08 | 只看该作者
    很详细,很适合后面的使用
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-8-11 17:26 , Processed in 0.109375 second(s), 26 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表