八、STM32位带操作

一、位带区与位带别名区

(一)位带介绍

1、位带操作
在学习51单片机时就已经使用过位操作,比如使用sbit对单片机IO口的定义,但是STM32中并没有这类关键字,而是通过访问位带别名区来实现,即通过将每个比特位膨胀成一个32位字,当访问这些字的时候就达到了访问比特的目的。比方说BSRR寄存器有32个位,那么可以映射到32个地址上,当我们去访问这32个地址就达到访问32个比特的目的。
2、STM32位带及位带别名区域
支持位带操作的区域是SRAM区的最低1MB范围(APB1/2,AHB外设)和片内外设区的最低1MB范围。

1MB的位就扩展为了32MB的位带别名区

(二)位带区与位带别名区地址转换

外设位带区与外设位带别名区的地址转换公式:AliasAddr = 0x42000000+ (A-0x40000000)*8*4+n*4

SRAM位带区与SRAM位带别名区的地址转换公式:AliasAddr = 0x22000000+ (A-0x20000000)*8*4 +n*4

A:表示我们要操作的那个位所在的寄存器的地址,n:位序号

理解要点:位带区的一个位在位带别名区会被膨胀成四个字节

根据上述两个公式特点,将其统一为一个公式表示:((A & 0xF0000000)+0x02000000+((A &0x000FFFFF)<<5)+(n<<2))

A:要操作的位所在寄存器的地址;n:位号,即在寄存器的第几位。

(三)位带操作的优点

(1)控制GPIO口输入输出非常简单。

(2)操作串行接口芯片非常方便(DS1302、74HC595等)

(3)代码简洁,阅读方便。

二、GPIO位带操作

//addr是地址,bitnum是该地址的第几位
#define BITBAND(addr,bitnum) ((addr&0xF0000000)+0x2000000+((addr&0xFFFFF)<<5)+(bitnum<<2))
//volatile提示该变量是随时可变的,每次使用都要读取
#define MEM_ADDR(addr)*((volatile unsigned long *)(addr))
#define BIT_ADDR(addr,bitnum) MEM_ADDR(BITBAND(addr,bitnum))
//IO口地址映射
//输出寄存器
#define GPIOA_ODR_Addr (GPIOA_BASE+12)//0x4001280C
#define GPIOB_ODR_Addr (GPIOB_BASE+12)//0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12)//0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12)//0x4001140C
#define GPTOE_ODR_Addr (GPIOE_BASE+12)//0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12)//0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12)//0x40011E0C
//输入寄存器
#define GPIOA_IDR_Addr (GPIOA_BASE+8)//0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8)//0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE+8)//0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE+8)//0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE+8)//0x40011808
#define GPTOF_IDR_Addr (GPIOF_BASE+8)//0x40011A08
#define GPTOG_IDR_Addr (GPIOG_BASE+8)//0x40011E08

//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)	BIT_ADDR(GPIOA_ODR_Addr,n)//输出
#define PAin(n) 	BIT_ADDR (GPIOA_IDR_Addr,n)//输入

#define PBout(n) 	BIT_ADDR(GPIOB_ODR_Addr,n)//输出
#define PBin(n) 	BIT_ADDR(GPIOB_IDR_Addr,n)//输入

#define PCout(n) 	BIT_ADDR(GPIOC_ODR_Addr,n)//输出
#define PCin(n) 	BIT_ADDR(GPIOC_IDR_Addr,n)//输入

#define PDout(n) 	BIT_ADDR(GPIOD_ODR_Addr,n)//输出
#define PDin(n) 	BIT_ADDR(GPIOD_IDR_Addr,n)//输入

#define PEout(n) 	BIT_ADDR(GPIOE_ODR_Addr,n)//输出
#define PEin(n) 	BIT_ADDR(GPIOE_IDR_Addr,n)//输入

