5.STM32F40x 位带操作内容及代码介绍

一、位带操作内容

位带操作(Bit-banding Operation)是一种在嵌入式系统中的编程技术,用于对单独的位(bit)进行读取和写入操作,以方便对特定位进行控制和操作。

在嵌入式系统中,内存按字节(Byte)进行寻址,而数据通常以比特(Bit)的形式进行操作。位带操作技术通过将每个比特映射到一个独立的内存位置,使得可以直接对一个比特进行读取和写入操作,而不需要额外的位操作指令。

二、位带区和位带别名区的内容

 (一)位带区和位带别名区的概念
  1. 位带区(Bit-band Region)是一种在嵌入式系统中的内存区域,用于实现位带操作技术。位带区将每个比特(Bit)映射到内存中的独立地址,从而可以针对单个比特进行读取和写入操作。

        在位带区中,通常将每个字节(Byte)的每个比特都映射到一个对应的位带别名地址。这些位带别名地址被用于访问位带区,可以通过读取或写入位带别名地址来操作相应的位。由于每个比特都有独立的地址,因此可以直接对其中的某个比特进行读取或写入操作,而无需使用位操作指令或遮罩操作。

    2.位带别名区(Bit-band Alias Region)是一种在某些嵌入式系统中的内存映射区域,用于实现位带操作技术。

       在位带别名区中,每个比特(Bit)都被映射到一个真实的内存地址。通常,每个字节(Byte)的位带别名区域将比特和字节的内存地址相关联。这种映射关系使得可以使用普通的内存访问指令来对单个比特进行读取和写入操作。

(二)位带区与位带别名区的膨胀关系图如下

5.STM32F40x 位带操作内容及代码介绍_第1张图片

     

位带区与位带别名区的膨胀关系图A

5.STM32F40x 位带操作内容及代码介绍_第2张图片

位带区与位带别名区的膨胀关系图B

三、位带操作的优越性

  1. 原子性操作:位带操作可以实现对单个比特的原子性读取和写入。这意味着在多线

程或中断处理等并发环境下,不会出现竞争条件(Race condition)的问题。位带操作可以确保对比特的操作是稳定和可靠的。

  1. 简化代码:使用位带操作可以显著简化代码的编写。通过将比特映射到单独的内存

地址,可以使用常规的内存访问指令,而不需要通过位操作运算符和位操作指令来实现对特定位的访问和控制。这样可以降低代码的复杂性和维护成本。

  1. 提高效率:相比使用位操作指令和运算符来读取、修改和写入特定位,位带操作通

常更高效。这是因为位带操作可以直接读取和写入单个比特,而不需要对整个字节进行访问和操作。这降低了内存带宽的占用,并减少了 CPU 的计算和周期消耗。

  1. 可移植性:虽然位带操作的可用性和实现细节会依赖于具体的嵌入式系统和芯片型

号,但位带操作的概念和原理是相对通用的。这意味着一旦掌握了位带操作的基本知识和技巧,可以在不同的嵌入式平台上进行迁移和应用。

注意:位带操作不一定适用于所有的嵌入式系统和芯片。在使用位带操作时,应仔细阅读相关芯片的文档和手册,并了解具体的实现细节和使用方法。!!!!

四、IO口的位操作实现

  1. 位带操作简单的说,就是把每个比特膨胀为一个32位的字,当访问这些字的时候就达到了访问比特的目的,比如说GPIO的ODR寄存器有32个位,那么可以映射到32个地址上,我们去访问这32个地址就达到访问32个比特的目的。这样我们往某个地址写1就达到往对应比特位写1的目的,同样往某个地址写0就达到往对应的比特位写0的目的。位带操作映射图如下:

5.STM32F40x 位带操作内容及代码介绍_第3张图片

2.代码如下 

#ifndef __IO_BIT_H
#define __IO_BIT_H	 

#include "stm32f4xx.h"
#include 
#include 
#include 

#define BYTE0(dwTemp)       (*( char *) (&dwTemp))
#define BYTE1(dwTemp)       (*((char *) (&dwTemp) + 1))
#define BYTE2(dwTemp)       (*((char *) (&dwTemp) + 2))
#define BYTE3(dwTemp)       (*((char *) (&dwTemp) + 3))

//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<>第五章(87页~92页).
//IO口操作宏定义      //(addr & 0xF0000000)获得SRAM的地址或者外设地址
                      //0x2000000补偿,,基地址
                     //(addr &0xFFFFF) 我们只需要的到1M偏移
                     // <<5  地址膨胀*32
                     // (bitnum<<2)  写进去的偏移值(N)*4  4个字节
#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) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40011E08 
 
//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)  //输入


#endif

注意:所写的文章均用于记录作者的学习过程!!!!!

你可能感兴趣的:(STM32F40x,stm32,前端,javascript)