研究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); //将打包的结构体变量传入函数(地址传递)

相关推荐
QYR-分析2 小时前
汽车碳刷市场深度解析:存量维保支撑需求,电动化重塑行业格局
单片机·嵌入式硬件·汽车
沐欣工作室_lvyiyi2 小时前
基于单片机的升降式立体车库系统设计(论文+源码)
单片机·嵌入式硬件·毕业设计·rfid·单片机毕业设计·数据库设计·物联网毕业设计
碧海银沙音频科技研究院3 小时前
基于炬芯ATS3089X的BLE opus音频传输系统设计
stm32·单片机·嵌入式硬件
编程圈子4 小时前
I.MX6U 裸机开发 25. PWM 与 LCD 背光
单片机·嵌入式硬件
创界工坊工作室5 小时前
35-基于AT89C51单片机的罐头生产线传送系统设计
stm32·单片机·嵌入式硬件·51单片机·proteus·生产线
qq_401700415 小时前
MCU串口接收不定长数据的三种方案,哪种最稳?
stm32·单片机·嵌入式硬件
inrichtt6 小时前
第七课时:STM32时钟系统揭秘:从零理解时钟树
c语言·数据结构·stm32·单片机·嵌入式硬件
硅基手札6 小时前
【Linux 内核专栏 17】进程间通信 IPC(上)— 管道·信号·System V IPC·mmap·文件锁
linux·运维·服务器·stm32·单片机·mcu
Zw-awa7 小时前
PID 用顺了,然后呢:增强手术与前馈
stm32
zcmodeltech7 小时前
沙盘模型控制系统STM32和PLC方案对比:选型逻辑与代码实现
stm32·嵌入式硬件·自动化