STM32入门系列-使用C语言封装寄存器

2023-05-16

前面介绍了存储器映射、寄存器和寄存器映射,这些都是为了介绍使用 C语言封装寄存器做铺垫。这里我们通过一个实例来对 C 语言封装寄存器进行介绍。

    具体实例:控制 GPIOC 端口的第 0 管脚输出一个低电平。首先我们需要知道GPIOC 端口外设是挂接在哪个总线上的,然后根据总线基地址和本身的偏移地址得到 GPIOC 外设基地址,最后通过这个外设基地址得到里面各种寄存器基地址。

总线和外设基地址封装

    根据寄存器的概念,我们可以使用 C 语言中的宏定义对寄存器进行定义。具体代码如下:

    //定义外设基地址

    #define PERIPH_BASE ((unsigned int)0x40000000) 1)

    //定义 APB2 总线基地址

    #define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000) 2)

    //定义 GPIOC 外设基地址

    #define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800) 3)

    //定义寄存器基地址 这里以 GPIOC 为例

    #define GPIOC_CRL *(unsigned int*)(GPIOC_BASE+0x00) 4)

    #define GPIOC_CRH *(unsigned int*)(GPIOC_BASE+0x04)

    #define GPIOC_IDR *(unsigned int*)(GPIOC_BASE+0x08)

    #define GPIOC_ODR *(unsigned int*)(GPIOC_BASE+0x0C)

    #define GPIOC_BSRR *(unsigned int*)(GPIOC_BASE+0x10)

    #define GPIOC_BRR *(unsigned int*)(GPIOC_BASE+0x14)

    #define GPIOC_LCKR *(unsigned int*)(GPIOC_BASE+0x18)

    上述代码中我们在后面备注了数字,下面对其进行简单介绍下其功能:

· 

定义外设的基地址,这个地址也是 Block2 的基地址。

· 

· 

定义 APB2 总线基地址,因为 Block2 的第一个总线是 APB1,而 APB2 总线地址只需要加上对应的地址偏移量即可。

· 

· 

定义 GPIO 外设基地址,因为 GPIOC 是挂接在 APB2 总线上的,所以找到对应的端口地址偏移量即可知道 GPIOC 端口基地址。

· 

· 

定义 GPIO 外设寄存器基地址,这里以 GPIOC 端口为例,因GPIOC_CRL是 GPIOC 外设的第一个寄存器,所以基地址就是 GPIOC 地址,其他寄存器地址只需要在 GPIOC 基地址上加上相应的偏移量即可。

· 

    我们得到了寄存器具体的地址,那么就可以使用 C 语言指针来操作读写。例如我们需要 GPIOC0 输出一个低电平或者高电平,可以使用下面语句来操作。

    //控制 GPIOC 第 0 管脚输出一个低电平

    GPIOC_BSRR = (0x01<<(16+0));

    //控制 GPIOC 第 0 管脚输出一个高电平

    GPIOC_BSRR = (0x01<<0);

    我们知道 GPIOC_BSRR 的值是这个寄存器的地址,但是编译器不知道它是地址,而是把它当做立即数,所以我们必须要强制转换为(unsigned int *)指针类型才可以对其操作,这一点特别要注意。嵌入式物联网智能硬件等系统学习企鹅意义气呜呜吧久零就易,然后再在前面加上一个“*”作取指针操作,表示对该地址内内容进行写,读操作也同样使用“*”取指针操作。如下:

    unsigned int temp;

    temp =GPIOC_IDR;

    将寄存器内的数据保存在变量 temp 中,使用到变量时一定要进行定义。

