STM32寄存器操作简单介绍

发布者:Meilin8888最新更新时间:2018-08-26 来源: eefocus关键字:STM32  寄存器操作 手机看文章 扫描二维码
随时随地手机看文章

STM32单片机可以使用库函数进行操作,再加上现在越来越强大的MDK ARM编译环境,使用库函数开发简直是不二的选择,但是工具越来越强大的同时意味着对编程人员降低了要求,在很大程度上降低了准入门槛,我们因此高兴吗?我倒是觉得这很像温水煮青蛙,所以库函数固然好用却也不应该抛弃最初的做法——寄存器操作。

先从启动文件开始介绍:这里介绍比较常见的一种启动方式(从内部的的FLASH启动,至于另外两个是否常用本人不甚了解),在启动代码了首先对栈和堆的大小进行定义,并在代码的起始处建立中断向量表,其第一个表项是栈顶(__initial_sp )地址,第二个表项是复位中断服务( Reset_Handler )入口地址。然后在复位中断服务程序中跳转C/C++标准实时库的__main函数,完成用户堆栈等的初始化后,跳转.c文件中的main函数开始执行C程序。STM32从内部FLASH启动,中断向量表起始地位为0x8000000,则栈顶地址存放于0x8000000处,而复位中断服务入口地址存放于0x8000004处。当STM32遇到复位信号后,则从0x80000004处取出复位中断服务入口地址,继而执行复位中断服务程序,然后跳转__main函数,完成这些事情在才始进入最耗费我们精力的main函数。以上内容是否重要,因项目而异,不过栈大小和堆大小可能会需要改动的,如果有机会学习cortex-A系列的SoC,比如三星的S5PV210之类一定会接触到启动文件(bootloader)的。

一个插曲,就是systeminit ,这个函数在官方提供的3.5版本的固件库的启动文件里是在main函数之前运行的,也就是说在官方给的库函数里面是有这个函数的,并且里面的内容是官方给出的,目的是设置系统的频率,一般是72M,但是我希望直接操作寄存器一定要写这个函数吗,或者一定要在main函数之前执行吗,答案是不一定,一个简单粗暴的办法就是直接写一个空的systeminit函数,写一个空的并不建议因为毕竟要调整这个SoC各个总线的频率,不如添加上。直接在启动文件里删去关于systeminit的代码也是可以的,在之后的操作里面写main函数的时候先调用systeminit函数,自己设置频率。

进入主题,说说寄存器,从官方给出的存储器映像可以看出各个外设的的基地址,这些基地址在加上相应的偏移量就是我们希望的寄存器的地址,之后修改寄存器的内容就可以,原理就是这样,关键是如何构造好的数据结构对这些寄存器进行操作。下面通过实例介绍三种方法:

实例:让GPIOB0置位,方式推挽输出,思路是1、开GPIOB的时钟 2、设置输出方式 3、端口置位


第一种:直接宏定义精确到各个具体的寄存器。GPIOB开始的地址是0X40010C00,其中端口配置低寄存器(GPIOx_CRL)偏移地址是0x00,这样(0X40010C00+0x00)就是CRL寄存器的地址,使用(long *)(0X40010C00+0x00),将这个地址强制转换成指针类型,在利用*((long *)(0X40010C00+0x00))操作(0X40010C00+0x00)地址里的内容。


#define GPIOB_CRL    (*((long *)(0X40010C00+0x00)))

#define RCC_APB2ENR  (*((long *)(0x40021000+0x18)))

#define GPIOB_ODR    (*((long *)(0X40010C00+0x0C)))

这样就可以像上面的思路操作了。


RCC_APB2ENR|=(1<<3);//开GPIOB的时钟

GPIOB_CRL=3;//设置输出方式

GPIOB_ODR=0XFFFF;//端口置位

这样操作直观,但是需要的宏太多,容易出现问题,稍不留神偏移量写错就前功尽弃了。

第二种:构造结构体,将GPIO的寄存器全部写进结构体,相比上面的方法让编译器帮我们进行计算,减少出错的可能,本来像上面那样体现不出C语言这个工具的强大。首先构造


typedef struct

