当前位置: 首页 > news >正文

STM32F103C8T6开发板入门学习——寄存器和库函数介绍

学习目标:STM32F103C8T6开发板入门学习——寄存器和库函数介绍


学习内容:

1. 寄存器介绍

1.1 存储器映射

存储器本身无固有地址,是具有特定功能的内存单元。它的地址是由芯片厂商或用户分配,给存储器分配地址的过程就叫做存储区映射。给内存单元分配地址之后,就可以通过指针去操作内存地址。

1.2 存储器映射表

STM32作为32位单片机,地址范围为2³²(即4GB)。为降低相同应用场景下的软件复杂度,其存储映射按Cortex-M4处理器规则预先定义:

  • 部分地址空间由Arm Cortex-M4的系统外设占用,且不可更改;
  • 其余地址空间可由芯片供应商定义使用。
1.3 什么是寄存器

寄存器是具有特定功能的内存单元,通过操作这些单元可驱动外设工作。按功能可分为:

  • 指令寄存器、地址寄存器、数据寄存器;
  • 处理器可通过相互独立的总线读取指令、加载/存储数据。
1.4 寄存器映射

程序存储器、数据存储器、寄存器和I/O端口位于同一4GB线性地址空间内:

  • 每个寄存器对应不同功能,操作相应寄存器可配置对应功能;
  • 控制外设时,可通过起始地址以C语言指针方式访问内存单元;
  • 给已分配地址、有特定功能的内存单元取别名的过程,称为寄存器映射,该别名即寄存器。
1.5 寄存器重映射

给寄存器再次分配地址的过程称为寄存器重映射。

1.6 总线基地址

片上外设区域分为三条总线,按外设速度不同挂载相应外设:

  • AHB总线:最高时钟可达72MHz;
  • APB1总线:最高时钟可达36MHz;
  • APB2总线:最高时钟可达72MHz。

根据外设速度的不同,不同的总线挂载着不同的外设。总线的最低地址我们称为该总线的基地址,总线基地址也是挂载在该总线上的首个外设的地址。
请添加图片描述

1.7 外设基地址

每条总线上挂载多个外设,每个外设均有自己的地址范围。

请添加图片描述

1.8 外设寄存器地址

在外设的地址范围内,分布着该外设的多个寄存器。以GPIO外设为例:

  • GPIO外设地址范围内有多个寄存器,每个均有特定功能,通过操作对应寄存器可配置GPIO功能;
  • 每个寄存器为32位,占4个字节。

请添加图片描述

1.9 如何操作寄存器

以“让GPIOA端口的16个引脚都置1”为例,操作步骤如下:

  1. 确定目标寄存器:需配置端口输出寄存器GPIOx_ODR;
  2. 计算寄存器地址
    • 由中文参考手册第115页可知,GPIOx_ODR寄存器的地址偏移量为0x0C;
    • GPIOA端口的基地址为0x40010800;
    • 因此,GPIOx_ODR寄存器的地址为:0x40010800 + 0x0C = 0x4001080C。
      请添加图片描述

通过上图可以了解到要想使能所有引脚配置为1,只需要将ODRy(y=0…15)对应的位置1即可。也就是配置GPIOA_ODR寄存器的高16位为0,低16位为1,换成十六进制就是0x0000FFFF。

1.通过绝对地址访问内存单元
// GPIOA 端口的16个引脚全部输出高电平
*(unsigned int*)(0x4001080C) = 0xFFFF;

说明

  • (unsigned int*):将立即数0x4001080C强制转换为无符号整型指针,告诉编译器这是一个内存地址;
  • *:对该地址进行解引用,访问地址对应的内存空间;
  • 整体含义:向0x4001080C(GPIOA_ODR寄存器)对应的内存空间写入0xFFFF,实现GPIOA所有16个引脚输出高电平(低16位置1,高16位为0)。
2. 通过别名访问内存单元

为简化操作并增强可读性,可给寄存器地址定义别名:

