datasheet

STM32总结一 STM32三种点亮LED灯方式的不同之处

2019-07-12来源: eefocus关键字:STM32  点亮LED灯  寄存器  模板  位带操作

STM32点亮LED灯有很多种方法。


第一种是操作寄存器来点亮LED灯,(以GPIOC的第一个LED为例)操作的方法是首先在中文手册,首先要声明的是,手册里面看到的地址,都是字节,表示第多少多少个字节,然后这个数字对应一个字节位,所以每一个32位的寄存器占四个字节,找到block2(这个是外设区,所有的外设地址都在这个区)的基地址,然后加上第一段偏移地址,就越过APB1总线的内存区,到达了APB2总线这个区的基地址。然后再加上相对于APB2的偏移地址就可以定位出某个特定外设的基地址,这里所指的是GPIOC端口的基地址,然后再在这个端口外设基地址的基础上,加上相应的偏移地址,就可以定义出这个端口的寄存器地址,这些寄存器是紧紧的挨着的,一个接一个的,每个寄存器占四个字节。然后就参考手册的寄存器介绍图来编程,从而操作寄存器相应的位来实现引脚输入输出的不同,也就是配置寄存器实现相关的功能。(要注意的是:其实这里我们所定义的宏(也就是定义的地址)其实就是相关的寄存器的基地址,这个寄存器的全程还包括这个基地址以后的四个字节,其实这里定义的这个宏代表的就是这个寄存器,虽然它只用了每个寄存器的基地址来表示),其实都是一样的,每个数字对应着一个位。要让GPIOC的引脚0输出低电平的意思就是配置BSRR寄存器的BS0位为1。当然在配置这个之前,我们还需要了解GPIOC的基本结构(其实每个GPIO的结构都是一样的,这里用GPIOC引脚来举例子)和它的八种工作模式。这里需要着重说一下的是,除了模拟输入和模拟输出这两种工作模式用的是模拟量以外,其他的工作模式,如果是输入则从引脚处进去模拟量通过施密特触发器以后变成数字0和1,如果是输出则通过一个模拟量输出然后经过MOS管的处理变成了输出量为高电平和低电平,这里本质上就是把控制引脚输出高低电平的寄存器位设置为0或者1,然后会让相应的引脚输出高低电平。当然在配置寄存器让引脚输出高低电平之前,还需要配置其他的寄存器,让这个引脚位置有相应的工作模式和工作速度。这样就实现了LED点亮(本质上就是引脚位置输出了一个低电平接在LED灯的一端,LED灯的另一端接了一个VDD正电源,然后灯就亮了)。所有的点亮LED灯的操作说白了都是这个最基本原理,配置寄存器,输出低电平,点亮灯。在GPIO每个端口的某个引脚输出电平时,其实可以在输入端测出到底输出的是高电平还是低电平(测的原理就和输入原理一样)。


第二种方式用的是固件库模板点亮LED。这种方法的本质和第一种是一样的都是操作寄存器的位从而实现对应引脚输出不同的电平。使用这种方法首先需要创建一个模板,创建方式可以参考中文参考手册和开发攻略。然后再自己新定义一个函数,将用到的函数从已经定义好的库文件中调用出来即可。再在main.c函数中调用新定义的函数初始化寄存器即可。虽然与第一种方式不同,但实际上达到的效果是一样的(也就是说最后实现的配置结构是一样的,只是配置的方式并不相同)。


第三种方法是位带操作。


STM32所基于的ARM Cortex-M3内核引入了一种新颖的“位带”技术(英文称为Bit

Band),这种“位带”技术将部分其片内的部分称为“位带区”的存储区域和另外一部分称为“位带别名区”的区域映射起来。一个比较完整的描述是:Cortex-M3的内部存储空间有2个“位带区”,分别称为“SRAM位带区”和“外设存储位带区”,各自位于SRAM区和外设存储区各自最低的1MBit空间;并有对应的2个“位带别名区”,分别称为“SRAM位带别名区”和“外设存储位带别名区”,每个别名区大小为32MBit。“位带”技术将两个“位带区”的每一位分别映射带对应的“位带别名区”的一个“字”(即32位)的最低位上。图1展示了这种关系:


