一、位带操作
1.意义
回想以前写51代码
P0 = 0x10; //将P0端口设置为0x10
P1_0=1; //将P1端口1号引脚设置为高电平
a = P2_2; //获取P2端口2号引脚的电平
根据上述的方法,我们可以发现快速定位修改某个引脚的电平还有获取引脚的状态
GPIO_SetBits、GPIO_ResetBits操作IO口的性能没有达到极致,因为这些函数都需要进行现场保护和现场恢复的动作,比较耗时间,没有进行一步到位,使用位带操作则没有上述的烦恼,简单快速!
//位带操作,实现51类似的GPIO控制功能
//IO口操作宏定义#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
GPIO_SetBits(GPIOF,GPIO_Pin_9);
修改为
PFout(9)=1;
公式如下:
寄存器的位带别名 = 0x42000000 + (寄存器的地址- 0x40000000)*8*4 + 引脚编号*4
M4中,有两个地方实现了位带,一个是SRAM最低的1MB,一个是外设区最低1MB
1、外设区位带
ADDR = 0x42000000 + (A - 0x40000000) * 8 * 4 + n*4
2、SRAM区
ADDR = 0x22000000 + (A - 20000000) * 8 * 4 + n*4
统一公式#define BITBAND(addr, bitnum) ((addr & 0xF000 0000)+0x200 0000+((addr &0xFFFFF)<<5)+(bitnum<<2))
1)多线程编程共享全局变量的时候,该全局变量要加上volatile进行修饰,让编译器不要优化该变量。
2)裸机编程的时候,某函数与中断服务函数共享全局变量的时候,该全局变量要加上volatile进行修饰,让编译器不要优化该变量
3)ARM定义寄存器的时候,寄存器是指向一个地址,要加上volatile进行修饰,让编译器不要优化该变量。
编译器不要优化该变量也就是不对该资源进行保护,让任何程序随时都可以对它修改。
加上volatile关键字生成的汇编代码会发生明显的变化,同样调用delay函数,灯的速度发生变化!
#include "stm32f4xx.h"
//使用结构体的初始化,可以增强代码的阅读性
static GPIO_InitTypeDef GPIO_InitStructure;
int main(void)
{
//获取GPIOF的ODR寄存器的地址
uint32_t PF_ODR_ADDR = GPIOF_BASE + 0x14;
//转换为别名地址