方式一:定义地址指针

// 定义 GPIOA_ODR 地址指针
#define GPIOA_ODR (unsigned int*)(0x4001080C)// GPIOA 端口的16个引脚全部输出高电平
*GPIOA_ODR = 0xFFFF;

方式二:直接定义解引用的地址(更常用)

// 定义 GPIOA_ODR 并直接解引用
#define GPIOA_ODR (*(unsigned int*)(0x4001080C))// GPIOA 端口的16个引脚全部输出高电平
GPIOA_ODR = 0xFFFF;
  • 优势:通过GPIOA_ODR这样的别名,可直观理解操作的是GPIOA的输出数据寄存器,无需记忆复杂的十六进制地址,提升代码可读性和可维护性。

2. 库函数介绍

2.1 为什么要使用库函数

从上一节可知,通过寄存器驱动外设虽可行,但STM32寄存器数量极多:

  • 仅定义寄存器就需耗费大量时间,还需逐一查找其功能、地址并配置对应值,在开发难度和时间成本上均不划算。

库函数的出现正是为解决这一问题,其优势在于:

  • 由STM32官方开发,可直接移植到工程中使用,大幅提升开发效率;
  • 无需深入了解硬件底层机制,只需根据需求查找对应函数并调用,降低了开发门槛。
2.2 库函数简单介绍

在创建的工程模板中,包含STM32F1x的标准外设库,可通过打开stm32f10x_gpio.hstm32f10x_gpio.c等文件查看具体实现。

本质上,库函数是在寄存器操作的基础上进行了封装:

  • 底层仍通过操作寄存器实现功能,但上层提供了更简洁的函数接口,使开发操作更简单。

3. 寄存器和库函数的区别

寄存器和库函数最终均通过对地址操作实现功能,但二者存在明显差异,适用场景也不同:

  • 原理与直观性:寄存器操作更易理解底层原理,过程直观;库函数则屏蔽了底层细节,直接面向应用功能。
  • 代码量与冗余:库函数代码量相对更大,因函数需考虑多种使用场景,可能存在代码冗余;寄存器操作代码更精简。
  • 开发难度与效率:库函数使用简单、易上手,可快速开发应用,能显著提高开发效率;寄存器操作需熟悉硬件细节,开发门槛更高。
  • 资源占用与速度:寄存器操作占用内存少、执行速度快,在资源有限(如内存紧张)或对执行速度有高要求的场景下更具优势。

学习时间:8月25日

1. 寄存器介绍

1.1 存储器映射

原文核心:存储器本身无固有地址,分配地址的过程称为存储区映射,映射后可通过指针操作内存单元。

个人理解:存储器就像一堆无编号的储物箱,“存储器映射”就是给每个箱子贴上限号(地址)。有了编号后,CPU才能通过“地址指针”准确找到并操作对应的存储单元。这是硬件与软件交互的基础——没有地址映射,软件就无法“定位”硬件资源。

1.2 存储器映射表

原文核心:STM32作为32位单片机,地址范围为4GB,部分地址由Cortex-M4内核占用(不可改),其余由芯片厂商定义。

个人理解:4GB地址空间是32位处理器的“理论上限”,就像一个巨大的“地址版图”。其中,Cortex-M4内核预留了部分区域(如系统外设),相当于“国家划定的保护区”,不可占用;剩下的区域由STM32厂商分配给片上外设(如GPIO、UART等),形成了固定的“地址规划”。这种标准化的映射表让不同开发者能基于同一套地址规则操作硬件,降低了兼容性成本。

1.3 什么是寄存器

原文核心:寄存器是具有特定功能的内存单元,按功能分为指令、地址、数据寄存器,处理器通过独立总线访问。

个人理解:寄存器是硬件的“控制面板”。比如,指令寄存器存放当前要执行的指令,地址寄存器存放要访问的内存地址,数据寄存器临时存储运算数据。独立总线设计(如指令总线、数据总线)就像“专用通道”,避免了指令读取和数据传输的冲突,提高了CPU效率。简单说,寄存器是CPU与外设“对话”的直接窗口——操作寄存器就是在“告诉”硬件该做什么。

