使用寄存器点亮第LED灯——基于野火STM32F103Mini开发板

先给程序:

main.c

#include "stm32f10x.h" 

/* 主函数 */
int main(void)
{	
	// 开启GPIOC 端口时钟
	RCC_APB2ENR |= (1<<4);

	//清空控制PC2的端口位
	GPIOC_CRL &= ~( 0x0F<< (4*2));	
	// 配置PC2为通用推挽输出,速度为10M
	GPIOC_CRL |= (1<<4*2);

	// PC2 输出 低电平
	GPIOC_ODR &= ~(1<<2);
	
	while(1);
}

// 函数为空,目的是为了骗过编译器不报错
void SystemInit(void)
{	
	
}

stm32f10x.h

/*本文件用于添加寄存器地址及结构体定义*/

/*片上外设基地址  */
#define PERIPH_BASE           ((unsigned int)0x40000000)

/*APB2 总线基地址 */
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
/* AHB总线基地址 */
#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)

/*GPIOC外设基地址*/
#define GPIOC_BASE            (APB2PERIPH_BASE + 0x1000)

/* GPIOC寄存器地址,强制转换成指针 */
#define GPIOC_CRL		    *(unsigned int*)(GPIOC_BASE+0x00)
#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)

/*RCC外设基地址*/
#define RCC_BASE      (AHBPERIPH_BASE + 0x1000)
/*RCC的AHB1时钟使能寄存器地址,强制转换成指针*/
#define RCC_APB2ENR		 *(unsigned int*)(RCC_BASE+0x18)

代码分析:

(初学小白,理解颇浅,如有不对,敬请谅解【抱歉脸】)

首先参考STM32F103Mini原理图,得到LED1和LED2灯为PC2和PC3,对应连接着R45和R46电阻,管脚号分别为10和11,这里主要先点亮PC2端口的LED1灯,LED2同理,如下图所示:

 LED灯原理图

开发板上LED灯所对应的R45和R46电阻

 STM32F103RCT6芯片原理图

两个LED灯的阳极引出连接到3.3V电源,阴极各经过1个限流电阻引入至STM32的2个GPIO引脚中,所以我们只要控制这两个引脚输出高低电平,即可控制其所连接LED灯的亮灭。将GPIO的引脚设置成推挽输出模式并且默认下拉,输出低电平,这样就能让LED灯亮起来了。

stm32f10x.h 文件

/*片上外设基地址  */
#define PERIPH_BASE           ((unsigned int)0x40000000)

首先,需要明白的一件事是GPIO这个终究归属还是一个外设,所以是挂接在BLOCK2(所有片内外设都在这个区)区,所以要定义GPIO这个外设的片上外设总线基地址,那么BLOCK2的地址范围可以从数据手册-4 存储器映像中得到,如下图所示:

(注意:起始位置也就是BLOCK2这个区块的基地址,即0x4000 0000) 

/* APB2 总线基地址 */
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
/* AHB总线基地址 */
#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)

接着,外设分了很多,GPIO(挂接到APB2)是挂接在APB1、APB2总线、AHB总线,就得找到对应挂接总线的位置,参考中文参考手册-2.3 存储器映像(如下图),得到APB2的总线基地址需要在片上外设基地址的基础上 + 0x0001 0000,同理AHB的总线基地址需要在片上外设基地址的基础上 + 0x0002 0000。

 寄存器组起始地址

总线基地址(《STM32库开发实战指南》)

/*GPIOC外设基地址*/
#define GPIOC_BASE            (APB2PERIPH_BASE + 0x1000)

APB2里面挂接了很多外设,所以需要知道GPIOC对应的APB2基地址的偏移量(对于为什么不选择GPIOA/GPIOB/GPIOD...我也不太清楚,也百度了很久,得到的答案大多是只是个分组并没有太大意义,有个中肯一点的回答是需要参考数据手册看看GPIO具体支不支持哪种模式,再根据具体情况使用不同的GPIO,这里教程里使用的是GPIOC就按着做了,若日后深入学习后了解了一定再写一篇文章解释一下,这里就不深究了),参考《STM32库开发实战指南》-储存器映射,如下图所示: 

GPIO外设基地址

/* GPIOC寄存器地址,强制转换成指针 */
#define GPIOC_CRL			*(unsigned int*)(GPIOC_BASE+0x00)
#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)

GPIO有很多个寄存器,每一个都有特定的功能。每个寄存器为32bit,占四个字节,在该外设的基地址上按照顺序排列,寄存器的位置都以相对该外设基地址的偏移地址来描述。具体参考《STM32库开发实战指南》-储存器映射。

接下来就需要对寄存器进行操作,例如对GPIOC_CRL(端口配置低寄存器)进行操作,但是有一点需要注意,GPIOC_BASE+0x00在keil编译器眼中只是个二进制数,但是我们想要是这个地址,要让编译器知道这是个地址,需要将这个二进制数强制转换成指针类型(unsigned int*)变为地址存放,如果要读取地址里面的数据,则需要再加一个指针*。通过这样的宏定义,后面就可以直接通过GPIOC_CRL这个名字就能操控这个寄存器的内容了。

/*RCC外设基地址*/
#define RCC_BASE      (AHBPERIPH_BASE + 0x1000)
/*RCC的AHB1时钟使能寄存器地址,强制转换成指针*/
#define RCC_APB2ENR		 *(unsigned int*)(RCC_BASE+0x18)

在操控GPIO进行点灯前还需要对时钟RCC进行开启,只有开启时钟才能对GPIO进行控制(虽然还没学时钟是什么,但是在操作任何外设之前都应该开启该外设的时钟,记得看过一句话,时钟就像开发板的心脏,必须得跳动起来【无辜脸】,还有一句话,时钟就是告诉板子他运行了多长时间,不然会无休止的运行下去),找到GPIO外设的时钟基地址。

main.c文件

// 开启GPIOC 端口时钟
RCC_APB2ENR |= (1<<4);

首先,开启外部时钟,RCC_APB2ENR置1,代码释义参考下图:

|= (1 << 4)详解

所有的GPIO都挂载到APB2总线上,具体的时钟由APB2外设时钟使能寄存器 (RCC_ APB2ENR)来控制。

//清空控制PC2的端口位
GPIOC_CRL &= ~( 0x0F<< (4*2));	
// 配置PC2为通用推挽输出,速度为10M
GPIOC_CRL |= (1<<4*2);

接着,在代码中,我们先把控制PC2的端口位清0,然后再向它赋值“0001b”,从而使GPIOC2引脚设置成输出模式,速度为10M,设置参考《STM32库开发实战指南》99页,如下图所示:

// PC2 输出 低电平
GPIOC_ODR &= ~(1<<2);

 最后,给PC2输出低电平,点亮LED1。

(在输出模式时,对端口位设置/清除寄存器BSRR寄存器、端口位清除寄存器BRR和ODR寄存器写入参数即可控制引脚的电平状态,其中操作BSRR和BRR最终影响的都是ODR寄存器,然后再通过ODR寄存器的输出来控制GPIO。为了一步到位,我们在这里直接操作ODR寄存器来控制GPIO的电平)

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值