两种方式实现STM32寄存器点灯

一、使用技术手册找取寄存器地址

        本文以打开  PB8  LED灯为例

1、定位APB总线寄存器位置

       1. 根据下图可知,GPIOB桥接在APB2上

所以需要打开RCC_APB2的时钟,

而打开时钟就需要先找到RCC_APB2的地址,在技术手册中先打开2.3存储器映射章节

在此章到RCC端口的基地址为  0x4002 1000  而APB2的地址只需加上偏移量就可确定

偏移量可在6.3.7节找到

于此可知偏移地址为  0x18  所以RCC_APB2的地址就为

RCC基地址0x4002 1000 + APB2偏移量 0x18 

在keil中就可定义

#define RCC_APB2ENR          *((volatile unsigned int *) (0x40021000 + 0x18))      //RCC起始地址加偏移

volatile是C的关键词,作用是不让编译器优化代码,防止程序出错。

0x40021000 + 0x18,如果不加任何操作,他便只是一串数字,所以需要先将其转换成指针类型((volatile unsigned int *) (0x40021000 + 0x18))然后再将其中的值取出所以需要再加上*号。

这样就可对这个地址存的值进行操作。

2、定位GPIO端口位置

在2.3存储器映射章节可找到GPIOB的基地址为0X4001 0C00 

然后找到偏移地址便可确定GPIOB的地址,

8.2.1 端口配置低寄存器(GPIOx_CRL) (x=A..E)    低寄存器端口x配置位(y = 0…7) 即职能配置GPIOB的第0口到第7口

所以想pin8口就需要配置高寄存器,高寄存器的偏移地址为  0x04

于此可知偏移地址为  0x04所以GPIOB高寄存器的地址就为

GPIOB基地址0X4001 0C00 + APB2偏移量 0x04

在keil中就可定义

3、找到端口输出数据(ODR)

此寄存器为配置pin口 1 或 0 

#define GPIOB_ODR           *((volatile unsigned int *) (0x40010C00 + 0x0C))      //GPIOB端口地址加偏移

以上就找到了所有需要配置的寄存器

4、RCC_APB2时钟使能

由此可知要想打开GPIOB的时钟就要控制此寄存器的第三位。

所以只需要将第三位 置一 就可打开GPIOB的时钟

RCC_APB2ENR |= (0x01 << 3);  //APB2时钟启用

5、IO端口配置

此图中的CNF8,MODE8就是代表的就是pin8口

如图进行配置便可初始化GPIOB.

二进制0011转换为16进制就为0x03

GPIOB_CRH   |= 0x03;   // 推完输出  50Hz  PB8 

6、引脚置零

	GPIOB_ODR  &=~ (0x01 << 8);          //PB8置0

7、完整代码

#define RCC_APB2ENR          *((volatile unsigned int *) (0x40021000 + 0x18))      //RCC起始地址加偏移
#define GPIOB_CRH            *((volatile unsigned int *) (0x40010C00 + 0x04))      //GPIOB起始地址加偏移
#define GPIOB_ODR           *((volatile unsigned int *) (0x40010C00 + 0x0C))      //GPIOB端口地址加偏移
	
int main(void)
{
	RCC_APB2ENR |= (0x01 << 3);  //APB2时钟启用
	GPIOB_CRH   |= 0x03;   // 推完输出  50Hz  PB8 PB9
	GPIOB_ODR  &=~ (0x01 << 8);          //PB8置0
	while(1)
	{ 
	}
}	

二、使用 stm32f10x.h 头文件

观看一后再看二,不然必定看不懂 ! ! !

stm32f10x.h中已将RCC的基地址强制转换成了结构体类型并且define为了 “RCC” 

所以只需要在mian中引用头文件即可

#include "stm32f10x.h"                  // Device header

引用之后便可直接使用,GPIOB也是如此

代码为

#include "stm32f10x.h"                  // Device header
int main(void)
{
		RCC->APB2ENR |=(0x01 << 3);  //APB2时钟启用
		GPIOB->CRH   |= 0x03;
		GPIOB->ODR   &=~ (0x01 << 8);
}

三、扩展

#define     __IO    volatile                  /*!< defines 'read / write' permissions   */
  • 可看到__IO  即为volatile 的define, 
  • 在这个结构体中,可看到其中的成员为CR、CFGR、CIR...
  • 而在技术手册中6.3.11 RCC寄存器地址映像中可找到

这些成员正是按照寄存器的顺序而定义并且每个寄存器的大小都为32字节,而uint32_t正好占据32字节,所以一旦将GPIO的地址作为此结构体的首地址,那么所有成员的首地址都将与所对应寄存器一一对应。所以在我们在用结构体调用成员赋值的时候才能给对应寄存器进行赋值,所有这种类型的结构体都是如此。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值