1.4 寄存器映射

原文核心:给已分配地址、有特定功能的内存单元取别名的过程,称为寄存器映射,别名即寄存器。

个人理解:假设某块内存单元的地址是0x4001080C,其功能是控制GPIOA的输出,我们给它起个名字“GPIOA_ODR”,这个过程就是寄存器映射。它的本质是“地址→功能别名”的映射,让开发者不用死记硬背冗长的十六进制地址,而是通过“GPIOA_ODR”这样直观的名字操作硬件,大幅降低了代码的理解难度。

1.6 总线基地址

原文核心:片上外设分为AHB(72MHz)、APB1(36MHz)、APB2(72MHz)三条总线,总线基地址是总线上首个外设的地址。

个人理解:总线就像“高速公路”,外设是“车辆”。AHB和APB2是“快车道”(72MHz),适合高速外设(如GPIO、SPI);APB1是“慢车道”(36MHz),适合低速外设(如I2C、UART)。总线基地址是“高速路的起点”,比如AHB总线基地址是0x40010000,总线上的所有外设地址都从这个起点开始“编号”,方便按总线归类管理外设。

1.7 外设基地址

原文核心:每条总线上的外设都有自己的地址范围。

个人理解:如果总线是“高速公路”,外设就是路上的“服务区”,每个服务区有自己的“管辖范围”(地址范围)。比如,GPIOA挂在APB2总线上,其基地址是0x40010800,地址范围从0x40010800到下一个外设的基地址前,这样CPU就能通过地址范围准确区分不同外设(如GPIOA和GPIOB)。

1.8 外设寄存器地址

原文核心:外设地址范围内有多个寄存器,每个32位(4字节),对应特定功能(以GPIO为例)。

个人理解:一个外设(如GPIOA)就像一个“工具箱”,里面的每个“工具”(寄存器)对应不同功能:比如“GPIOA_CRL”控制低8位引脚模式,“GPIOA_ODR”控制输出电平。每个寄存器占4字节(32位),是因为STM32是32位处理器,一次可处理32位数据,这种设计能高效读写寄存器。

1.9 如何操作寄存器(以GPIOA引脚置1为例)

原文核心:步骤为“确定目标寄存器→计算地址→写入值”,并给出了具体示例。

个人理解:操作寄存器的本质是“地址+值”的精准控制。比如要让GPIOA所有引脚输出高电平,需找到“输出数据寄存器(ODR)”,计算其地址(GPIOA基地址+偏移量0x0C=0x4001080C),再写入0xFFFF(低16位置1)。这个过程像“按地址找到开关,再拨动开关”,需要对硬件地址和寄存器功能有清晰了解。

1. 通过绝对地址访问内存单元

原文示例:*(unsigned int*)(0x4001080C) = 0xFFFF;

个人理解:这种方式直接通过地址操作,优点是“直达底层”,缺点是可读性差——如果不查手册,没人知道0x4001080C是什么。适合对硬件极度熟悉的场景,或调试时快速验证功能。

2. 通过别名访问内存单元