图1


图1中,左边的0x40000000表示“外设存储位带区”的起始地址,而右边的0x42000000则表示“外设存储位带别名区”的存储地址,0th Bit、1th Bit等表示从地址0x40000000依次往后的第0位,第1位等。右边的0x42000000表示STM32内部的“外设存储位带别名区”起始地址,而下面的0x42000000 – 0x420000010、0x42000010 – 0x420000020等则表示从地址0x42000000依次往后的第1个、第二个“字”空间。在此要注意到的是,STM32作为一款32位控制器,其数据总线当然是32位的,但其内部存储空间不仅支持32位存取,同时也支持8位(字节)、16位(半字)存取方式,因此其内部存储空间是按照最小存取长度(8位)来对齐的,以图1中的0x42000000 – 0x420000010为例,其存储空间的排列情况如下图2所示。假设想这段空间内写入数据0x12345678,则实际内容(假设是小端存储格式)如图3所示。


图2  图3


8位长度的对齐方式决定了用户通过应用程序操作存储空间的最小长度为8位,亦即1个字节。因此如果要单独对某一“位”进行操作,则必须使用上文中所讲述的办法。

但通过这种“位带”技术进行存储空间的映射后,可以很轻易快捷的实现位操作。当对“位带别名区”的某一个“字”空间的最低位进行清除操作时,则对应的“位带区”所对应的“位”即会被清除,反之当对“位带别名区”的某一个“字”空间的最低位进行置位操作时,,则对应的“位带区”所对应的“位”也会被置位。这样一来,前文所讲述的“读出——修改——写入”就变成了只有“写入”的过程,这是一种非常典型的空间换时间的做法。也许有读者会疑问,这样岂不是损失掉了2个32MBit的存储空间?答案是这部分存储空间是通过映射技术“虚拟”出来的,STM32片内的这部分地址空间并没有物理存储介质存在。


下面通过一个简单的例子讲述如何实现STM32微控制器平台上的“位带”技术实现一个简单的点亮发光二极管的操作。其中发光二极管使用STM32的PA4引脚的输出高电平点亮,则只要在PA4引脚输出一个高电平,即可点亮该发光二极管。


通过查阅STM32的开发手册可以知道,要在PA4引脚输出高电平,则只需要在初始化完毕GPIOA设备之后对GPIOA的ODR寄存器的第4位写入一个“1”即可。这个目的很简单,重点是如何计算ODR寄存器的第4位在“位带别名区”中所对应的“字”空间地址。获取该地址的过程如下图4所示。


图4


事实上有了前文的描述,相信图4是比较容易理解的。图中自上往下最终推算出了GPIOA的ODR各个位的“位带别名区”的地址,可以看到ODR寄存器的第4位所对应的“字”空间地址为0x42210190。从STM32的开发手册上也可以获取“位带别名区”的字空间所对应的“位”:

bit_word_addr = bit_band_base + (byte_offset×32) + (bit_number×4)

上述公式中,bit_word_addr表示“位带别名区”字空间,bit_band_base表示对应的“位带区别名区”起始地址,byte_offset表示“位”在“位带区”中的字节偏移地址,bit_number则表示“位”在对应“位带区”字节中的位置。


以对GPIOA的ODR寄存器的第4位写入一个“1”为例,首先要找到ODR寄存器的第4位的“位带区”起始地址,字节偏移地址和在字节中的位置。其中“位带区”起始地址已知为0x42000000,而字节偏移地址由在图4找出为0x0001080C(注意是此处偏移地址,不是图中的绝对地址),同时位置为第4位,因此可以套用上述公式计算对应的“字空间”

bit_word_addr = 0x42000000 + (0x0001080C × 32) + (4 × 4) = 0x42210190

可知可图中推算的结果一致。因此,只要向地址为0x42210190的空间写入“1”即可点亮发光二极管。


关键字:STM32  点亮LED灯  寄存器  模板  位带操作

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

上一篇:STM32 Contex-M的位带操作
下一篇:STM32F103C8T6最小系统地的构建(3)_时钟源电路-晶振

关注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