Section 6

    科技2024-04-03  36

    Section 6_STM32位带操作

    1.位带介绍(1)位带操作(2)STM32位带及位带别名区域 2.位带区与位带别名区地址转换3.位带操作的优点4.编程1.新建Public文件夹,创建两个文件2.各文件代码system.hsystem.cled.hled.cmain.c

    1.位带介绍

    (1)位带操作

    在学习51单片机时就已经使用过位操作,比如使用sbit对单片机IO口的定义,但是STM32中并没有这类关键字,而是通过访问位带别名区来实现,即通过将每个比特位膨胀成一个32位字,当访问这些字的时候就达到了访问比特的目的。比方说BSRR寄存器有32个位,那么可以映射到32个地址上,当我们去访问这32个地址就达到访问32个比特的目的。

    (2)STM32位带及位带别名区域

    支持位带操作的区域是 SRAM 区的最低 1MB 范围(APB1/2,AHB1外设)和片内外设区的最低 1MB范围。

    2.位带区与位带别名区地址转换

    外设位带区与外设位带别名区的地址转换公式:

    AliasAddr = 0x42000000+ (A-0x40000000)*8*4 +n*4

    SRAM位带区与SRAM位带别名区的地址转换公式:

    AliasAddr = 0x22000000+ (A-0x20000000)*8*4 +n*4

    A:表示我们要操作的那个位所在的寄存器的地址 n:位序号 理解要点:位带区的一个位在位带别名区会被膨胀成四个字节

    根据上述两个公式特点,将其统一为一个公式表示:

    ((A & 0xF0000000)+0x02000000+((A &0x000FFFFF)<<5)+(n<<2))

    A:要操作的位所在寄存器的地址 n:位号,即在寄存器的第几位。

    3.位带操作的优点

    (1)控制GPIO口输入输出非常简单。 (2)操作串行接口芯片非常方便(DS1302、74HC595等)。 (3)代码简洁,阅读方便。

    4.编程

    1.新建Public文件夹,创建两个文件

    2.各文件代码

    system.h
    #ifndef _system_H #define _system_H #include "stm32f4xx.h" #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)) //IO口地址映射 #define GPIOA_ODR_Addr (GPIOA_BASE+20) //0x40020014 #define GPIOB_ODR_Addr (GPIOB_BASE+20) //0x40020414 #define GPIOC_ODR_Addr (GPIOC_BASE+20) //0x40020814 #define GPIOD_ODR_Addr (GPIOD_BASE+20) //0x40020C14 #define GPIOE_ODR_Addr (GPIOE_BASE+20) //0x40021014 #define GPIOF_ODR_Addr (GPIOF_BASE+20) //0x40021414 #define GPIOG_ODR_Addr (GPIOG_BASE+20) //0x40021814 #define GPIOH_ODR_Addr (GPIOH_BASE+20) //0x40021C14 #define GPIOI_ODR_Addr (GPIOI_BASE+20) //0x40022014 #define GPIOA_IDR_Addr (GPIOA_BASE+16) //0x40020010 #define GPIOB_IDR_Addr (GPIOB_BASE+16) //0x40020410 #define GPIOC_IDR_Addr (GPIOC_BASE+16) //0x40020810 #define GPIOD_IDR_Addr (GPIOD_BASE+16) //0x40020C10 #define GPIOE_IDR_Addr (GPIOE_BASE+16) //0x40021010 #define GPIOF_IDR_Addr (GPIOF_BASE+16) //0x40021410 #define GPIOG_IDR_Addr (GPIOG_BASE+16) //0x40021810 #define GPIOH_IDR_Addr (GPIOH_BASE+16) //0x40021C10 #define GPIOI_IDR_Addr (GPIOI_BASE+16) //0x40022010 //IO口操作,只对单一的IO口! //确保n的值小于16! #define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出 #define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入 #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出 #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入 #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出 #define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入 #define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出 #define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入 #define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出 #define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入 #define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出 #define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入 #define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出 #define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入 #define PHout(n) BIT_ADDR(GPIOH_ODR_Addr,n) //输出 #define PHin(n) BIT_ADDR(GPIOH_IDR_Addr,n) //输入 #define PIout(n) BIT_ADDR(GPIOI_ODR_Addr,n) //输出 #define PIin(n) BIT_ADDR(GPIOI_IDR_Addr,n) //输入 #endif
    system.c
    #include "system.h"
    led.h
    #ifndef _led_H #define _led_H #include "system.h" //包含F4头文件 void LED_Init(void); #define led1 PFout(9) #define led2 PFout(10) #endif
    led.c
    #include "led.h" void LED_Init() { GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10|GPIO_Pin_9;//管脚设置F9 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉 GPIO_Init(GPIOF,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10); }
    main.c
    #include "system.h" #include "led.h" void delay(u32 i) { while(i--); } int main() { LED_Init(); while(1) { led1=!led1; delay(9000000); led2=!led2; } }
    Processed: 0.049, SQL: 8