stm32点亮一个灯的6种方式:
本代码在正点原子ministm32 实现,闪亮PD2:
总体来说分两种:
1 通过控制三个寄存器实现,ODR,BRR,BSRR
2 位带地址写0/1实现
操作方式 | 寄存器 | 封装函数 | |
寄存器 | ODR | GPIO_WriteBit | |
BRR | GPIO_ResetBits | ||
BSRR | GPIO_SetBits | ||
位带地址 | 如(*((u32*)0x42228188))=0 |
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx->BSRR = GPIO_Pin;
}
void GPIO_ResetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
GPIOx->BRR |= GPIO_Pin;
}
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx->BSRR = GPIO_Pin;
}
void GPIO_ResetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin){
GPIOx->BRR |= GPIO_Pin;
}
char x=5;
while(1)
{
switch (x) {
case 1:
GPIOD-> ODR =0x0;
delay_ms(0xFF);
GPIOD ->ODR =0xffff;
delay_ms(0x10FF);
break;
case 2:
GPIOD->BRR |= 0x0004; // PD2 ¶ÔÓ¦µÄÊǵÚ3λ£¡²»ÊǵÚ2λ 43210
delay_ms(0xFF);
GPIOD->BSRR |=0x0004;
delay_ms(0xFF);
break;
case 3:
GPIOD->BSRR =0x00040000;
delay_ms(0xFF);
GPIOD->BSRR |=0x0004;
delay_ms(0xFF);
break;
case 4:
GPIO_WriteBit(GPIOD, GPIO_Pin_2,0);
delay_ms(0xFF);
GPIO_WriteBit(GPIOD, GPIO_Pin_2, 1);
delay_ms(0xFF);
break;
case 5:
GPIO_ResetBits(GPIOD, 4);
delay_ms(0xFF);
GPIO_SetBits(GPIOD, 4);
delay_ms(0xFF);
break;
case 6:
(*((u32*)0x42228188))=0; //0x42228180+2*4
delay_ms(0xFF);
(*((u32*)0x42228188))=1;
delay_ms(0x10FF);
break;
default:
}
位绑定地址计算公式为:
结合“豆包” ,prompt: stm32 gpioA PA0的位绑定地址 计算:
AliasAddr = 0x42000000 + ((A – 0x40000000) * 32 + n * 4),其中A为要绑定的寄存器地址,n表示寄存器中的位序号(0~7)。()
PA0的位绑定地址 ,也称位带地址(C是 ODR的偏移地址)
= 0x42000000 + (0x1080C × 32) + 0 × 4= 0x42000000 + 0x210180 = 0x42210180
则PA8的位绑定地址: (0x42210180+8*4)
PD2的位绑定地址 ,也称位带地址(C是 ODR的偏移地址)
= 0x42000000 + (0x1140C × 32) + 2 × 4 =0x42228188
注:× 32等于16进制的 x20 ,很方便手算。
教材的算法:
// 把“位带地址+位序号”转换成别名地址的宏
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2))
其中:addr & 0xF0000000:
取地址的高4位,看看是2还是4,用于区分SRAM和外设地址,
1 *如果是2,即是SRAM,+0x02000000则=0X2200 0000,
*SRAM位带别名地址
*AliasAddr= 0x2200 0000+((A-0x2000 0000)*8+n)*4 =0x22000000+ (A-0x20000000)*8*4 +n*4
2 如果是4,即是外设,+0x02000000则=0X4200 0000,
其中 :addr & 0x000FFFFFF:
屏蔽掉高两位,相当于-0X2000 0000(SRAM)或者-0X4000 0000(外设),结果表示偏移位带区多少个字节
*<<5 等于*8*4,因为位带区一个地址表示一个字节,一个字节有8个bit,一个bit可以膨胀成一个字,即4个字节
*<<2 等于*4,因为一个位可以膨胀成一个字,即4个字节
例: PD2 位带地址 (A 指的是地址 — ODR的绝对地址)
= 0x4200 0000+((A-0x4000 0000)*8+n)*4
=0x4200 0000+ (A-0x4000 0000)*8*4 +n*4
= 0x4200 0000 +(0x4001 140C – 0x4000 0000)*32+ 2*4
= 0x4200 0000 + 0x0001 140C *16*2+8 // *16左移一个16进制的0,好计算,然后口算
= 0x4200 0000 + 0x0001 140C0*2 + 8
= 0x 4200 0000
+ 0x 0022 8180
+ 8
= 0x 4222 8188
PD->ODR 绝对地址的来由:
以上是 GPIOD_BASE 地址:
GPIOD_ODR地址还要加上ODR的偏移地址 C,如图:
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001 140C
更多 关于 ODR地址,点击: https://blog.csdn.net/weixin_41830837/article/details/124135996
最后还要加上,某位的偏移地址。
点灯的位带操作更多参考:
https://blog.csdn.net/wh201906/article/details/103861517
#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))
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#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 GPIOE_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 GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n)
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n)
————————————————
原文链接:https://blog.csdn.net/wh201906/article/details/103861517
作者:真实义