#define PFout(n)	BIT_ADDR(GPIOF_ODR_Addr,n)//输出
#define PFin(n)		BIT_ADDR(GPIOF_IDR_Addr,n)//输入

#define PGout(n)	BIT_ADDR(GPIOG_oDR_Addr,n)//输出
#define PGin(n) 	BIT_ADDR(GPIOG_IDR_Addr,n)//输入

三、LED闪烁

在点亮LED灯的文件六、使用库函数点亮一个LED_并不傻的袍子-CSDN博客中,新建system.h和system.c文件,并添加到工程中,在system.h文件中键入以下代码:

#ifndef _system_H
#define _system_H

#include "stm32f10x.h"

//addr是地址,bitnum是该地址的第几位
#define BITBAND(addr,bitnum) ((addr&0xF0000000)+0x2000000+((addr&0xFFFFF)<<5)+(bitnum<<2))
//volatile提示该变量是随时可变的,每次使用都要读取
#define MEM_ADDR(addr)*((volatile unsigned long *)(addr))
#define BIT_ADDR(addr,bitnum) MEM_ADDR(BITBAND(addr,bitnum))
//IO口地址映射
//输出寄存器
#define GPIOA_ODR_Addr (GPIOA_BASE+12)//0x4001280C
#define GPIOB_ODR_Addr (GPIOB_BASE+12)//0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12)//0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12)//0x4001140C
#define GPTOE_ODR_Addr (GPIOE_BASE+12)//0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12)//0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12)//0x40011E0C
//输入寄存器
#define GPIOA_IDR_Addr (GPIOA_BASE+8)//0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8)//0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE+8)//0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE+8)//0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE+8)//0x40011808
#define GPTOF_IDR_Addr (GPIOF_BASE+8)//0x40011A08
#define GPTOG_IDR_Addr (GPIOG_BASE+8)//0x40011E08

//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)	BIT_ADDR(GPIOA_ODR_Addr,n)//输出
#define PAin(n) 	BIT_ADDR (GPIOA_IDR_Addr,n)//输入

#define PBout(n) 	BIT_ADDR(GPIOB_ODR_Addr,n)//输出
#define PBin(n) 	BIT_ADDR(GPIOB_IDR_Addr,n)//输入

#define PCout(n) 	BIT_ADDR(GPIOC_ODR_Addr,n)//输出
#define PCin(n) 	BIT_ADDR(GPIOC_IDR_Addr,n)//输入

#define PDout(n) 	BIT_ADDR(GPIOD_ODR_Addr,n)//输出
#define PDin(n) 	BIT_ADDR(GPIOD_IDR_Addr,n)//输入

#define PEout(n) 	BIT_ADDR(GPIOE_ODR_Addr,n)//输出
#define PEin(n) 	BIT_ADDR(GPIOE_IDR_Addr,n)//输入

#define PFout(n)	BIT_ADDR(GPIOF_ODR_Addr,n)//输出
#define PFin(n)		BIT_ADDR(GPIOF_IDR_Addr,n)//输入

#define PGout(n)	BIT_ADDR(GPIOG_oDR_Addr,n)//输出
#define PGin(n) 	BIT_ADDR(GPIOG_IDR_Addr,n)//输入

#endif

在system.c中键入以下代码:

#include "system.h"

在main.c中键入以下代码:

#include "system.h"
#include "led.h"

//延时函数
void delay(u32 i)
{
	u16 j=0;
	while(i--)
	{
		//1ms
		j=12000;
		while(j--);
	}
}

int main()
{
	LED_Init();	
	while(1)
	{
		PCout(0)=0;
		delay(1000);
		PCout(0)=1;
		delay(1000);
	}
}

下载到普中STM32F103ZET6开发板中,即可观察LED灯闪烁。如果不是普中的开发板,只要把LED在自己板子相应的引脚替换主函数while(1)中的PCout(0)即可

猜你喜欢

转载自blog.csdn.net/qq_40836442/article/details/110198507