当前位置: 首页 > news >正文

STM32位带操作理论实践

文章目录

  • 理论基础
      • 1. 左移运算与乘法的关系
      • 2. STM32位带操作理论整理
        • (1)位带区与位带别名区的划分
        • (2)位带地址映射原理
        • (3)图片中宏定义解析
        • (4)位带操作的作用
  • 代码实现
      • `bitband.h`(位带操作核心头文件)
      • `led.c`(基于位带操作的LED驱动示例)
      • `main.c`(主函数应用示例)
      • 代码说明与使用注意事项:

理论基础

1. 左移运算与乘法的关系

在二进制数中,左移( n )位等价于乘以( 2^n )

  • 左移2位(<<2):( 2^2 = 4 ),因此a << 2等价于a × 4
  • 左移5位(<<5):( 2^5 = 32 ),因此a << 5等价于a × 32

2. STM32位带操作理论整理

STM32的位带操作是一种对单个比特位进行独立读写的机制,通过“位带区”与“位带别名区”的映射关系实现。

(1)位带区与位带别名区的划分
区域类型位带区地址范围位带别名区地址范围
SRAM位带区0x20000000 - 0x200FFFFF(1MB SRAM)0x22000000 - 0x23FFFFFF
外设位带区0x40000000 - 0x400FFFFF(部分外设寄存器)0x42000000 - 0x43FFFFFF
(2)位带地址映射原理

对于位带区中某一位(地址为addr,位编号为bitnum),其在位带别名区的地址计算公式为:
别名地址=位带别名区基地址+(位带区内字节偏移量×32)+(位编号×4)

  • 位带区内字节偏移量:addr - 位带区基地址(即addr相对于位带区起始地址的偏移字节数)。
  • ×32(即<<5):每个字节对应位带别名区的32个地址(8位×4),因此字节偏移量需左移5位(乘以32)。
  • ×4(即<<2):每个位对应4个地址空间,因此位编号需左移2位(乘以4)。
(3)图片中宏定义解析
  • BITBAND(addr, bitnum):用于计算位带别名区地址。
    • addr & 0xF0000000:区分SRAM位带区(0x20000000开头)或外设位带区(0x40000000开头)。
    • + 0x20000000:计算位带别名区基地址(SRAM别名区基地址为0x22000000,外设为0x42000000)。
    • (addr & 0xFFFFF) << 5:获取位带区内字节偏移量,左移5位(乘以32)。
    • (bitnum << 2):位编号左移2位(乘以4)。
  • MEM_ADDR(addr):将地址转换为volatile unsigned long *类型,用于直接访问内存(或寄存器),保证操作的原子性与实时性。
(4)位带操作的作用

通过位带操作,可用普通内存访问指令(如赋值)实现单个比特位的置1、清0或读取,简化了GPIO、外设寄存器等单个位的操作,提升代码可读性与执行效率(无需“读-改-写”整字节)

以下是基于STM32位带操作的完整实用代码,包含核心宏定义、GPIO位操作封装及实际应用示例(以STM32F1系列为例,其他系列可参考修改基地址),可直接用于开发:

代码实现

bitband.h(位带操作核心头文件)

#ifndef __BITBAND_H
#define __BITBAND_H#include "stm32f1xx.h"  // 根据根据实际芯片型号修改(如stm32f4xx.h)// 1. 位带区与位带别名区基地址定义
#define SRAM_BASE        0x20000000UL  // SRAM位带区基地址
#define SRAM_BB_BASE     0x22000000UL  // SRAM位带别名区基地址
#define PERIPH_BASE      0x40000000UL  // 外设位带区基地址
#define PERIPH_BB_BASE   0x42000000UL  // 外设位带别名区基地址// 2. 位带地址计算宏(核心)
// 功能:计算位带区中某一位在别名区的地址
// 参数:addr-位带区地址(如GPIO寄存器地址);bitnum-位编号(0~7)
#define BITBAND(addr, bitnum) ( \(addr & 0xF0000000UL) == 0x40000000UL ? /* 区分外设/SRAM位带区 */ \(PERIPH_BB_BASE + ((addr - PERIPH_BASE) << 5) + (bitnum << 2)) : \(SRAM_BB_BASE + ((addr - SRAM_BASE) << 5) + (bitnum << 2)) \
)// 3. 地址转指针宏(用于直接读写位带别名区)
// 功能:将别名区地址转换为volatile指针,确保内存操作不被编译器优化
#define MEM_ADDR(addr) (*(volatile uint32_t *)(addr))// 4. GPIO位操作封装(直接操作单个IO口,无需"读-改-写")
// 外设位带区包含GPIO寄存器,以GPIOx_ODR(输出数据寄存器)为例:
// 置位宏:GPIO_BSET(GPIOx, pin)  ->  置位GPIOx的pin脚
// 清零宏:GPIO_BCLR(GPIOx, pin)  ->  清零GPIOx的pin脚
// 读取宏:GPIO_BVAL(GPIOx, pin)  ->  读取GPIOx的pin脚电平
#define GPIO_BSET(GPIOx, pin) MEM_ADDR(BITBAND(&GPIOx->ODR, pin)) = 1
#define GPIO_BCLR(GPIOx, pin) MEM_ADDR(BITBAND(&GPIOx->ODR, pin)) = 0
#define GPIO_BVAL(GPIOx, pin) MEM_ADDR(BITBAND(&GPIOx->IDR, pin))#endif

led.c(基于位带操作的LED驱动示例)

#include "bitband.h"
#include "stm32f1xx_hal.h"  // 使用HAL库初始化GPIO(也可替换为标准库)// LED硬件定义:PA5引脚接LED(低电平点亮)
#define LED_GPIO_PORT    GPIOA
#define LED_GPIO_PIN     5// LED初始化函数
void LED_Init(void) {GPIO_InitTypeDef GPIO_InitStruct = {0};// 使能GPIOA时钟__HAL_RCC_GPIOA_CLK_ENABLE();// 配置PA5为推挽输出GPIO_InitStruct.Pin = LED_GPIO_PIN;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;  // 推挽输出GPIO_InitStruct.Pull = GPIO_NOPULL;          // 无上下拉GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速HAL_GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct);// 初始状态:LED熄灭(PA5置高)GPIO_BSET(LED_GPIO_PORT, LED_GPIO_PIN);
}// LED翻转函数(基于位带操作)
void LED_Toggle(void) {// 读取当前电平并翻转(无需操作整个ODR寄存器,仅操作单个位)if (GPIO_BVAL(LED_GPIO_PORT, LED_GPIO_PIN)) {GPIO_BCLR(LED_GPIO_PORT, LED_GPIO_PIN);  // 若为高,则置低(点亮)} else {GPIO_BSET(LED_GPIO_PORT, LED_GPIO_PIN);  // 若为低,则置高(熄灭)}
}

main.c(主函数应用示例)

#include "bitband.h"
#include "led.h"
#include "stm32f1xx_hal.h"void SystemClock_Config(void);  // 系统时钟配置(根据实际硬件实现)int main(void) {// 初始化HAL库HAL_Init();// 配置系统时钟(例如72MHz)SystemClock_Config();// 初始化LEDLED_Init();// 主循环:LED闪烁(间隔500ms)while (1) {LED_Toggle();HAL_Delay(500);  // 延时500ms}
}// 系统时钟配置示例(STM32F103C8T6参考)
void SystemClock_Config(void) {RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};// 配置HSE(外部高速时钟)为8MHz,PLL倍频至72MHzRCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;HAL_RCC_OscConfig(&RCC_OscInitStruct);// 配置系统时钟源为PLL,AHB=72MHz,APB1=36MHz,APB2=72MHzRCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}

代码说明与使用注意事项:

  1. 兼容性:代码基于STM32F1系列,其他系列(如F4、L0)需修改stm32xxxx.h头文件,位带区基地址与F1一致,可直接复用。

  2. 核心优势

    • 位带操作通过宏定义(而非库函数)直接操作寄存器位,执行效率远高于HAL_GPIO_WritePin等库函数(无需“读-改-写”整字节)。
    • 宏定义GPIO_BSET/GPIO_BCLR/GPIO_BVAL可直接用于任何GPIO引脚,无需单独编写驱动。
  3. 扩展使用

    • 除GPIO外,位带操作可用于其他外设寄存器(如定时器、UART的控制位),例如通过BITBAND(&TIM2->CR1, 0)直接操作TIM2的CEN位(计数器使能)。
    • 可扩展到SRAM位带操作(例如操作全局变量的某一位),用法类似。
  4. 编译注意:确保编译器开启“volatile”优化(默认开启),避免位操作被编译器优化失效。

该代码可直接集成到STM32工程中,通过位带操作实现高效的GPIO控制,适合对实时性要求较高的场景(如高频IO翻转、快速外设控制)。

http://www.dtcms.com/a/557192.html

相关文章:

  • 住房和城乡建设部的网站首页不懂网站怎么做平台
  • 禁止Windows 10升级至Windows 11的方法
  • 人工智能之数学基础:随机变量函数的分布(离散和连续)
  • 30.16.2.表现层框架设计
  • DMS 迁移错误:String Length Exceeds DDL Length 完整解决方案
  • 福建建设厅网站官网宣传推广方案
  • 网站搭建的步骤百度网站怎样做
  • 网站的建设与开发discover wordpress
  • apk反编译修改教程系列-----读懂 Android 签名机制:从 V1 到 V4的签名区别
  • 人工智能本体论!
  • 将Git项目的所有远程分支打包成压缩包文件
  • 做液压的公司网站佛山网站建设格式有哪些
  • 深圳做微商网站的公司二维码生成器app
  • WebClient发送请求示例
  • Wireshark TS | 接收数据超出接收窗口续
  • mapset的使用
  • 要事优先-深耕目标
  • 禄劝彝族苗族网站建设食品 技术支持 东莞网站建设
  • 宁波市省网站建设济南工程建设交易信息网
  • 伯克利哈斯商学院的金融工程硕士(MFE)
  • 政安晨【零基础玩转开源AI项目】video-subtitle-remover 去除视频字幕水印(图像也可以)(基于Ubuntu Linux系统)
  • 温州市名城建设集团有限公司网站二级域名如何申请
  • 【C++】模拟算法习题
  • QLoRA基础知识和微调原理学习
  • 在 vscode 中配置juypter notebook 插件
  • 石家庄好用的招聘网站门户网站网站建设
  • ENERGY Designer:重构跨平台GUI开发的高效解决方案
  • 网站建设要准备什么资料wordpress回复下载
  • RabbitMQ 在拼团系统中的应用:延迟队列、订单超时与消息幂等
  • 【printpdf】color.rs 文件解析