研究STM32库函数 如何操作寄存器

目录

1.以LED闪烁为例子

比如LED闪烁例程中,打开数据生成

2.LED闪烁中开启GPIOA时钟的拆解

3.使用指针直接访问寄存器的方法(标准库函数操作寄存器的方法)

访问此寄存器的三步:

将上述三个步骤简化为一行:

使用宏定义替换上述的一行代码:

代码:

4.改变数据中的某一位而不影响其他位(标准库函数中|=、&=的作用)

[将其位2置1,其他位不变,0x04的二进制是0000 0100:](#将其位2置1,其他位不变,0x04的二进制是0000 0100:)

[将其位2清0,其他位不变,~0x04的二进制是1111 1011:](#将其位2清0,其他位不变,~0x04的二进制是1111 1011:)

宏定义

所以可以将APB2外设时钟使能寄存器RCC_APB2ENR的位掩码使用宏定义标注出来,保留位就是为后续开发,增加功能预留的位,这里默认为无效位

代码

使用

开启GPIOA的时钟

关闭GPIOA的时钟

同时开启GPIOA和TIM1的时钟

5.结构体,数据打包好帮手(标志库函数中->中的作用)

定义结构体类型:

定义结构体变量/结构体指针:

[访问结构体变量/结构体指针(其中pa = &a(表示pa指针,指向a这个结构体)):](#访问结构体变量/结构体指针(其中pa = &a(表示pa指针,指向a这个结构体)):)

6.使用结构体描述寄存器(标准库函数中对于寄存器的宏定义)

以下两种方法都是标准库中对于GPIO的宏定义

描述寄存器地址,常规做法:

结构体做法:

STM32F1系列数据手册中GPIO寄存器

7.使用结构体打包传参(标准库中初始化函数的使用)

例如GPIO初始化时,是将结构体作为指针传递参数

某函数需要传入一堆参数,常规做法:

结构体打包传参:

调用函数:


1.以LED闪烁为例子

软件程序能控制硬件最关键的是硬件中的寄存器,寄存器是软件到硬件的桥梁,对于软件来说,寄存器是RAM中的一段存储空间,使用指针来访问这些空间,就可以读写寄存器中的每一位,对于硬件来说,寄存器中的每一位,背后都有一个导线,去控制相应的设备,比如软件给寄存器的位写0或1,对硬件就可能是,开关某个电路或者输出某个高低电平

任何软件包装的库函数,最终都要落实到寄存器中,或者说寄存器就是对读写寄存器操作的一种封装

比如LED闪烁例程中,打开数据生成

使用RCC开启CPIOA的时钟,就要看APB2外设时钟使能寄存器RCC_APB2ENR


初始化GPIO端口,就要看端口配置低寄存器CRL和端口配置高寄存器CRH


给端口写高低电平,就看输出数据寄存器ODR,或者位设置寄存器BSRR/位清除寄存器BRR


2.LED闪烁中开启GPIOA时钟的拆解

开启GPIOA的时钟,就是给RCC_APB2ENR寄存器的位2(IOPAEN)设置位1

RCC_APB2PeriphClockCmd内部

下面会分别介绍这个RCC开启时钟函数内部的操作,大部分标准库函数和RCC开启时钟的函数是类似的,所以会了这个,其他逻辑差不多


3.使用指针直接访问寄存器的方法(标准库函数操作寄存器的方法)

0x40021018:起始地址+偏移地址

起始地址:在STM32F1系列数据手册中2.3存储器映像中有RCC的起始地址

偏移地址:在STM32F1系列数据手册中6.3.7APB2外设时钟使能寄存器中可知,这个寄存器的偏移地址和它是一个32位寄存器

例如:RCC_APB2ENR寄存器存储在地址0x40021018下,长度4字节(32位)

访问此寄存器的三步:

uint32_t *p; // 定义uint32_t类型指针

p = (uint32_t *)0x40021018; // 指针指向目标地址

*p = 0x04; // 在目标地址写入数据

要给这个寄存器写入值,就*p = 一个数据,比如这里的0x04

要读出这个寄存器的值,就直接*p

将上述三个步骤简化为一行:

*(uint32_t *)0x40021018 = 0x04;

使用宏定义替换上述的一行代码:

#define RCC_APB2ENR (*(uint32_t *)0x40021018)

RCC_APB2ENR = 0x04;

代码:


4.改变数据中的某一位而不影响其他位(标准库函数中|=、&=的作用)

上述的直接访问寄存器的方法,有不足的地方,就是虽然成功的将寄存器的某一位置1了,但是其他位都置0,如果想给寄存器的某一位置1而不影响其他位,那么就使用要 |=、&=的方法

例如:有一变量/寄存器uint8_t REG

将其位2置1,其他位不变,0x04的二进制是0000 0100:

REG |= 0x04; // REG |= 0000 0100

任何位和1相或都变成1,任何位和0相或都保持不变

将其位2清0,其他位不变,~0x04的二进制是1111 1011:

REG &= ~0x04; // REG &= 1111 1011

任何位和0相与都变为0,任何位和1相与保持不变

宏定义

这个0x04在 |=、&=、~ 的配合下只对位2进行操作,所以这个0x04称为位2的掩码

所以将0x04使用宏定义替换:

#define BIT2_MASK 0x04 // 0x04是位2的位掩码

REG |= BIT2_MASK; // |=位掩码,将此位置1,其他位不变

REG &= ~BIT2_MASK; // &= ~位掩码,将此位清0,其他位不变

所以可以将APB2外设时钟使能寄存器RCC_APB2ENR的位掩码使用宏定义标注出来,保留位就是为后续开发,增加功能预留的位,这里默认为无效位

代码

使用

开启GPIOA的时钟

关闭GPIOA的时钟

同时开启GPIOA和TIM1的时钟


5.结构体,数据打包好帮手(标志库函数中->中的作用)

定义结构体类型:

struct S {char x; int y;}; //打包数据里面的数据类型为char和int

typedef struct {char x; int y;} S_t; //这个是标志库里面运用最多的和上面是一样的

定义结构体变量/结构体指针:

struct S a;//结构体变量 struct S *pa;//结构体指针

S_t a;//结构体变量 S_t *pa;//结构体指针

访问结构体变量/结构体指针(其中pa = &a(表示pa指针,指向a这个结构体)):

a.x = '#';//结构体变量名a.结构体成员名x = 赋值 pa->x = '#';//结构体指针名pa -> 结构体成员名x = 赋值

a.y = 123;//结构体变量名a.结构体成员名y = 赋值 pa->y = 123;//结构体指针名pa -> 结构体成员名y = 赋值


6.使用结构体描述寄存器(标准库函数中对于寄存器的宏定义)

以下两种方法都是标准库中对于GPIO的宏定义

描述寄存器地址,常规做法:

指针做法虽然简洁易懂,但是很繁琐

结构体做法:

这种做法就很有规范还简单,这里的指针类型不再是uint32_t*,因为这个类型,只能指向一个寄存器,而现在定义了一个GPIO箱子(结构体),这个GPIO结构体一次性可以把所有的寄存器装在一起,所以这个类型是GPIO_t *是一个结构体指针

STM32F1系列数据手册中GPIO寄存器


7.使用结构体打包传参(标准库中初始化函数的使用)

例如GPIO初始化时,是将结构体作为指针传递参数

注意:地址传参才是最好的,不要值传参,值传参会再开辟一个空间来存储传的值,而且还有可能出错,地址传参就不会出现这种情况,地址传参是通过地址找到存储这个值的寄存器,然后复制一份

某函数需要传入一堆参数,常规做法:

定义函数:void function(char x, int y, float z) { ... }

调用函数:function('#', 123, 66.88);

结构体打包传参:

定义结构体:typedef struct {char x, int y, float z} S_t;

定义函数:void function(S_t *p) { ... }

调用函数:

S_t a; //定义结构体变量

a.x = '#'; a.y = 123; a.z = 66.88; //结构体变量赋值

function(&a); //将打包的结构体变量传入函数(地址传递)

相关推荐
rit84324993 小时前
基于STM32的触控USB鼠标设计
stm32·嵌入式硬件·计算机外设
天狼IoT3 小时前
STM32-keil+CubeMX快速开发:GPIO功能
stm32·单片机·嵌入式硬件
芯岭技术3 小时前
PY32C673单片机特性,应用场景介绍,最高主频可达 72 MHz
单片机·嵌入式硬件
ytttr8733 小时前
STM32 独立看门狗(IWDG)程序设计与实现
stm32·单片机·嵌入式硬件
学习噢学个屁3 小时前
基于51单片机心率仪—体温心率血氧蓝牙
c语言·单片机·嵌入式硬件·51单片机
济6173 小时前
FreeRTOS 通信任务设计(2)----UART+DMA 环形缓冲 + 空闲中断+ 流缓冲区--- 高效接收方案详解
stm32·单片机·嵌入式·freertos
W.W.H.4 小时前
嵌入式常见面试题——硬件与中断篇
经验分享·单片机·嵌入式硬件
灰子学技术4 小时前
Envoy 中 UDP 网络通信实现分析
网络·单片机·嵌入式硬件·网络协议·udp
济6174 小时前
FreeRTOS 通信任务设计(1)---STM32 串口 DMA + 协议帧解析 + CRC 校验全流程详解
stm32·嵌入式·freertos