stm32点亮一个灯的6种方式:

 本代码在正点原子ministm32 实现,闪亮PD2:

353e348794d841e4b0d154206ef4f909.png

总体来说分两种:

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 绝对地址的来由:

fbad9d34f39f4977b03aec78bc9c46af.png

 

以上是 GPIOD_BASE 地址:

GPIOD_ODR地址还要加上ODR的偏移地址 C,如图:

 

802846911fdda46cbeac1d2a9f4e6d70.png

#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

 

 

作者:真实义

物联沃分享整理
物联沃-IOTWORD物联网 » stm32点亮一个灯的6种方式:

发表回复