{

  int CRL;

  int CRH;

  int IDR;

  int ODR;

  int BSRR;

  int BRR;

  int LCKR;

} GPIO_TypeDef;

之后


#define GPIOB ((GPIO_TypeDef*)(0X40010C00))

这样就可以用指针的方式操作GPIOB的各个寄存器了,这里的GPIO_TypeDef类型的数据结构保证操作的寄存器全是GPIO的寄存器不会越界,具体的原因是C语言的问题,这里不做过多的解释,以免跑题。下面按照最开始的操作思路进行:


RCC->APB2ENR|=(1<<3);//开GPIOB的时钟

GPIOB->CRL=3;//设置输出方式

GPIOB->ODR=0XFFFF;//端口置位

显然这种方式借助C语言这个工具和编译器帮我们解决了很多的问题。

第三种方法:查看库文件stm32f10x.h有以下的宏定义


#define PERIPH_BASE           ((uint32_t)0x40000000)

#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)

#define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)

#define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)

要知道define定义就是简单的字符串替换,替换之后的结果是


#define GPIOB   ((GPIO_TypeDef *) 0x40000000 + 0x10000 + 0x0C00)

可以看出就是第二种方法里面的


#define GPIOB ((GPIO_TypeDef*)(0X40010C00))

所以既然官方已经帮我们做好了我们为什么不用呢。所以直接包含头文件#include “stm32f10x.h” 就可以了。说到这里似乎又回到了起点,这不是还是使用了官方的库函数吗?但是这和#include 是一样的道理,只是用到了官方已经做好的寄存器名字的定义,以及一种简单的调用寄存器的方法。

使用库函数还是直接操作寄存器更好,以上的例子并没有说明问题,我们看到的只是库函数无外乎是操作寄存器,没有看到的是库函数的函数多级调用,这里不做说明。

最后一句,对于我们使用的人来说一定不要被层层的外包装所迷惑。


关键字:STM32  寄存器操作 引用地址:STM32寄存器操作简单介绍

上一篇:STM32 GPIO几个寄存器的理解
下一篇:STM32库函数和寄存器操作的思考

推荐阅读最新更新时间:2024-03-16 16:12

