首先我把位段操作的步骤说一下:
(直接cp手册上的原文)
下面的映射公式给出了别名区中的每个字是如何对应位带区的相应位的:
bit_word_addr = bit_band_base + (byte_offset×32) + (bit_number×4)
其中:
bit_word_addr是别名存储器区中字的地址,它映射到某个目标位。
bit_band_base是别名区的起始地址。
byte_offset是包含目标位的字节在位段里的序号
bit_number是目标位所在位置(0-31)
例子:
下面的例子说明如何映射别名区中SRAM地址为0x20000300的字节中的位2:
0x22006008 = 0x22000000 + (0x300×32) + (2×4).
对0x22006008地址的写操作与对SRAM中地址0x20000300字节的位2执行读-改-写操作有着相同的效果
我们需要知道位段操作同样适用于外设的映射地址
外设起始地址为 0x40000000;
我们以stm32f103RC6芯片为例:
我买的该板子pd2引脚连着led灯,因此需要知道的一些关键信息包括如下
//GPIOD的映射地址
#define GPIOD ((GPIO_TypeDef *)GPIOD_BASE) //0x4001 1400
//GPIO的寄存器的定义如下,其中__IO就是volatile关键字,对于GPIOD而言,我们直接将GPIOD包含的寄存器的地址标上,方便查看
typedef struct
{
__IO uint32_t CRL; //0x40011400
__IO uint32_t CRH; //0x40011404
__IO uint32_t IDR; //0x40011408
__IO uint32_t ODR; //0x4001140c
__IO uint32_t BSRR; //0x40011410
__IO uint32_t BRR; //0x40011414
__IO uint32_t LCKR; //0x40011418
} GPIO_TypeDef;
如何点亮led灯?
我们可以对 GPIOD的 ODR 寄存器或者BSSR寄存器进行操作;
1、对ODR寄存器的 bit2(0~31)写0,则 PD2输出低电平,对ODR寄存器的 bit2(0~31)写1,则 PD2输出高电平
2、对BSSR的 bit2(0~31)写1,PD2输出高电平,对BSSR的 bit(2+16)(0~31)写1,PD2输出低电平, //16 代表引脚为 0~15 ,16个引脚 。对BSSR寄存器写0 ,不产生任何动作
因此我们可以用以下的方法来控制LED灯的亮灭。
1、用位段操作来控制ODR或者 BSSR寄存器
2、在直接的外设地址寄存器中去写数据
因此我们可以按照以下方法
①第一种是对BSSR进行位段操作,我们看之前的 BSSR的地址为 0x40011410,则位段操作地址(对PD2引脚,因此是 bit2)为 0x4200 0000 + 0x11410*32 + 2*4 引脚输出高电平
引脚需要输出低电平时 则位段操作为(对BSSR寄存器的18bit进行操作) 地址为 0x4200 0000 + 11412*32 +18*4
②对BSSR寄存器的映射地址直接写数据 BSSR的地址为 0x40011410,则我们在 bit2写1 ,操作为 *((volatile uint32_t *)0x40011410) = 0x04; 给PD2输出高电平
或者bit18写1, *((volatile uint32_t *)0x40011410) = 0x040000; 给PD2输出低电平
③ 当然我们可以直接对 GPIOD的BSSR寄存器进行操作 GPIOD->BSRR = 4;//输出高电平
GPIOD->BSRR = (uint32_t)4<<16; //输出低电平 也是完全ok的
④我们对 ODR寄存器进行位段操作 ODR的映射地址为 0x4001140c ,位段操作 地址为 0x4200 0000 + 0x1140c*32 + 2*4
⑤直接对ODR寄存器进行写数据
⑥调用HAL库
代码如下,只起到参考作用
#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))
int main()
{
//....
//..一些GPIO初始化
while(1)
{
HAL_Delay(1000);
switch(way)
{
case 1:
//TODO:1 对BSSR寄存器进行位段操作
BIT_ADDR(0x40011410,2) = 1; //宏定义展开为 *((volatile unsigned long*)0x42228208) = 1;
HAL_Delay(1000);
BIT_ADDR(0x40011410,18) = 1;
break;
case 2:
//TODO:2 对BSSR寄存器的映射地址直接写数
*((volatile uint32_t *)0x40011410) = 0x04;
HAL_Delay(1000);
*((volatile uint32_t *)0x40011410) = 0x040000;
break;
case 3:
//TODO:3 对BSSR寄存器的操作
GPIOD->BSRR = 4;
HAL_Delay(1000);
GPIOD->BSRR = (uint32_t)4<<16;
break;
case 4:
//TODO:4 对ODR寄存器进行位段操作
BIT_ADDR((GPIOD_BASE+12),2) = 1;
HAL_Delay(1000);
BIT_ADDR((GPIOD_BASE+12),2) = 0;
break;
case 5:
//TODO:5 对ODR寄存器的映射地址直接写数
*((volatile uint32_t *)0x4001140c) = 0x04;
HAL_Delay(1000);
*((volatile uint32_t *)0x4001140c) = 0x00;
break;
case 6:
//TODO:6 调用HAL库函数
HAL_GPIO_WritePin(GPIOD, LED1_Pin, 0);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOD, LED1_Pin, 1);
break;
default:break;
}
}
}
功能就是led闪烁。用的IDE是 STM32CUBE ide 讲真的确非常好用!!!(👍)