一、位带操作
eg:51代码
sfr P0 = 0x10; //将P0端口设置为0x10 00010000
P1_0 = 1; //将P1(GPIOP1_0)端口0号引脚设置为高电平
A = P2_2; //获取P2端口2号引号的电平
根据上述的方法,我们可以发现快速定位修改某个引脚的电平还有获取引脚的状态
Bit-band operation support allows a single load/store operation to access (read/write) to a single data bit. In the Cortex ? -M3 and Cortex-M4 processors, this is sup-ported in two pre-defined memory regions called bit-band regions.
位带操作的概念其实30年前就有了,那还是 CM3 将此能力进化,这里的位带操作是 8051 位寻址区的威力大幅加强版
位带区: 支持位带操作的地址区
位带别名: 对别名地址的访问最终作 用到位带区的访问上(注意:这中途有一个 地址映射过程)
二、位带操作的优越性
位带操作对于硬件 I/O 密集型的底层程序最有用处
支持了位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写。在CM3中,有两个区中实现了位带。其中一个是SRAM区的最低1MB范围,第二个则是片内外设区的最低1MB范围。这两个区中的地址除了可以像普通的RAM一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个32位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。
关于IO引脚对应的访问地址,可以参考以下公式
寄存器位带别名 = 0x42000000 + (寄存器的地址-0x40000000)*32 + 引脚编号*4
三、寄存器的地址转换成别名地址
1、确定某端口访问起始地址
如:端口F访问的起始地址GPIOF_BASE
#define GPIOF ((GPIO_TypeDef *)GPIOF_BASE)
2、根据要访问的寄存器地址计算偏移值
GPIOF的某个寄存器地址 = GPIOF_BASE+偏移地址
例如:
GPIOF的ODR寄存器的地址 = GPIOF_BASE + 0x14
3、根据以下公式进行换算
寄存器位带别名 = 0x42000000 + (寄存器的地址-0x40000000)*32 + 引脚编号*4
4、设置PF9引脚电平代码如下:
uint32_t *PF9_BitBand =
*(uint32_t *)(0x42000000 + ((uint32_t )&GPIOF->ODR– 0x40000000) *32 + 9*4)
四、代码调整
将端口的访问封装为Pxout、Pxin,例如端口F引脚电平设置PFout
#define PFout(x) *(volatile uint32_t *)(0x42000000 + ((uint32_t )&GPIOF->ODR – 0x40000000) *32 + x*4)
注意:
当你使用位带功能时,要访问的变量必须用volatile来定义。因为C编译器并不知道同一个比特可以有两个地址。所以就要通过volatile,使得编译器每次都如实地把新数值写入存储器,而不再会出于优化的考虑,在中途使用寄存器来操作数据的复本直,到最后才把复本写回(这和cache的原理是一样的)。
四、test
#include "stm32f4xx.h"
#define PAin(n) *(volatile uint32_t *)(0x42000000+(((uint32_t)&GPIOA->IDR - 0x40000000)<<5) + (n<<2))
#define PEin(n) *(volatile uint32_t *)(0x42000000+(((uint32_t)&GPIOE->IDR - 0x40000000)<<5) + (n<<2))
#define PFout(n) *(volatile uint32_t *)(0x42000000+(((uint32_t)&GPIOF->ODR - 0x40000000)<<5) + (n<<2))
#define PEout(n) *(volatile uint32_t *)(0x42000000+((uint32_t)&GPIOE->ODR - 0x40000000)*32+n*4)
#define KEY0 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)
#define KEY2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)
#define KEY3 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)
#define KEY00 PAin(0)
#define KEY11 PEin(2)
#define KEY22 PEin(3)
#define KEY33 PEin(4)
static GPIO_InitTypeDef GPIO_InitStruct;
static GPIO_InitTypeDef GPIO_InitStructKey;
static uint16_t flag = 1;
void delay(uint32_t ms)
{
int i=0;
while(ms--)
{ for(i=0;i<18000;i++)
{
}
}
}
void init_led_beep()
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOE, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10 | GPIO_Pin_8;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOF, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
GPIO_Init(GPIOE, &GPIO_InitStruct);
}
void Key_init(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
GPIO_InitStructKey.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructKey.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructKey.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 |GPIO_Pin_4;
GPIO_InitStructKey.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructKey.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOF, &GPIO_InitStructKey);
GPIO_InitStructKey.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructKey.GPIO_PuPd = GPIO_PuPd_DOWN ;
GPIO_Init(GPIOA, &GPIO_InitStructKey);
}
uint32_t Key_Scan1(void)
{
if(KEY0 == 0)
return 1;
else if( KEY1 == 0 )
return 2;
else if( KEY2 == 0 )
return 3;
else if( KEY3 == 1 )
return 4;
return 0;
}
uint32_t Key_Scan2(void)
{
if(KEY00 == 0)
return 1;
else if( KEY11 == 0 )
return 2;
else if( KEY22 == 0 )
return 3;
else if( KEY33 == 1 )
return 4;
return 0;
}
void Led_All_On1(void)
{
GPIO_ResetBits(GPIOF, GPIO_Pin_9|GPIO_Pin_10);
GPIO_ResetBits(GPIOE, GPIO_Pin_13|GPIO_Pin_14);
}
void Led_All_off1(void)
{
GPIO_SetBits(GPIOF, GPIO_Pin_9|GPIO_Pin_10);
GPIO_SetBits(GPIOE, GPIO_Pin_13|GPIO_Pin_14);
}
void Led_All_On2(void)
{
PFout(9) = 0;
PFout(10) = 0;
PEout(13) = 0;
PEout(14) = 0;
}
void Led_All_off2(void)
{
PFout(9) = 1;
PFout(10) = 1;
PEout(13) = 1;
PEout(14) = 1;
}
void Led_pao(void)
{
PFout(9) = 0;
PFout(10) = 1;
PEout(13) = 1;
PEout(14) = 1;
delay(800);
PFout(9) = 1;
PFout(10) = 0;
PEout(13) = 1;
PEout(14) = 1;
delay(800);
PFout(9) = 1;
PFout(10) = 1;
PEout(13) = 0;
PEout(14) = 1;
delay(800);
PFout(9) = 1;
PFout(10) = 1;
PEout(13) = 1;
PEout(14) = 0;
delay(800);
}
int main(void)
{
init_led_beep();
Key_init();
while(1)
{
uint32_t res = Key_Scan1();
delay(20);
switch(res)
{
case 1:
Led_pao();
break;
case 2:
Led_All_off2();
break;
case 3:
PFout(8) = 1;
delay(1000);
break;
case 4:
PFout(8) = 0;
break;
default:
break;
}
}
}
|