01_点灯

开发板:野火指南者

MCU:STM32F103VET6

仿真器:DAP

开发环境:windows、Keil5

1、创建工程

1.1、项目结构如下

01_led_register_create_project

1.2、拷贝标准库到工程

01_led_register_start01

01_led_register_start02

下方为板子型号对应汇编文件,需要参考板子具体Flash选择合适文件,指南者使用``startup_stm32f10x_hd.s`

01_led_register_start03

01_led_register_start04

共六个文件

1.3、加入项目配置

01_led_register_start07

01_led_register_start05

01_led_register_start06

2、编译配置

01_led_register_config01

野火指南者配套开发板仿真器使用DAP下载器,同时MCU使用VET6,因此需要以下配置,如果使用其他开发板,请自行配置

01_led_register_config02

01_led_register_config03

01_led_register_config04

01_led_register_config06

(可选)如果不想每次按复位,需要如下配置

01_led_register_config05

3、寄存器代码实现

3.1、整体代码

配置完成开始编写代码,点亮小灯(由于指南者中只有一个LED灯,所以只操作小灯发出不同颜色RGB,不进行流水灯操作)

#include <stdint.h>	// uint32_t 需要引用该头文件

int main(void)
{
	// 蓝灯 PB1
	// 1、时钟配置
	*(uint32_t*)(0x40021000 + 0x18) = 8;
	// 2、GPIO工作模式配置
	*(uint32_t*)(0X40010C00) = 3 << 4;
	// 3、PB1 输出低电平
	*(uint32_t*)(0X40010C00 + 0x0C) = 0xFFFD;
	
	// *********************************************
	
	// 绿灯 PB0
	// 1、时钟配置
	*(uint32_t*)(0x40021000 + 0x18) = 8;
	// 2、GPIO工作模式配置
	*(uint32_t*)(0X40010C00) = 3;
	// 3、PB0 输出低电平
	*(uint32_t*)(0X40010C00 + 0x0C) = 0xFFFE;
	
	// *********************************************
	
	// 红灯 PB5
	// 1、时钟配置
	*(uint32_t*)(0x40021000 + 0x18) = 8;
	// 2、GPIO工作模式配置
	*(uint32_t*)(0X40010C00) = 3 << 20;
	// 3、PB5 输出低电平
	*(uint32_t*)(0X40010C00 + 0x0C) = 0xFFDF;
    
	// 4、死循环保持状态
	while (1) {}
}

3.2、解释

3.2.1、开启外设模块时钟

主要的目的就是给相对独立的外设模块提供时钟,也是为了降低整个芯片的功能。 降低功耗是主要原因,还有一个原因,就是为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费。 RCC给外设提供时钟是一个主要目的,那么为什么要提供时钟呢? 原因在于外围设备的寄存器需要时钟才能工作。 你可以把外设当做一个设备,而这个设备需要给它提供电源(时钟)才能工作。

3.2.1.1、找到APB2外设时钟使能寄存器(RCC_APB2ENR)

在STM32官网中找到对应型号的文档手册

01_led_register_RCC01

要操作的外设模块为``GPIO,并且组为GPIOB,因此 ↓ 将其置为 1`

01_led_register_RCC02

*(uint32_t*)(0x40021000 + 0x18) = 8;

uint32_t*:左值为常量无法赋值、找到指针

*():前面的 * 解引用,设置特定寄存器

0x40021000:RCC基地址

0x18:偏移地址

8:相当于 左移到第三个操作位


其他代码解释类似

3.2.1.2、找地址

外设模块基地址(手册:存储器映像)

01_led_register_RCC03

偏移地址(每个寄存器上方有标注)

例如:

01_led_register_RCC04

3.2.2、配置GPIO工作模式

因为开发板中LED对应引脚为P0/1/5,而低寄存器对应0-7,高寄存器对应8-15,因此找到GPIO端口配置低寄存器

01_led_register_RCC05

根据对应的P0/1/5找到对应的CNF0/MODE0、CNF1/MODE1、CNF5/MODE5

CNFy[1,0]:使用通用推挽输出模式 00

MODEy[1,0]:使用输出50MHz 11

因此对应二进制为 00113

*(uint32_t*)(0X40010C00) = 3 << 4;

3.2.3、设置低电平

3.2.3.1、原理图

01_led_register_led

3.2.3.2、编写

01_led_register_ODR

看这段代码

*(uint32_t*)(0X40010C00 + 0x0C) = 0xFFFD;

0X40010C00:GPIO基地址

0x0C:ODR偏移

0xFFFD:对应的是0-15的十六进制,即将PB1(ODR1)置为低电平,想让哪个灯亮,就设置那个ODRx为低电平

4、宏定义 + 位操作

#include "stm32f10x.h"

// #include <stdint.h>

int main(void)
{
	// 蓝灯 PB1
	// 1、时钟配置
	// *(uint32_t*)(0x40021000 + 0x18) = 8;
	// RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
	
	// 2、GPIO工作模式配置
	// *(uint32_t*)(0X40010C00) = 3 << 4;
	// GPIOB->CRL &= ~GPIO_CRL_CNF1;
	// GPIOB->CRL |= GPIO_CRL_MODE1_0;
	
	// 3、PB1 输出低电平
	// *(uint32_t*)(0X40010C00 + 0x0C) = 0xFFFD;
	// GPIOB->ODR &= ~GPIO_ODR_ODR1;
	
	// *********************************************
	
	// 绿灯 PB0
	// 1、时钟配置
	// *(uint32_t*)(0x40021000 + 0x18) = 8;
	// RCC->APB2ENR |= 1 << 3;
	// RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
	
	// 2、GPIO工作模式配置
	// *(uint32_t*)(0X40010C00) = 3;
	// GPIOB->CRL |= 1 << 1;
	// GPIOB->CRL &= ~GPIO_CRL_CNF0;
	// GPIOB->CRL |= GPIO_CRL_MODE0_1;
	
	// 3、PB0 输出低电平
	// *(uint32_t*)(0X40010C00 + 0x0C) = 0xFFFE;
	// GPIOB->ODR &= ~(1 << 0);
	// GPIOB->ODR &= ~GPIO_ODR_ODR0;
	
	// *********************************************
	
	// 红灯 PB5
	// 1、时钟配置
	// *(uint32_t*)(0x40021000 + 0x18) = 8;
	// RCC->APB2ENR |= 1 << 3;
	RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
	
	// 2、GPIO工作模式配置
	// *(uint32_t*)(0X40010C00) = 3 << 20;
	// GPIOB->CRL |= 3 << 20;
	GPIOB->CRL &= ~GPIO_CRL_CNF5;
	GPIOB->CRL |= GPIO_CRL_MODE5_1;
	
	// 3、PB5 输出低电平
	// *(uint32_t*)(0X40010C00 + 0x0C) = 0xFFDF;
	// GPIOB->ODR &= ~(1 << 5);
	GPIOB->ODR &= ~GPIO_ODR_ODR5;
	
	// 4、死循环保持状态
	while (1) {}
}

感谢:尚硅谷 | 视频课程移步bilibili尚硅谷stm32单片机教程,STM32入门教程,寄存器与HAL开发一套通P12-P18(开发板非授课配套)

posted @ 2025-07-25 11:21  KAZU0105  阅读(15)  评论(0)    收藏  举报