STM32F103-入门基础实验-GPIO输出控制LED核心代码(位带版)

上次我们讲解了操作GPIO的方法和核心代码,分别是寄存器版和固件库版,今天我们讲最后一种操作GPIO的方法,—位带操作。
之前我们在学习51单片机的过程中,
我们是用“sbit”关键字---位定义的方法去操作一个引脚,
CPU在(读/写)时也就是1位的数据量,
那为什么51单片机就可以使用这样位定义“sbit”的操作?
:因为,我们可以点开<reg51.h>这个头文件,
中看到 SFR 关键字,后门跟的是寄存器的名字,或一串16进制数,
这就是51中的存储器映射和寄存器映射,
通过SFR关键字把引脚也封装了起来,这样我们也就可以位操作。
#include"reg51.h"	    //C51头文件

sbit LED0 = P2^0;	    //位定义
void delay(unsigned int n);

void main()
{
	while(1)             //led灯的闪烁
	{
		LED0 = 0;
		delay(500);
		LED0 = 1;
		delay(500);
	}
}
void delay(unsigned int n)//非标准延时,大约是1μs
{
	unsigned int i=0,j=0;
	for(i=0;i<n;i++)
	{
		for(j=0;j<120;j++);
	}

}
问题来了,难道咱们的STM32就没有这么便捷的操作嘛?
:肯定是有啊!但是STM32 没有这样的关键字,而是通过访问位带别名区来实现。

在 STM32 中,有两个地方实现了位带,一个是 SRAM 区的最低 1MB 空间,令一个是外设区最低 1MB 空间。这两个 1MB 的空间除了可以像正常的 RAM 一样操作外,他们还有自己的位带别名区,位带别名区把这 1MB 的空间的每一个位膨胀成一个 32 位的字,当访问位带别名区的这些字时,就可以达到访问位带区某个比特位的目的。

简单说,就是通过一个公式,和一些宏定义的封装,
我们就可以实现,类似“sbit”的位操作,
咱们直接上代码,去理解~
#include "stm32f10x.h"

// 这里只定义了 GPIO ODR和IDR这两个寄存器的位带别名区地址,其他寄存器的没有定义
// 把“位带地址+位序号”转换成别名地址的宏
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2))

// 把一个地址转换成一个指针
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 

// 把位带别名区地址转换成指针
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))    

//拿GPIOB端口的引脚为例
// GPIO ODR 和 IDR 寄存器地址映射 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C  
#define GPIOB_IDR_Addr    (GPIOB_BASE+8)  //0x40010C08  

// 单独操作 GPIO的某一个IO口,n表示具体是哪一个IO口
#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出   
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入   

void Delay(uint32_t Count);	 //声明简单延时函数
void LED_GPIO_Config(void);	 //声明LED端口初始化函数
/*==================主程序入口======================*/
int main(void)
{	
	LED_GPIO_Config();
	
	while(1)
	{
		// PB5 = 0,点亮LED
		PBout(5)= 0;		
		Delay(0x0FFFFF);
		
		// PB5 = 1,熄灭LED		
		PBout(5)= 1;
		Delay(0x0FFFFF);	
	}
}
/*=================声明函数的具体实现================*/
void LED_GPIO_Config(void)
{		
	// 定义一个GPIO_InitTypeDef类型的结构体
	GPIO_InitTypeDef GPIO_InitStructure;

	// 开启GPIOB的时钟
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); 

	// 选择要控制的IO口													   
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;	

	// 设置引脚为推挽输出
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   

	// 设置引脚速率为50MHz
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; 

	/*调用库函数,初始化GPIOB0*/
	GPIO_Init(GPIOB, &GPIO_InitStructure);		  

	// 关闭LED
    GPIO_SetBits(GPIOB, GPIO_Pin_5); 
   
}

// 简单延时函数
void Delay(uint32_t Count)	
{
	for(; Count != 0; Count--);
}
STM32的位操作的难点就是地址转换公式这一块,大家有不懂的地方就看看数据手册,如果有同学找不到资源,可以在博客下方评论留言,我会在第一时间为你充当学习的传送门哦~
欢迎大家的留言和评论我会在看到的第一时间内答复。
看完后感觉得到帮助的小伙伴,要点点赞哦~
给笔者一些动力嘛!谢谢啦~
原创文章 13 获赞 10 访问量 540

猜你喜欢

转载自blog.csdn.net/weixin_45636395/article/details/106053001