datasheet

STM32 Contex-M的位带操作

2019-07-12来源: eefocus关键字:STM32  Contex-M  位带操作

位带操作的思想在30年前就已经有了,还是8051开创的先河。如今,Contex-M3将此能力进化,这里的位带操作位寻址区威力大幅度增强。  


有两个区中实现了位带。其中一个是 SRAM 区的最低 1MB 范围,第二个则是片内外设区的最低 1MB 范围。这两个区中的地址除了可以像普通的 RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个 32 位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。


上图为位带区和位带别名区的膨胀对应关系


在位带区中,每个比特都映射到别名地址区的一个字——这是只有 LSB 有效的字。当一

个别名地址被访问时,会先把该地址变换成位带地址。对于读操作,读取位带地址中的一个字,再把需要的位右移到 LSB,并把 LSB 返回。对于写操作,把需要写的位左移至对应的位序号处,然后执行一个原子的“读-改-写”过程。



M3的位带地址映射如下表所示

介绍完了地址映射之后,下面就是位带操作的实现方式了。

一、写数据到位带别名区



二、从位带别名区读取比特



具体的代码实现如下所示:


//位带操作,实现51类似的GPIO控制功能

//具体实现思想,参考<>第五章(87页~92页).M4同M3类似,只是寄存器地址变了.

//IO口操作宏定义

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 

#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 

#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 

//IO口地址映射

#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014

#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 

#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 

#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 

#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 

#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    

#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   

#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    

#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 

#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 

#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 

#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 

#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 

#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 

#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 

#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 

#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 

 

//IO口操作,只对单一的IO口!

//确保n的值小于16!

#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 

#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 

#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 

#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 

#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 

#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 

#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 

#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 

#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入

#define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出 

#define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输入



关键字:STM32  Contex-M  位带操作

编辑:什么鱼 引用地址:http://www.eeworld.com.cn/mcu/ic467566.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:Cortex-M3内核之位带操作
下一篇:STM32总结一 STM32三种点亮LED灯方式的不同之处

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

STM32开发笔记71: 解决FreeRTOS任务的内存分配问题

单片机型号:STM32F091RCT6在使用FreeRTOS进行程序设计时,遇到任务不能运行的问题,具体程序如下: DebugOutput("启动USB通讯线程...rnrn"); osThreadDef(usbTask, StartUsbTask, osPriorityNormal, 0, 128); usbTaskHandle = osThreadCreate(osThread(usbTask), NULL); DebugOutput("启动雷达红外通讯线程...rnrn"); osThreadDef(irdaTask, St
发表于 2019-07-13

STM32开发笔记72: 使用命名空间解决类名冲突问题

单片机型号:STM32L053R8T6在程序设计中,使用了两个类,这两个类都有引脚定义并同名,程序如下:#ifndef E32_400T20S_H_#define E32_400T20S_H_ #include "io.h"#include "mini_uart.h" #ifdef __cplusplusextern "C"{ class CM0:public CIO_Output{public: CM0(void);}; class CM1:public CIO_Output{public: CM1(void);}; 
发表于 2019-07-13

STM32开发笔记73: C++中子类调用父类同名函数的处理方法

单片机型号:STM32L053R8T61、问题父类有1方法:Enable_RS485,如下所示:class CUart{public: uint8_t u8_UartNumber; //端口号1-8 uint32_t u32_BaudRate; //波特率 uint8_t u8_Parity; //效验位 CC0 C0; //485控制引脚C0 CC1 C1; //485控制引脚C1 UART_HandleTypeDef hUART; uint8_t u8_UartReceiveBuffer[1];public: CUart(uint8_t
发表于 2019-07-13

STM32开发笔记74: STM32L0低功耗唤醒后的时钟选择

本文介绍STM32L0系列单片机低功耗唤醒后的时钟选择。参看已有的低功耗例程,发现都使能了HSI时钟,一致没有深究其中的具体原因,今天把它搞明白了,现记录如下:先看一下,使能低功耗的函数:void CTarget::EnableLowPower(void){ HAL_PWREx_EnableUltraLowPower(); HAL_PWREx_EnableFastWakeUp(); __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI); DisableAllIO();}第1句使能超低功耗,第2句使能快速唤醒,第3句选择唤醒后的主始终,第4句将所有IO引脚设置为低功耗状态
发表于 2019-07-13

STM32开发笔记75: 使用STM32CubeMX点亮一个LED

今天调试在自己的程序框架下调试RTC始终不成功,只要初始化RTC就进入死机状态。现在重温一下STM32CubeMX的使用方法,看STM32CubeMX生成的程序是否有RTC初始化不成功的问题。本日志从工程的建立讲到点亮一个LED。1、启动STM32CubeMX,我现在使用的版本是5.2.1。2、File-New Project,选择相应的芯片类型。3、双击相应的芯片类型后,进入配置界面。进行SYS配置,选中Debug Serial Wire,由于我习惯于使用FreeRTOS所以在我的项目中Timebase Source都选择定时器。4、进行RCC设置。5、时钟设置如下:6、在芯片引脚图中,将连接LED的引脚设置
发表于 2019-07-13
STM32开发笔记75: 使用STM32CubeMX点亮一个LED

STM32开发笔记76: 初始化RTC后死机的原因

项目开发中只要初始化RTC,则系统死机。其初始化步骤可参考日志:STM32开发笔记44:RTC驱动程序的移植。按照日志STM32开发笔记75: 使用STM32CubeMX点亮一个LED使用STM32CubeMX直接生成程序则运行正常。分析原因在于,少移植了2个函数:HAL_RTC_MspInit和HAL_RTC_MspDeInit。这两个函数的实现非常简单,可以靠STM32CubeMX直接生成。void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc){  __HAL_RCC_RTC_ENABLE();   HAL_NVIC_SetPriority(RTC_IRQn
发表于 2019-07-13

小广播

何立民专栏

单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved