写在前面:本系列内容均为自学笔记,参考资料为野火指南者开发板资料及芯片参考手册等,使用野火指南者开发板进行学习,该系列内容仅用于记录笔记,不做其他用途,笔记的内容可能会存在不准确或者错误等,如有大佬看到错误内容还望能够评论指正,感谢各位。
本节包括前一节的程序,请参考野火开发板资料,里面由更加清晰的教学,野火B站账号:野火官方B站账号链接。
本节内容与上一节(STM32单片机学习笔记(二)-点亮LED灯(寄存器版)(一))的内容相关,在上一节的基础上进一步学习优化。
学习目标
1、进行寄存器映射,并使用寄存器点亮LED灯;
2、操作GPIOx_BSRR或者GPIOx_BRR寄存器,点亮或者熄灭LED灯;
一、寄存器映射,点亮LED灯
本节用到以下电路图:
图2-1:绿色LED灯点灯电路
先看一下来自芯片官方参考手册的关于寄存器及其地址的表格,共截图3张,参考英文版手册,当然中文版手册也有这几个表格;
图2-2:寄存器及其地址(截图来自官方参考手册,共截图3张)
以上表格我们着重看总线APB1、APB2、AHB基地址,GPIOB、RCC基地址;除此之外还要看GPIOB各个寄存器偏移地址,RCC中RCC_APB2ENR寄存器偏移地址;
表2-1:寄存器偏移地址
寄存器名称 | 偏移地址 |
---|---|
RCC_APB2ENR | 0x18 |
GPIOB_CRL | 0x00 |
GPIOB_CRH | 0x04 |
GPIOB_IDR | 0x08 |
GPIOB_ODR | 0x0C |
GPIOB_BSRR | 0x10 |
GPIOB_BRR | 0x14 |
GPIOB_LCKR | 0x18 |
上面的表格是RCC部分寄存器及GPIO寄存器的偏移地址;
表2-2:总线地址及偏移
总线名称 | 总线地址 | 外设基地址 | 偏移地址 |
---|---|---|---|
APB1 | 0x40000000 | 0x40000000 | 0x00000 |
APB2 | 0x40010000 | 0x40000000 | 0x10000 |
AHB | 0x40018000 | 0x40000000 | 0x18000 |
上面的表格是总线的地址及偏移地址;
由上面的表格和图片可以看出APB1基地址为0x4000000,APB2基地址为0x40010000,AHB基地址为0x40018000,于是可以进行以下寄存器映射:
下列程序可放至stm32f10x.h文件中,前提该文件为空,上节内容有提到:
//stm32f10x.h文件中的内容,存放用于寄存器映射的程序
//外设英文:peripheral,本程序简写为PERIPH
//十六进制的加减法,不要用十进制加减法算,两种方式结果不一样
#define PERIPH_BASE ((unsigned int)0x40000000) //外设基地址,不做强制转换,方便后面进行宏定义
#define APB1PERIPH_BASE (PERIPH_BASE + 0x00000) //APB1总线基地址
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) //APB2总线基地址
#define AHBPERIPH_BASE (PERIPH_BASE + 0x18000) //AHB总线基地址
#define RCC_BASE (AHBPERIPH_BASE + 0x9000) //RCC寄存器基地址
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00) //GPIO寄存器基地址
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE + 0x18) //APB2外设时钟使能寄存器地址,强制转换
#define GPIOB_CRL *(unsigned int*)(GPIOB_BASE + 0x00) //GPIOB端口配置低寄存器地址,强制转换
#define GPIOB_CRH *(unsigned int*)(GPIOB_BASE + 0x04) //GPIOB端口配置高寄存器地址,强制转换
#define GPIOB_ODR *(unsigned int*)(GPIOB_BASE + 0x0C) //GPIOB端口输出数据寄存器地址,强制转换
通过以上程序即可将相关寄存器进行映射,在之后使用时直接使用相关寄存器的名字即可实现功能,功能程序会简化一些;
main.c中的程序如下:
#include "stm32f10x.h"
int main(void)
{
//使能GPIOB时钟
RCC_APB2ENR |= (1<<3);
//设置端口为输出模式,速率为10MHz
GPIOB_CRL &= ~(1<<(4*0)); //防止其他程序影响配置,先将第0位的4位数值清零
GPIOB_CRL |= (1<<(4*0));
//设置PB0_0为低电平
GPIOB_ODR &= ~(1<<0);
}
void SystemInit(void)
{
//函数体为空,目的是骗过编译器
}
以上程序即为点灯程序,相较于学习笔记1中的点灯程序,本程序可以直观的看到使用的是什么寄存器,也更加简洁,当然前提是先进行正确的寄存器映射。
二、操作GPIOx_BSRR及GPIOx_BRR寄存器控制LED灯
首先看以下GPIOx_BSRR寄存器相关介绍:
图2-3:GPIOx_BSRR寄存器(截图来自官方参考手册)
1、通过BSRR寄存器点亮LED灯
由图2-3可知,GPIOx_BSRR寄存器低16位负责将ODR寄存器置1,高16位负责置0,,根据这个特点,可以得到下面的程序,以实现控制LED灯:
stm32f10x.h文件程序如下,其中加入了GPIOB_BSRR和GPIOB_BRR两个寄存器的映射程序:
//stm32f10x.h文件中的内容,存放用于寄存器映射的程序
//外设英文:peripheral,本程序简写为PERIPH
//十六进制的加减法,不要用十进制加减法算,两种方式结果不一样
#define PERIPH_BASE ((unsigned int)0x40000000) //宏定义外设基地址,不做强制转换,方便后面进行宏定义
#define APB1PERIPH_BASE (PERIPH_BASE + 0x00000) //APB1基地址
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) //APB2基地址
#define AHBPERIPH_BASE (PERIPH_BASE + 0x18000) //AHB基地址
#define RCC_BASE (AHBPERIPH_BASE + 0x9000) //RCC寄存器基地址
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00) //GPIO寄存器基地址
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE + 0x18) //APB2外设时钟使能寄存器地址,强制转换
#define GPIOB_CRL *(unsigned int*)(GPIOB_BASE + 0x00) //GPIOB端口配置低寄存器地址,强制转换
#define GPIOB_CRH *(unsigned int*)(GPIOB_BASE + 0x04) //GPIOB端口配置高寄存器地址,强制转换
#define GPIOB_ODR *(unsigned int*)(GPIOB_BASE + 0x0C) //GPIOB端口输出数据寄存器地址,强制转换
#define GPIOB_BSRR *(unsigned int*)(GPIOB_BASE + 0x10) //GPIOB端口位设置/清除寄存器地址,强制转换
#define GPIOB_BRR *(unsigned int*)(GPIOB_BASE + 0x14) //GPIOB端口位清除寄存器地址,强制转换
main.c中的程序如下:
#include "stm32f10x.h"
int main(void)
{
//使能GPIOB时钟
RCC_APB2ENR |= (1<<3);
//设置端口为输出模式,速率为10MHz
GPIOB_CRL &= ~(1<<(4*0)); //防止其他程序影响配置,先将第0位的4位数值清零
GPIOB_CRL |= (1<<(4*0));
//设置PB0_0为低电平
GPIOB_ODR |= 1<<0; //先将ODR寄存器相关位置1,熄灭LED灯
GPIOB_BSRR |= (1<<16); //清零ODR寄存器第0位
}
void SystemInit(void)
{
//函数体为空,目的是骗过编译器
}
main.c中的程序先对GPIOB_ODR进行操作,将其置1,这主要是为了排除ODR寄存器复位值的影响,ODR寄存器复位值为0x00000000,这会影响后续程序;将ODR寄存器置1后,LED灯将会处于熄灭状态,此时使用BSRR寄存器将相应位置0即可将LED灯点亮。
2、通过BSRR寄存器熄灭LED灯
main.c中程序如下:
#include "stm32f10x.h"
int main(void)
{
//使能GPIOB时钟
RCC_APB2ENR |= (1<<3);
//设置端口为输出模式,速率为10MHz
GPIOB_CRL &= ~(1<<(4*0)); //防止其他程序影响配置,先将第0位的4位数值清零
GPIOB_CRL |= (1<<(4*0));
//设置PB0_0为低电平
GPIOB_ODR &= ~(1<<0); //点亮LED灯
GPIOB_BSRR |= (1<<0); //置1ODR寄存器第0位
}
void SystemInit(void)
{
//函数体为空,目的是骗过编译器
}
由于ODR寄存器复位为0,所以不对ODR寄存器操作LED灯也会亮,当ODR寄存器中第0位为0时LED灯亮,此时使用BSRR寄存器将该位置1,此时LED灯为熄灭状态。
3、通过BRR寄存器点亮LED灯
先看一下GPIOx_BRR寄存器相关介绍,分为两个截图:
图2-4:GPIOx_BRR寄存器(截图来自官方参考手册,2个截图)
通过图2-4可知,BRR寄存器只能会ODR寄存器进行清0,所以根据这个特点,得到以下程序:
#include "stm32f10x.h"
int main(void)
{
//使能GPIOB时钟
RCC_APB2ENR |= (1<<3);
//设置端口为输出模式,速率为10MHz
GPIOB_CRL &= ~(1<<(4*0)); //防止其他程序影响配置,先将第0位的4位数值清零
GPIOB_CRL |= (1<<(4*0));
//设置PB0_0为低电平
GPIOB_ODR |= (1<<0); //先将ODR寄存器相关位置1,熄灭LED灯
GPIOB_BRR |= (1<<0); //ODR寄存器第0位置0
}
void SystemInit(void)
{
//函数体为空,目的是骗过编译器
}
程序中,先将LED灯熄灭,排除干扰,再操作BRR寄存器点亮LED灯。
以上仅作笔记参考,不做教学,感谢观看。