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

最新更新时间:2022-11-18来源: zhihu关键字:STM32  入门系列  C语言 手机看文章 扫描二维码
随时随地手机看文章

前面介绍了存储器映射、寄存器和寄存器映射,这些都是为了介绍使用 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来封装寄存器的。

关键字:STM32  入门系列  C语言 编辑:什么鱼 引用地址:STM32入门系列-使用C语言封装寄存器

上一篇:STM32入门系列-STM32外设地址映射
下一篇:STM32入门系列-创建寄存器模板

推荐阅读

意法半导体发布STM32C0系列MCU 让成本敏感的8位应用也能享受32 位性能
意法半导体发布STM32C0系列MCU让成本敏感的8位应用也能享受32 位性能STM32系列高性价比入门级产品,现已量产并发货,享受 10 年产品寿命保障2023年1月31日,中国 ---- 服务多重电子应用领域、全球排名前列的半导体公司意法半导体(STMicroelectronics,简称ST;)推出迄今为止STM32 微控制器 (MCU)产品家族中性价比最高的STM32C0系列产品,为开发者降低STM32入门门槛。全球已有数十亿个智能工业、医疗和消费产品采用STM32 MCU。STM32现有产品型号达数千种,让产品设计人员总能选到价格适中、功能和性能皆满意的产品。在保障供货的同时,意法半导体将新的 STM32C0 系列定位于家用
发表于 2023-01-31
意法半导体发布STM32C0<font color='red'>系列</font>MCU  让成本敏感的8位应用也能享受32 位性能
学习STM32日志——简单外部中断
STM32支持19个外部中断和事件请求,其中线0~15映射对应IO口的输入中断。每个线同时最多只能映射一个IO口。映射关系而中断服务函数只有7个。线5-9共用一个,10到15共用一个。下面是配置步骤。开始自己编写一个程序,通过两个按键的按下来触发中断,一个按键接地,端口设置为上拉状态,触发模式为下降沿触发;另一个按键接VCC,端口设置为下拉状态,触发模式为上升沿触发。然后在中断服务函数中编写触发中断后要执行的函数。一个为切换LED的亮灭状态,另一个控制蜂鸣器的通断。在调试过程中,出现了按键按下但会偶尔失灵,既不触发中断的现象,经过半个小时的找原因,发现因为粗心,将接地按键的触发模式设置为下降沿,而将接VCC按键的触发模式设置为上升沿
发表于 2023-01-31
学习STM32日志——独立看门狗实验
继续更新学习STM32的历程,今天学习看门狗。在单片机构成的微型计算机系统中,单片机的工作时常收到外界电磁场的干扰,导致程序跑飞,陷入死循环。为了解决这个问题,产生了一种用于监测单片机程序运行状态的模块或芯片,叫做看门狗(WatchDog),而这个东西已经集成在STM32芯片内部。它能在系统跑飞的情况下将系统复位,重新执行程序。STM32有两个看门狗,一个是窗口看门狗,由APB1时钟分频后得到的时钟驱动;另一个是独立看门狗,由专用的低速时钟(LSI)驱动,它是由内部的RC振荡器产生的,约为40KHZ,即使主时钟发生故障它仍然有效。看门狗的原理是:当我们使能看门狗时(往键值寄存器IWDG_KR写入0xCCCC实现),12位的计数器就会
发表于 2023-01-31
STM32学习日志——窗口看门狗实验
程序的调试有时候很令人头痛,但找出原因并解决的一刻是真的爽。下午继续STM32的学习,接下来是窗口看门狗实验,之所以叫做窗口,是因为它的喂狗时间有一个上下限范围,可以通过寄存器去配置。而它的下限是固定的,为0x3F(0x001111111),上限通过寄存器WWDG_CFR配置,如果在上限之前喂狗则会复位,到达下限后系统也会自动复位。从看门狗框图中可以看出,复位的与门输出要为1,则两个输入必须都为1,说明WDGA启动位必须置1,或门的输出也要为1这两个条件必须满足。而要想或门的输出为1,有两个条件之一满足即可,1)T6为0,即0x40减至0x3F的一瞬间触发复位。2)比较器的输出为1,即T6:0>W6:0,也就是计数器的当前值比
发表于 2023-01-31
STM32学习日志——定时器中断实验
今天学习的是通用定时器及其中断,首先是内部时钟的选择,定时器的时钟Tclk是由APB1时钟乘以1或2决定的,至于是1还是2,要看APB1的分频系数(AHB/APB1),如果为1,则乘以1,否则乘以2。接着就可以根据我们想设定的时间Tout,去配置ARR跟PSC,这两个数是存在16位的寄存器,所以他们的范围为(0-65535),在这个范围内任意取值,满足公式即可。如果我么要配置500ms,可将ARR配置为2499,PSC配置为14399。也就是定时器计数的一个周期为500ms。(ARR为自动重装载值,PSC为Tclk的预分频系数)根据步骤去写程序就很简单了。实现功能:通过定时器的中断控制一个绿灯翻转,时间为500ms,主函数一个红灯以
发表于 2023-01-31
<font color='red'>STM32</font>学习日志——定时器中断实验
STM32学习日志——PWM输出实验
今天学习的是通用定时器的比较输出功能,也就是PWM;从它的工作过程图中很容易看出,就是计数器与比较值CCRx作比较,可以产生对应的IO口逻辑。而具体的对应关系需要对相应的寄存器进行配置。1)首先是选择工作模式,即对CCMR1的OC1M[2:0]配置,模式1是计数器小于比较值为有效电平,模式2是计数器大于比较值为有效电平。2)其次配置输出极性,0为高电平有效,1为低电平有效。3)使能比较输出。在频率确定的情况下(上一节课有提到,通过预分频系数来设定),PWM的周期是由ARR自动重装载确定,占空比是由CCRx确定,通过对这两个参数的修改,就可以得到我们想要的脉冲波。根据下面的步骤就可以输出PWM,因为使用的是PB5端口,所以需要开启TI
发表于 2023-01-31
小广播
设计资源 培训 开发板 精华推荐

何立民专栏 单片机及嵌入式宝典

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

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