寄存器封装

    通过前面讲解,我们已经可以对寄存器进行操作,但是还稍有不足,因为STM32的GPIO比较多, 我们不可能每使用一个GPIO都做前面一样的一大堆定义。根据GPIO寄存器的特点,我们知道不论GPIOA还是GPIOB等都拥有一组功能相同的寄存器,如GPIOA_ODR/GPIOB_ODR/GPIOC_ODR等等,它们只是地址不一样。

    为了更方便地访问寄存器,我们引入C语言中的结构体对寄存器进行封装,具体代码如下:

    typedef unsigned int uint32_t; /*无符号 32 位变量*/

    typedef unsigned short int uint16_t; /*无符号 16 位变量*/

    /* GPIO 寄存器列表 */

    typedef struct

    {

        uint32_t CRL; /*GPIO 端口配置低寄存器 地址偏移: 0x00 */

        uint32_t CRH; /*GPIO 端口配置高寄存器 地址偏移: 0x04 */

        uint32_t IDR; /*GPIO 数据输入寄存器 地址偏移: 0x08 */

        uint32_t ODR; /*GPIO 数据输出寄存器 地址偏移: 0x0C */

        uint32_t BSRR; /*GPIO 位设置/清除寄存器 地址偏移: 0x10 */

        uint32_t BRR; /*GPIO 端口位清除寄存器 地址偏移: 0x14 */

        uint16_t LCKR; /*GPIO 端口配置锁定寄存器 地址偏移: 0x18 */

    }GPIO_TypeDef;

    这段代码用 typedef 关键字声明了名为GPIO_TypeDef的结构体类型,结构体内有7 个成员变量,变量名正好对应寄存器的名字。C 语言的语法规定,结构体内变量的存储空间是连续的,其中32位的变量占用4个字节,16 位的变量占用2个字节。

    于是,我们定义的GPIO_TypeDef,假如这个结构体的首地址为0x4001 1000(这也是第一个成员变量 CRL的地址),那么结构体中第二个成员变量CRH的地址即为0x4001 1000 +0x04,加上的这个0x04,正是代表CRH所占用的4个字节地址的偏移量,其它成员变量相对于结构体首地址的偏移,在上述代码右侧注释已给出。

    这样的地址偏移与STM32 GPIO外设定义的寄存器地址偏移一一对应,只要给结构体设置好首地址,就能把结构体内成员的地址确定下来,然后就能以结构体的形式访问寄存器了,比如我们还是将GPIOC0输出低电平,具体代码如下:

    GPIO_TypeDef * GPIOx; //定义一个GPIO_TypeDef型结构体指针GPIOx

    GPIOx = GPIOC_BASE; //把指针地址设置为宏 GPIOC_BASE 地址

    GPIOx->BSRR =(1<<(16+0)); //通过指针访问并修改 GPIOC_BSRR 寄存器

    这段代码先用GPIO_TypeDef类型定义一个结构体指针GPIOx,并让指针指向GPIOC基地址GPIOC_BASE,地址确定下来,然后根据C语言访问结构体的内容,用GPIOx->BSRR写寄存器。为了操作更简便灵活,我们直接使用宏定义好GPIO_TypeDef类型的指针,而且指针指向各个GPIO端口的首地址,使用时我们直接用该宏访问寄存器即可。具体代码如下:

    #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)

    #define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)

    #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)

    #define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)

    #define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)

    #define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)

    #define GPIOG ((GPIO_TypeDef *) GPIOG_BASE)

    GPIOC->BSRR = (1<<(16+0));

    我们这里仅仅以GPIO这个外设为例,给大家讲解了如何使用C语言对寄存器封装,对于其他的外设也是使用同样方法。其实到了后面的实验程序的编写,我们都是使用ST公司提供的固件库,他们把STM32所有外设都已经封装好了,我们只需要调用即可。 我们这里分析这个封装过程只是想让大家更加清楚理解如何使用C来封装寄存器的。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32入门系列-使用C语言封装寄存器 的相关文章

  • NRF24L01数据通信C程序

    NRF24l01 产品性能 xff1a 1 xff09 2 4GHZ全球开放ISM频段免许可使用 2 xff09 最高工作速率2Mbps GFSK高效调制 3 xff09 125个频道满足多点通讯和跳频通讯需求 4 xff09 1 9 3
  • gazebo仿真之xacro文件

    span class token operator lt span span class token operator span xml version span class token operator 61 span span clas
  • c++ 释放内存 野指针

    在释放内存之时 xff0c 不仅仅是将该块内存进行释放 xff0c 还要将指向该块内存的指针置为NULL 如果不置为NULL xff0c 下次继续使用该指针时会出现问题 具体看示例 在下面的示例中 xff0c 如果没有处理野指针的那句话 x
  • 二维码识别 -- 基于ros平台下的仿真

    生活中的二维码 二维码是用某种特定的几何图形按一定规律在平面 xff08 二维方向上 xff09 分布的黑白相间的图形记录数据符号信息的 xff1b 在代码编制上巧妙地利用构成计算机内部逻辑基础的 0 1 比特流的概念 xff0c 使用若干
  • ROS中控制机械臂抓取目标例程

    在上一个博文中介绍了一个简单的目标识别的例子 xff0c 在这篇博客中 xff0c 例如是别的结果 xff0c 完成机械臂的抓取控制 xff0c 主要进行程序的分析和学习 包含的头文件 xff1a include lt ros ros h
  • STM32_Debug 使用ST-Link进行调试出现Error:Flash Download Failed-"Cortex-M3" 解决方案

    在Debug窗口依次注意以下几个点 xff1a 1 选择与主控芯片相配套的芯片 2 选择ST Link Debugger 此处注意该页面最下面一行可不更改 xff08 亲测有效 xff09 3 接上图点击进入Setting xff0c 依次
  • 标准外设库(STD库)、HAL库、LL库三者区别

    转自 xff1a https blog csdn net zcshoucsdn article details 54613202 2018 1 19 HAL库详解见STM32之HAL库详解 及 手动移植 STM32 Embedded Sof
  • FOC矢量控制

    FOC xff08 Filed Oriented Control xff09 是采用数学方法实现三相马达的力矩与励磁的解耦控制 主要是对电机的控制电流进行矢量分解 xff0c 变成励磁电流 I d Id 之后我将详细介绍一下这个算法的数学原
  • Linux网络编程8——对TCP与UDP的简易封装

    引言 每次使用socket通信 xff0c 都会有很对相似的操作 本文 xff0c 会对TCP与UDP通信做一简单封装 xff0c 并生成动态库 代码 my socket h ifndef MY SOCKET H define MY SOC
  • 分分钟带你入门无刷电机控制_P-NUCLEO-IHM001套件评测使用

    终于有时间将前段时间把有关ST公司的分分钟带你入门无刷电机控制 P NUCLEO IHM001套件评测的资料系统的整理一下 刚一开始接触接触这个套件的时候感觉这是什么鬼 xff0c 可以实现正弦波矢量控制 xff1f 这么强 xff0c 慢
  • SiamFC代码配置复现

    写在前面 最近在研究SiamRPN xff0c 究其根本 xff0c CNN依托于AlexNet骨架 xff0c 所以花些功夫研究以下SiamFC代码 xff0c 将其阶段性复现 Tracking only 关于GPU显卡配置 cudn和c
  • PySOT

    写在前面 期待已久的PySOT终于放上了code xff0c 高兴ing xff0c 赶忙进行相应的配置加以复现 xff0c 不得不说 xff0c 作者真的很贴心 xff0c 把配置环境的指令封装成脚本 xff0c 直接按需配置即可 但是在
  • 【Linux】SocketCan c语言编程

    前言 为了能够对Socket CAN的深入理解 xff0c 我们需要了解Socket的机制 Socket的中文翻译为 插座 xff0c 在计算机世界里称为套接字 Socket最初是作为网络上不同主机之间进程的通信接口 xff0c 后来应用越
  • VMWare虚拟机网络配置及虚拟机远程rviz显示雷达数据

    虚拟机网络配置 1 工具 环境 本机 xff1a Windows 10 64位虚拟机 xff1a VMware Workstation xff0c Ubuntu 18 04 2 Windows配置 WLAN部分 网络和Internet配置
  • 2022数学建模国赛B题思路分析

    分享一下 xff0c 仅供参考借鉴 xff0c 切勿直接使用 xff01 致谢一下全糖奶茶屋 xff01 一 问题重述 1 1 问题背景 由于无人机集群在遂行编队飞行时 应尽可能的避免外界干扰 因此需要尽可能的保持电磁静默减少电磁波信号的发
  • 利用Visual Studio创建C语言dll

    利用VS2019创建dll方法 动态链接库的定义及意义如何在VS创建dll入口函数DLLMain如何创建导出函数动态调用导出函数 动态链接库的定义及意义 动态链接库 xff08 Dynamic Link Library 或者 Dynamic
  • Human-in-the-Loop Optimization of Exoskeleton Assistance Via Online Simulation of Metabolic Cost

    Human in the Loop Optimization of Exoskeleton Assistance Via Online Simulation of Metabolic Cost 文章来源https ieeexplore ie
  • Dynamical Movement Primitives (DMP) 总结

    Dynamical Movement Primitives DMP 总结 概述 DMP通过将动态系统建立为 弹簧阻尼系统 43 非线性控制项的方式 f f f xff0c 实现了对示教数据的建模 具体贡献如下 xff1a 提供了一种简单的非
  • Probabilistic Movement Primitives (ProMP) 总结

    概述 文章通过在DMP的基础上增加随机项 xff0c 并通过EM算法求解得到符合示教数据的参数 一 模型介绍 1 系统方程 假设示教数据为 61 q t
  • 一些有用的数学定理

    法托引理 xff08 Fatou Theorem xff09 设 f n f n f n 是非负可测函数 xff0c 那么