原文给出两种方式:定义地址指针(#define GPIOA_ODR (unsigned int*)(0x4001080C))或直接定义解引用地址(#define GPIOA_ODR (*(unsigned int*)(0x4001080C)))。

个人理解:这是实际开发中更推荐的方式。通过“GPIOA_ODR”这样的别名,代码可读性大幅提升,且修改时只需改宏定义,无需逐个修改地址。就像用“家门钥匙”代替“钥匙的物理编号”,更符合人类的记忆习惯。

2. 库函数介绍

2.1 为什么要使用库函数

原文核心:寄存器数量多,手动定义和配置耗时,库函数由官方开发,可直接移植,降低门槛、提高效率。

个人理解:STM32的外设和寄存器极其庞大(仅GPIO就有近10个寄存器,全芯片有上百个外设),如果每个寄存器都手动定义地址、查手册配置值,开发效率会极低。库函数就像“封装好的快捷指令”,比如要配置GPIO输出,直接调用GPIO_Init()即可,无需关心底层寄存器的地址和具体值,适合快速开发。

2.2 库函数简单介绍

原文核心:库函数基于寄存器操作封装,在stm32f10x_gpio.h等文件中实现,提供简洁接口。

个人理解:库函数不是“魔法”,其底层依然是操作寄存器。比如GPIO_SetBits(GPIOA, GPIO_Pin_All)函数,内部其实是对GPIOA_ODR寄存器写入0xFFFF。它的价值在于“抽象”——把复杂的寄存器配置逻辑(如时钟使能、模式设置、输出控制)打包成函数,让开发者只需关注“要做什么”,而非“怎么做”。

3. 寄存器和库函数的区别

原文从原理、代码量、开发效率、资源占用等方面对比了两者。

个人感悟:

  • 寄存器是“手动挡”:直接操作硬件,代码精简、执行快,但需要深入了解硬件细节,开发门槛高,适合底层驱动开发或资源受限场景(如内存极小的设备)。
  • 库函数是“自动挡”:屏蔽底层细节,开发效率高、易上手,但代码量较大(可能有冗余),执行速度略慢,适合应用层开发或快速原型验证。

实际开发中,两者并非对立:简单功能可用库函数快速实现,对性能要求高的部分(如中断处理)可结合寄存器操作优化。初学者建议先通过库函数入门,熟悉后再深入寄存器,理解底层原理。


学习产出:

  • 了解并学习STMSTM32F103C8T6开发板的寄存器和库函数介绍
  • 技术文章的1篇

文章转载自:

http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://00000000.zqypz.cn
http://www.dtcms.com/a/367165.html

相关文章:

  • 0904网络设备配置与管理第二次授课讲义
  • [科普] 卫星导航系统的授时原理与精度分析
  • Linux tail 命令使用说明
  • 机器学习基础-day04-数学方法实现线性回归
  • 如何在MacOS上卸载并且重新安装Homebrew
  • 基于 GEE 计算温度植被干旱指数 TVDI 并可视化分析
  • LED电路图判断灯在低电平时亮、高电平时灭
  • SpringBoot实现国际化(多语言)配置
  • 【代码随想录算法训练营——Day2】数组——209.长度最小的子数组、59.螺旋矩阵II、区间和、开发商购买土地
  • LinuxC++项目开发日志——高并发内存池(1-定长内存池)
  • 【提示词技巧】顺序位置对效果的影响
  • QT-菜单栏、工具栏和状态栏
  • Qt QJsonObject
  • 我辞职了,接替我的人私底下找我,我直接把她删了。明明有个交接群,她是觉得在群里提问会显得自己不够专业吗? 网友:凭啥惯着
  • Docker(②创造nginx容器)
  • 2025年B端产品经理进阶指南:掌握这些计算机专业技能,决胜职场!
  • 2025职场进阶:B端产品经理必备的计算机专业技能精要
  • 2025 年职场必看:B 端产品经理优化产品的计算机专业技能全解析​
  • 拉格朗日多项式
  • Elasticsearch面试精讲 Day 8:聚合分析与统计查询
  • 第13章 Jenkins性能优化
  • WebView安全实现(二)
  • push pop 和 present dismiss
  • macOS下基于Qt/C++的OpenGL开发环境的搭建
  • Swift 解法详解:LeetCode 371《两整数之和》
  • 【前端:Html】--5.进阶:APIs
  • 学习commonJS和esModuleJS的代码记录上传到git
  • WordPress搭建个人网站(Linux版)
  • 在VMware的Win10虚拟机中安装使用ENSP
  • Xterminal软件下载_Xterminal ssh远程链接工具下载__Xterminal安装包 网盘下载_Xterminal ssh远程链接工具安装包