完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
1. 什么是位带操作?
学习 51 单片机的时候就使用过位操作,通过关键字 ***it 对单片机IO口进行位定义。但STM32没有这样的关键字,于是便要通过访问位带别名区的方式来实现。即:将每一位膨胀成一个32位字,因此SRAM的1MB位带区就膨胀为32MB的位带别名区,通过访问位带别名区来实现访问位带中每一位的目的。 比如 BSRR 寄存器有 32 个位,那么可以映射到 32 个地址上(变成32个字),当我们去访问这 32 个地址字就达到了访问 32 个比特的目的。 由图,SRAM最低1MB区域地址范围0X2000 0000-0X200F FFFF,它是SRAM的位带区。 而片内外设最低1MB区域地址范围是0X4000 0000-0X400F FFFF(这个地址范围包括APB1、APB2、AHB总线上所有外设寄存器)。 SRAM区还有32MB空间地址范围是0X2200 0000-0X23FF FFFF,它是SRAM中1MB位带区膨胀后的位带别名区。 片内外设区也还有32MB地址范围是0X4200 0000-0X43FF FFFF,它是片内外设中1MB位带区膨胀后的位带别名区。 通常我们使用位带操作都是在外设区,在外设区中应用比较多的也就是GPIO 外设,在SRAM区内很少使用位操作。 . . . 2. 位带区与位带别名区地址转换 1)外设位带别名区地址 对于片上外设位带区的某个比特, 若它所在的字节地址为 A,位序号为 n (0~8), 则该比特在别名区地址: AliasAddr = 0x4200 0000 + [ (A-0x4000 0000) * 8 + n ] * 4 0x42000000:外设位带别名区起始地址 0x40000000:外设位带区起始地址 A-0x40000000:该比特前面有多少个字节 (A-0x40000000) * 8:该比特所在字节的第0位在外设位带区的位序号 (A-0x40000000) * 8 + n:该比特在外设位带区的位序号 一个位膨胀后是4字节,所以地址*4(地址的单位是字节) 2)SRAM位带别名区地址 对于SRAM位带区的某个比特, 若它所在的字节地址为 A,位序号为 n (0~8), 则该比特在别名区地址: AliasAddr = 0x2200 0000 + [ (A-0x2000 0000) * 8 + n ] * 4 0x22000000:SRAM位带别名区起始地址 0x20000000:SRAM位带区起始地址 A-0x20000000:该比特前面有多少个字节 (A-0x20000000) * 8:该比特所在字节的第0位在SRAM位带区的位序号 (A-0x20000000) * 8 + n:该比特在SRAM位带区的位序号 一个位膨胀后是4字节,所以地址*4(地址的单位是字节) 为了操作方便,我们将这两个公式合并,通过一个宏来定义,并把位带地址和位序号作为这个宏的参数。公式如下: AliasAddr = 0x□2000000 + (A-0x□0000000) * 32 + n * 4 //求位带别名区地址 #define BITBAND(addr, bitnum) ((addr&0xF0000000)+0x2000000 + ((addr&0xFFFFF)<<5) + (bitnum<<2)) FFFFF(H)=1048575(D) > 1000000(位带区共1M字节),*32即左移5位,*4即左移2位。 (addr&0xF0000000)+0x2000000:外设(SRAM)位带别名区的首地址 (addr&0xFFFFF):外设(SRAM)位带区最高地址为0x400FFFFF(0x200FFFFF),保留低5位相当于减去0x40000000(0x20000000)。 . . . 3. 代码实现 最后通过指针形式来操作这些位带别名区地址, 实现位带区对应位的操作。 代码如下: /*位带操作,实现类似51的GPIO控制功能*/ #define BITBAND(addr, bitnum) ((addr&0xF0000000)+0x2000000+((addr&0xFFFFF)<<5)+(bitnum<<2)) //求取位带别名区地址后,把地址强制转换为unsigned long型指针 #define MEM_ADDR(addr) *((volatile unsigned long *)(addr)) //把位带别名区地址转换为指针,获取地址内数据从而操作位带区对应位 #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum)) /*IO口地址映射*/ #define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808 输入 #define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08 输入 #define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008 输入 #define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408 输入 #define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808 输入 #define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08 输入 #define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08 输入 #define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C 输出 #define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C 输出 #define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C 输出 #define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C 输出 #define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C 输出 #define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C 输出 #define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C 输出 /*IO口操作,只对单一IO口*/ #define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入 #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入 #define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入 #define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入 #define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入 #define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入 #define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入 #define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出 #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出 #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出 #define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出 #define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出 #define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出 #define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出 volatile关键字,volatile提醒编译器它后面所定义的变量随时可能改变, 因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值, 如果这个变量由别的程序更新了的话,将出现不一致的现象。 |
|
|
|
只有小组成员才能发言,加入小组>>
3314 浏览 9 评论
2995 浏览 16 评论
3494 浏览 1 评论
9059 浏览 16 评论
4088 浏览 18 评论
1178浏览 3评论
605浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
599浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2335浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1896浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 12:13 , Processed in 1.310207 second(s), Total 77, Slave 58 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号