STM32的寄存器操作

STM32最基本的,最底层的,就是对寄存器的直接操作。通过操作特定寄存器的特定位,来实现相对应的功能。

本文通过GPIO点亮LED来演示。

GPIO

查阅数据手册,了解相关内容。

启动代码

旧版的keil,在建立工程时会提示自动导入启动代码。

但是新版在建立工程后,会弹出运行时环境配置。选择相应的启动代码。

为了选择这个startup,需要先选择CMSIS里的CORE内核模块。

之后生成了3个启动代码。

旧版只有1个启动代码startup_stm32f10x_hd.s,没有多余的文件,咋回事?

在回答这个问题之前,我们来了解下STM32的启动文件。

在使用 STM32CubeMX 开发 STM32时,往往会看到一个.s 的文件,这个文件就是 STM32 的启动文件,里面包含多个功能,例如堆栈大小配置、STM32 复位后初始化和建立中断服务入口地址等功能。

在支持包中,可以找到相应的启动文件。

启动代码在这里:

F:\czpBuiltin\keil5 mdk\Arm\Packs\Keil\STM32F1xx_DFP\2.4.0\Device\Source\ARM

这里有很多种启动代码,到底应该怎么选呢?

startup_stm32f10x_cl.s 互联型的STM32F105xx,STM32F107xx
startup_stm32f10x_hd.s 大容量的STM32F101xx,STM32F102xx,STM32F103xx
startup_stm32f10x_hd_vl.s 超值型大容量的STM32F100xx
startup_stm32f10x_ld.s 小容量的STM32F101xx,STM32F102xx,STM32F103xx
startup_stm32f10x_ld_vl.s 超值型小容量的STM32F100xx
startup_stm32f10x_md.s 中容量的STM32F101xx,STM32F102xx,STM32F103xx
startup_stm32f10x_md_vl.s 超值型中容量的STM32F100xx
startup_stm32f10x_xl.s

超大容量FLASH在512K到1024K字节的STM32F101xx,STM32F102xx,STM32F103xx

ROM容量为:

16~32K就是LD

64K~128K的就是MD

256~512K的就是HD

我这里用的是F103C8,64K的flash,所以用的是md,startup_stm32f10x_md.s。

现尝试将这个启动文件单独复制到工程中。

代码实现

编译后有一个error:

.\Objects\regled.axf: Error: L6218E: Undefined symbol SystemInit (referred from startup_stm32f10x_md.o). 

没定义的符号SystemInit,也就是说,该启动文件没有初始化的实现。其中关键的是没有开启时钟,所以无法工作。

来看看这个符号在哪?启动文件中有这一段:

这是复位之后的处理代码,先系统初始化,然后再跳转到main函数中执行。

两种解决方法,要么把带有SystemInit的文件导入进来,要么自己定义一个,可以不写实现,保持为空,也可以直接在这里面开启时钟。


/*************************************************************************************************
 *PB8-PB15,这8个端口依次控制着8颗LED的正极
 *
 *GPIOB的起始地址为:0x40010C00
 *
 *1、
 *GPIOB_CRH进行模式和输出配置,8个端口均为推挽输出,所以该寄存机的值应为0x11111111
 *该寄存器的偏移地址为04h,所以GPIOB_CRH寄存器的地址为:0x40010C04
 *
 *2、
 *我们先点亮第这8颗LED,所以接下来要先配置输出寄存器GPIOB_ODR,偏移量0x0C,所以地址为:0x40010C08
 *要赋予的值为:Ox0000FF00
 *
 *************************************************************************************************/

void SystemInit(void);

int main(void)
{
    unsigned int *ledCfg = (unsigned int *)0x40010C04;
    unsigned int *ledData = (unsigned int *)0x40010C0C;
    
    *ledCfg = 0x33333333;
    *ledData = 0x00005500;
    
    while(1);
}

void SystemInit()
{
    //开启GPIOB时钟,置RCC_APB2ENR寄存器的第3位为1,赋值0x00000008
    //RCC基地址为0x40021000,该寄存器的偏移量为18H,则地址为:0x40021018
    unsigned int *RCC_APB2ENR = (unsigned int *)0x40021018;
    
    *RCC_APB2ENR = 0x00000008;
}

注意,因为手册上没有写明GPIOB_ODR的偏移量,所以,按照我的想法,它的地址是按照4个字节来递增的,上一个偏移量是08H,下一个偏移量是10H,所以,我在想,08和10之间不可能隔了4个数呀?咋回事?难道是和上一个寄存器共用一个地址?结果,代码就错了。

这里犯了思维定势的错误。08和10都是16进制的数,那么08H和10H之间不就正好差了8个字节吗?08H和10H之间的不就是0CH吗?我还在疑惑,C换成十进制是12,怎么可能在10H之前呢?所以,千万别搞混了十进制和十六进制。

另外,还可以直接通过复位或者置位寄存器来控制电平高低。操作方法一样,不赘述。

再补充一点,以上代码可以通过宏定义(比如重复格式代码宏定义,基地址宏定义,基地址+偏移量方式宏定义等等)、位操作或者拆分头文件等方式来优化,不赘述。

归根结底

通过操作寄存器来实现对应的功能,是最底层的方式,需要我们通过查阅数据手册,找到对应寄存器的地址,并且了解对应寄存器相应位所表示的含义,从而实现相应功能。

要学会通过串口来调试程序。 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32中,寄存器操作是通过直接访问寄存器来对硬件进行配置和控制的一种方式。这种操作方式可以使用寄存器地址和指针来实现。STM32系列芯片提供了一个头文件stm32f10x.h,其中包含了寄存器与地址的映射关系。通过引用这个头文件,我们可以使用寄存器的具体名称而不是地址来进行操作。 要找到所需的寄存器,我们可以使用C语言中的指针和取地址操作符(&)。类似于使用scanf语句从控制台输入一个变量时需要使用&符号来获取变量的地址一样,不同的寄存器有不同的地址。因此,要找到对应的寄存器,我们只需找到对应的地址即可[2]。 在学习STM32的过程中,大部分人最初可能会使用标准库版本,对于寄存器操作可能不太熟悉。寄存器是CPU内部用来存放数据的小型存储区域,用于临时存放参与运算的数据和运算结果。 综上所述,STM32寄存器操作是通过直接访问寄存器来配置和控制硬件,可以使用寄存器地址和指针来实现。为方便使用,STM32提供了一个头文件stm32f10x.h,其中包含了寄存器与地址的映射关系。使用指针和取地址操作符(&),我们可以找到所需寄存器的地址。寄存器是CPU内部用于存放数据的小型存储区域,用于临时存放参与运算的数据和运算结果。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [STM32寄存器的简介、地址查找,与直接操作寄存器](https://blog.csdn.net/geek_monkey/article/details/86291377)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [关于STM32的寄存器操作学习](https://blog.csdn.net/lemou1211/article/details/129170414)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值