随机推荐

  • 爬取需要登录的网站

    爬虫在采集网站的过程中 xff0c 部分数据价值较高的网站 xff0c 会限制访客的访问行为 这种时候建议通过登录的方式 xff0c 获取目标网站的cookie xff0c 然后再使用cookie配合代理IP进行数据采集分析 1 使用表单登
  • Makefile和Cmake的联系与区别

    CMake是一种跨平台编译工具 xff0c 比make更为高级 xff0c 使用起来要方便得多 CMake主要是编写CMakeLists txt文件 xff0c 然后用cmake命令将CMakeLists txt文件转化为make所需要的m
  • STM32内部寄存器、储存器、C对寄存器的封装

    STM32内部寄存器 储存器 C对寄存器的封装 STM32的地址空间可以分为8个 xff0c 分别是Block0 Block7 xff0c 其中Block2是应用于外设的存储器 xff0c 也是主要学习的内容 存储器映射 存储器的地址由厂商
  • C++ STL中各种数据结构操作的时间复杂度比较

    C 43 43 STL中各种数据结构操作的时间复杂度比较 访问push back push front insert pop back pop front erace find listO n O 1 O 1 O 1 O 1 O 1 O 1
  • pom.xml 标签详解

    lt project xmlns 61 34 http maven apache org POM 4 0 0 34 xmlns xsi 61 34 http www w3 org 2001 XMLSchema instance 34 xsi
  • 解决“打开ArcGIS Server Manager”网页无反应为空白的情况

    问题 xff1a 装上arcgis serve 10后 xff0c 打开arcgis server manager页面返回空白 xff0c 用firefox显示 未找到元素 郁闷 xff0c 后来想尽各种办法 终于可以了 解决办法 xff1
  • 汇编语言教程-返回指令(RET)

    汇编语言教程 返回指令 RET 当子程序执行完时 xff0c 需要返回到调用它的程序之中 为实现此功能 xff0c 指令系统提供了一条专用的返回指令 其格式如下 xff1a RET RETN RETF Imm 子程序的返回在功能上是子程序调
  • 富斯/MC6接收机说明书

    正面 反面 1 PWM输出通道多达6个 xff0c 可以自由切换7种模式 xff0c 自由选择无刷 xff0c 有刷 xff0c 差速 xff0c 炫酷的RGB全彩灯带等 xff0c 自由玩耍 2 集成两个5A有刷电调 xff0c 通过模式
  • C++之struct构造函数(2010-10-19 15:04:47)

    C 43 43 之struct构造函数 2010 10 19 15 04 47 转载 标签 xff1a cpp struct 构造函数 校园 分类 xff1a C C PlusPlus 在网络协议 通信控制 嵌入式系统的C C 43 43
  • 汉字转拼音

    原创的兄弟 xff0c 看来是费了不少功夫 在此谢过了 代码如下 xff1a public class hanzi to pinyin1 private static readonly string Allhz 61 new string
  • 什么是功能性需求和非功能性需求

    需求定义 xff1a 需求 xff08 requirement xff09 就是系统 xff08 更广义的说法是项目 xff09 必须提供的能力和必须遵从的条件 需求分类 xff1a 1 在一般使用中 xff0c 需求按照功能性 xff08
  • 卷三、七言古诗

    卷三 七言古诗 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 登幽州台歌 作者 xff1a 陈子昂 前不见古人
  • 卷五、五言律诗

    卷五 五言律诗 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 经邹鲁祭孔子而叹之 作者 xff1a 唐玄宗 夫子
  • 卷六、七言律诗

    61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 黄鹤楼 作者 xff1a 崔颢 昔人已乘黄鹤去 xff0c 此地空
  • 计算两个经纬度间的距离(c++)

    double D jw double wd1 double jd1 double wd2 double jd2 double x y out double PI 61 3 14159265 double R 61 6 371229 1e6
  • C语言库函数及示例

    函数名 abort 功 能 异常终止一个进程 用 法 void abort void 程序例 include lt stdio h gt include lt stdlib h gt int main void printf 34 Call
  • Json风格指南

    英文版 xff1a http google styleguide googlecode com svn trunk jsoncstyleguide xml 翻译 xff1a Darcy Liu 简介 该风格指南是对在Google创建JSON
  • C中__FILE__ __LINE__的用法

    include lt stdio h gt void main void printf 34 File s Successfully reached line d n 34 FILE LINE Other statements here l
  • MC6C迈克/FLYSKY富斯/WFLY2天地飞二代接收机远程刷固件教程

    1 安装ch341的驱动程序 请找ch341卖家要或百度找 2 ch341的跳线跳到usb To ttl 如能本身只有TTL刷机的功能的板子 xff0c 像CH340一般只有usb to ttl的功能 xff0c 这一步可以不做 3 接收机
  • STM32入门系列-使用C语言封装寄存器

    前面介绍了存储器映射 寄存器和寄存器映射 xff0c 这些都是为了介绍使用 C语言封装寄存器做铺垫 这里我们通过一个实例来对 C 语言封装寄存器进行介绍 具体实例 xff1a 控制 GPIOC 端口的第 0 管脚输出一个低电平 首先我们需要