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

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

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

    [LV.3]偶尔看看II

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

    EDA365欢迎您登录!

    您需要 登录 才可以下载或查看,没有帐号?注册

    x
    为了像51单片机一样能够对某个管脚单独操作,引入了位带操作这样的操作机制。& E% a* a7 T4 q, W4 I& E6 |" W" V
    5 f0 p. l( d0 ^6 C
        如下图,位带(Bit band)区就是就是你想单独操作的IO的区域,比如PA1、PA2。而位带别名区就是你给每一位重新起了个名字的那一片地址区域。可以看下表,M3内核存储器映射表,你能看到1M内存的BitBand区,还有与之对应的32M内存的BitBand别名区,因为你将每一位膨胀成为了一个32位的地址,所以相应的别名区的内存也会是位带区的32倍。% `$ K/ r0 f( v. |$ q
      K  K# P- t7 i* P5 ^$ D8 T( E. X
        想进行位带操作,应该先去找该位对应的别名区的地址,找到了这个地址,对这个地址进行操作,那么实际上也就是对该位进行操作了。
    ' @5 v0 U; m" C  `4 R+ v+ c; h$ ]% F7 v- A; i: y/ @  i& D
        官方给出了如下相应的计算公式:7 L9 q, X% C9 ?* C  g
    3 `  L2 o7 P* k5 V# X3 Y" q" n
    AliasAddr. F" X  H: W( X( }' v) k# L
    =0x42000000+((A‐0x40000000)*8+n)*4; p( U9 Y: T7 k9 ^, s3 ?* L
    =0x42000000+ (A‐0x40000000)*32 + n*4
      F; g5 z- i: z& p- k+ ?
    # R  s6 N; j( ?! J- D6 E4 p; H; Y    其中,AliasAddr是别名区的地址,A是GPIOA->ODR的地址,n是该端口的上的某一位。
    5 q* P4 J+ Z1 h. O/ }: C, d* C5 x) v2 b2 ]# Y% S0 g3 J
        0x42000000是位带别名区域的起始地址,A是输出数据寄存器GPIOA->ODR的地址,A的地址先减去位带区基地址,得到的是相对于位带区基地址的偏移地址,那么膨胀之后还是一个偏移地址,是相对于位带别名区基地址的偏移量,加上位带别名区域基地址,就得到了其对应的别名区地址。
    9 B* F/ p! u$ W. U4 @
    4 T& [4 O; ]$ m$ o  {' _    多数情况下,大家见到的代码,应该是以下这个样子,一共分为三步:9 ^& K6 d# r; S
    : c2 J' L  Y( x2 P9 i
    #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
    ( ]- F9 @% R/ v# g6 \8 i#define MEM_ADDR(addr)  *((volatile unsigned long  *(addr))                                                                       
    ) c& }/ ?1 K3 l$ P$ d#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))
      I  c4 N" b3 B" s, A; w) ?% p4 p/ B0 n5 u0 A9 D0 N6 z8 g, _
        第一步,就是我们上面分析的,得到位带别名区域的32位地址。5 @% q/ Z( u0 n8 h% ^5 X

      L8 ~: t' x8 S) g& T' T    第二步,就是将第一步得到的32位地址,给转换成一个指针变量,并且操作这个地址里的值,唯一的区别,就是由于安全的考虑,多加了一个volatile 这样的关键字。
    ) Z9 Q2 l" G& L, X: V/ y) c6 D+ a8 B
    举个例子1 t" G( S2 K4 _' }

    0 z0 }2 ?4 E7 I9 p! b3 c# k    如下,想直接访问0x00000001这个地址,并且给这个地址写1,该怎么做呢?2 U6 {7 {! |2 x- e9 ?

    . B# [$ B7 [# Q+ h# define ADDR 0x00000001
    8 N9 ]- T1 r: Z6 \*(int *)ADDR = 1;
    $ L" z0 u! C! [* E
    8 ^" e' e( X  B0 Z: c7 x    第三步,就是将前两部,结合在一起,根据传入的addr和bit计算得到32位的地址,然后强制类型转换,使得我们可以去操作这个地址里的值。: c: ]) s" `6 Q* @" c
    7 J; x; t6 e( A  S  o* p. V8 H
        提示:bitnum<<2相当于bitnum2乘以4,位运算相关文章:C语言操作寄存器的常见手法,实际上在计算机底层乘法也是基于位运算实现的。1 S& _  d4 |( h3 A" [

    $ s3 B/ p) |. P找国产替代芯片,上道合顺大数据
    3 B7 r: u: o: f! o" A6 j  [' T# K& V

    该用户从未签到

    2#
    发表于 2021-12-1 17:12 | 只看该作者
    A的地址先减去位带区基地址,得到的是相对于位带区基地址的偏移地址
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

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

    EDA365公众号

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

    GMT+8, 2025-7-19 10:14 , Processed in 0.125000 second(s), 26 queries , Gzip On.

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

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

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