[STM32学习笔记(二)] 使用寄存器点亮LED小灯


我使用的是野火的STM32F103VET6指南者开发板学习

2.1 GPIO

2.1.1 GPIO介绍

GPIO 是通用输入输出端口的简称,简单来说就是STM32 可控制的引脚
STM32 芯片的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯控制以及数据采集的功能。
STM32 芯片的 GPIO 被分成很多组,每组有 16 个引脚,如型号为 STM32F103VET6 型号(指南者) 的芯片有 GPIOA、 GPIOB、 GPIOC 至 GPIOE 共 5 组 GPIO,芯片一共 100 个引脚,其中GPIO 就占了一大部分,所有的 GPIO 引脚都有基本的输入输出功能
最基本的输出功能是由 STM32 控制引脚输出高、低电平,实现控制。

如:把 GPIO引脚接入到 LED 灯,那就可以控制 LED 灯的亮灭,引脚接入到继电器或三极管,那就可以通过继电器或三极管控制外部大功率电路的通断。

最基本的输入功能检测外部输入电平.

如:把 GPIO 引脚连接到按键,通过电平高低区分按键是否被按下。

2.1.2 GPIO功能描述

GPIO端口的每个位可以由软件分别配置成多种模式:

  1. 输入浮空
  2. 输入上拉
  3. 输入下拉
  4. 模拟输入
  5. 开漏输出
  6. 推挽式输出
  7. 推挽式复用功能
  8. 开漏复用功能

每个I/O端口位可以自由编程,然而I/0端口寄存器必须按32位字被访问(不允许半字或字节访问)。 GPIOx_BSRR和GPIOx_BRR寄存器允许对任何GPIO寄存器的读/更改的独立访问;这样,在读和更改访问之间产生IRQ时不会发生危险。
I/O端口位的基本结构:
图1 I/O端口位的基本结构

2.2 使用寄存器点亮LED小灯

2.2.1 硬件连接

图2
这是一个 RGB 灯,里面由红蓝绿三个小灯构成, 使用 PWM 控制时可以混合成 256 不同的颜色。
图中从 3 个 LED 灯的阳极引出连接到 3.3V 电源,阴极各经过 1 个限流电阻引入至STM32 的 3 个 GPIO 引脚中,所以我们只要控制这三个引脚输出高低电平,即可控制其所连接 LED 灯的亮灭。

我们的目标是把 GPIO 的引脚设置成推挽输出模式并且默认下拉输出低电平,这样就能让 LED 灯亮起来了。

2.2.2 启动文件

名为“ startup_stm32f10x_hd.s”的文件,它里边使用汇编语言写好了基本程序,当STM32 芯片上电启动的时候,首先会执行这里的汇编程序,从而建立起 C 语言的运行环境,所以我们把这个文件称为 启动文件

该文件使用的汇编指令是 Cortex-M3 内核支持的指令,可参考《Cortex-M3 权威指南》 中指令集章节

关于启动文件了解到如下内容即可:
1、我们需要在外部定义一个 SystemInit函数设置 STM32 的时钟;
2、STM32 上电后,会执行 SystemInit 函数;
3、最后执行我们 C 语言中的 main 函数。

2.2.3 stm32f10x.h 文件

连接 LED 灯的 GPIO 引脚,是要通过读写寄存器来控制的
如何控制寄存器?

寄存器就是给一个已经分配好地址的特殊的内存空间取的一个别名, 这个特殊的内存空间可以通过指针来操作。

编程之前我们要先实现寄存器映射,有关寄存器映射的代码都统一写在 stm32f10x.h 文件中
stm32f10x.h文件代码如下:

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

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

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

/*GPIOB外设基地址*/
#define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)

/* GPIOB寄存器地址,强制转换成指针 */
#define GPIOB_CRL			*(unsigned int*)(GPIOB_BASE+0x00)
#define GPIOB_CRH			*(unsigned int*)(GPIOB_BASE+0x04)
#define GPIOB_IDR			*(unsigned int*)(GPIOB_BASE+0x08)
#define GPIOB_ODR			*(unsigned int*)(GPIOB_BASE+0x0C)
#define GPIOB_BSRR	  *(unsigned int*)(GPIOB_BASE+0x10)
#define GPIOB_BRR			*(unsigned int*)(GPIOB_BASE+0x14)
#define GPIOB_LCKR		*(unsigned int*)(GPIOB_BASE+0x18)

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

1、为方便使用,寄存器的地址值都直接强制转换成了指针。
2、代码的最后两段是 RCC 外设寄存器的地址定义, RCC 外设是用来设置时钟的,以后我们会详细分析,本实验中只要了解到 使用 GPIO 外设必须开启它的时钟 即可。

2.2.4 main函数

① SystemInit()函数

如果只写main函数,而不写Systemlnit函数,编译时会发生错误:
“Error: L6218E: Undefined symbol SystemInit (referred from startup_stm32f10x.o)”

从分析启动文件时我们知道, Reset_Handler 调用了该函数用来初始化 SMT32 系统时钟,为了简单起见,我们在 main 文件里面定义一个SystemInit 空函数,什么也不做,为的是骗过编译器,把这个错误去掉。

添加代码如下:

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

关于配置系统时钟我们在后面再写。当我们不配置系统时时, STM32 会把 HSI 当作系统时钟, HSI=8M,由芯片内部的振荡器提供。

还有一个方法就是在启动文件中把有关SystemInit 的代码注释掉也可以。

②GPIO设置

首先我们把连接到 LED 灯的 GPIO 引脚 PB0 配置成 输出模式,即配置 GPIO 的端口配置低寄存器 CRL

CRL 中包含 0-7 号引脚,每个引脚占用 4 个寄存器位。
1、MODE 位用来配置输出的速度,
2、CNF 位用来配置各种输入输出模式。
在这里我们把 PB0 配置为通用推挽输出,输出的速度为 10M。

图3
代码如下:

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

注意:
1、在代码中,我们先把控制 PB0 的端口位清 0,然后再向它赋值“0001 b”,从而使GPIOB0 引脚设置成输出模式,速度为 10M。
2、代码中使用了“&=~”、“|=”这种操作方法是为了避免影响到寄存器中的其它位。

③控制输出低电平

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

为了一步到位,在这里直接操作 ODR 寄存器来控制 GPIO 的电平。

	// PB0 输出 低电平
	GPIOB_ODR &= ~(1<<0);

④设置外设时钟

由于 STM32 的 外设很多,为了降低功耗,每个外设都对应着一个时钟,在芯片刚上电的时候这些时钟都是被关闭的,如果想要外设工作,必须把相应的时钟打开。


STM32 的所有外设的时钟由一个专门的外设来管理,叫 RCC(reset and clockcontrol)
所有的 GPIO 都挂载到 APB2 总线上,具体的时钟由 APB2 外设时钟使能寄存器(RCC_APB2ENR)来控制


代码如下:

// 开启GPIOB 端口时钟
	RCC_APB2ENR |= (1<<3);

⑤完整代码

main.c:

/*工程模板(寄存器版本)*/
#include "stm32f10x.h" 
/*主函数*/
int main(void)
{	
	// 开启GPIOB 端口时钟
	RCC_APB2ENR |= (1<<3);

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

	// PB0 输出 低电平
	GPIOB_ODR &= ~(1<<0);
	
	while(1);
}
// 函数为空,目的是为了骗过编译器不报错
void SystemInit(void)
{	
}

图4

  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值