01_点灯
开发板:野火指南者
MCU:STM32F103VET6
仿真器:DAP
开发环境:windows、Keil5
1、创建工程
1.1、项目结构如下
1.2、拷贝标准库到工程
下方为板子型号对应汇编文件,需要参考板子具体Flash选择合适文件,指南者使用``startup_stm32f10x_hd.s`
共六个文件
1.3、加入项目配置
2、编译配置
野火指南者配套开发板仿真器使用DAP下载器,同时MCU使用VET6,因此需要以下配置,如果使用其他开发板,请自行配置
(可选)如果不想每次按复位,需要如下配置
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官网中找到对应型号的文档手册
要操作的外设模块为``GPIO,并且组为
GPIOB,因此 ↓ 将其置为
1`
*(uint32_t*)(0x40021000 + 0x18) = 8;
uint32_t*
:左值为常量无法赋值、找到指针
*()
:前面的 * 解引用,设置特定寄存器
0x40021000
:RCC基地址
0x18
:偏移地址
8
:相当于 左移到第三个操作位
其他代码解释类似
3.2.1.2、找地址
外设模块基地址(手册:存储器映像)
偏移地址(每个寄存器上方有标注)
例如:
3.2.2、配置GPIO工作模式
因为开发板中LED对应引脚为P0/1/5,而低寄存器对应0-7,高寄存器对应8-15,因此找到GPIO
端口配置低寄存器
根据对应的P0/1/5
找到对应的CNF0/MODE0、CNF1/MODE1、CNF5/MODE5
CNFy[1,0]
:使用通用推挽输出模式 00
MODEy[1,0]
:使用输出50MHz 11
因此对应二进制为 0011
即 3
*(uint32_t*)(0X40010C00) = 3 << 4;
3.2.3、设置低电平
3.2.3.1、原理图
3.2.3.2、编写
看这段代码
*(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(开发板非授课配套)