STM32-外部中断学习笔记
简介:STM32的EXTI控制器支持19 个外部中断/ 事件请求。每个中断设有状态位,每个中断/ 事件都有独立的触发和屏蔽设置。STM32 规定,每一组中同时只能有一个中断触发源工作,那么,最多工作的也就是16个外部中断。 中断分类 STM32的EXTI控制器支持19 个外部中断/ 事件请求。每个中断设有状态位,每个中断/ 事件都有独立的触发和屏蔽设置。 STM32的19个外部中断对应着19路中断线,分别是EXTI_Line0-EXTI_Line18: 线0~15:对应外部 IO口的输入中断。 线16:连接到 PVD 输出。 线17:连接到 RTC 闹钟事件。 线18:连接到 USB 唤醒事件。 触发方式:STM32
[单片机]
STM32-外部中断学习笔记
STM32缺陷之一:串口中断标志位缺陷
根据小道消息,M3内核是有缺陷的,但是这种缺陷不会在大会上想广大群众透露的。我用的是M3内核的stm32,我来寻找一些缺陷。 今天找到的是串口中断标志位缺陷。 我是做四轴飞行器的,没有买遥控器,而是用的无线串口,一开始的想法是stm32接收到串口来的数据后,进入串口中断服务函数,再比对发来的数据进行接下来的动作。 一开始的程序是没有问题的,简单点吧,串口接收到数据后,让LED转换状态。 void USART2_IRQHandler(void) { if(USART_GetITStatus(USART2, USART_IT_RXNE) ==SET) { USART_ClearFlag (USART2
[单片机]
STM32电机矢量控制】记录13——EXTI外部中断
STM32的EXTI控制器支持19 个外部中断/ 事件请求。每个中断设有状态位,每个中断/ 事件都有独立的触发和屏蔽设置。 STM32的19个外部中断对应着19路中断线,分别是EXTI_Line0-EXTI_Line18: 线0~15:对应外部 IO口的输入中断。 线16:连接到 PVD 输出。 线17:连接到 RTC 闹钟事件。 线18:连接到 USB 唤醒事件。 触发方式:STM32 的外部中断是通过边沿来触发的,不支持电平触发。 外部中断分组:STM32 的每一个GPIO都能配置成一个外部中断触发源,STM32 通过根据引脚的序号不同将众多中断触发源分成不同的组,比如:PA0,PB0,PC0,PD0,PE0,PF0,P
[单片机]
【<font color='red'>STM32</font>电机矢量控制】记录13——EXTI外部中断
STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试
这篇文章翻译自 ARM Keil Application Note 230 (1.2版)的前半部分。其中包括 STM32F4 处理器在 Keil MDK 中进行断点调试、变量实时观察,及逻辑分析仪参与硬件调试的实验。 原文使用的是 STM32F4-Discovery 开发板,我这里都改用 NUCLEO-F401RE 实现了。Discovery 板卡在新版本的 Pack Installer 中已没有 Blinky 例程支持,可以用 CMSIS-RTOS Blinky 来做,变量定义的位置等会有变化。 1) Keil 评估软件:MDK 4.7x 和 MDK 5 MDK 5 以 Software Pack 的形式分发特定于处理器的
[单片机]
<font color='red'>STM32</font> 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试
STM32局部变量的数组最大能到多少?
当在一个函数中声明一个较大的局部数组变量时,程序可以编译通过,但运行时,老是进入hardfaulthandler,导致出现改问题的原因可能是栈溢出。因为局部变量是存放在栈区的,而全局变量在全局区(静态区),如果栈区较小,会产生溢出。 解决这种问题的方法: 方法1:启动文件里面对栈的大小有固定的值。函数里面的数组是在调用该函数的时候,才给你分配空间。将启动文件下的堆栈改大 Stack_Size EQU 0x00000400 。 Stack Size,一般小工程0X400足够,大工程才设置0X1000就够用,所以默认无需设置太大。 方法2:用静态数组代替普通局部数组。 方法3:数组过大,栈溢出了,有可能覆盖了其他全局变量的值
[单片机]
JLINK给STM32下载的两种模式--jtag & sw连线及配置
jtag线就不说了,将jlink的Vref、GND、TMS、TCK分别接至SW接口。对于STM32F103RCT6来说:TMS--PA12,TCK--PA14. 关于KEIL MDK中的设置如下图所示就可以了,然后就可以像下载JTAG那个下载sw了:
[单片机]
STM32学习005_端口复用与重映射
一、使用复用功能(AF)时,要对端口位配置寄存器进行编程。 1)对于复用的输入功能,配置必须为上拉/下拉或者浮空; 2)对于复用输出功能,配置必须为复用功能输出模式(推挽,开漏)。 对于双向复用功能,必须配置为复用功能输出模式(推挽或者开漏),此时输入驱动器配置为浮空输入模式。 如果将一端口配置成复用输出功能,会将引脚和输入寄存器断开,并和片上外设的输出信号连接, 如果软件将一GPIO 口配置为复用输出功能,但外设没有被激活,它的输出将不确定。 要正常使用GPIO 复用功能,分三步来配置: 第一步,位寄存器配置; 第二步,开启对应的外设时钟; 第三步,激活该端口。 二、端口重映射 优点:优化电路设计;扩展功能,减少外设芯片资源;
[单片机]
如何创建 USB-PD 接收设备(中)
2.7 [可选] 配置 Tracer 进行调试↑ 2.7.1配置LPUART ↑ 在STM32G0 Nucleo-64板子上,连接ST-LINK的Virtual COM口是LPUART1。 必须更改 LPUART1 使用的默认 STM32CubeMX 引脚以匹配 STM32G0 Nucleo-64 硬件: TX 的 PA2 用于接收的 PA3。 在Connectivity部分,在 Asynchronous 模式下启用LPUART1,波特率为921600 bauds。其余保持默认。 在引脚布局视图中,左键单击 PA2 和 PA3 以将它们重新映射到LPUART1_TX和LPUART1_RX。 在DMA 配置选项卡下,添加
[单片机]
如何创建 USB-PD 接收设备(中)
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

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

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved