首先:
#define BITBAND(addr,bitnum) ((addr & 0xF0000000) + 0x2000000 + ((addr & 0xFFFFF) << 5) + (bitnum << 2))
对上句程序的解释:
利用宏定义的方式将位带地址的映射表示出来,该函数有两个参数addr和bitnum,分别是原本的地址和在数据中的第几位。我们知道两个公式如下:
0x2000_0000‐0x200F_FFFF地址空间:AliasAddr = 0x22000000 + (A – 0x20000000)*32 + n*4
0x4000_0000‐0x400F_FFFF地址空间:AliasAddr = 0x42000000 + (A – 0x40000000)*32 + n*4
仔细观察我们可以发现,是有规律可寻的。两个公式的基地址一个是0x22000000,一个是0x42000000,他们只是最高位不一样,这个最高位和最原始的地址的最高位是一致的。所以我们通过 (addr & 0xF0000000) 来取最高位,再加上0x2000000就得到了公式中的基地址。我们知道两个地址空间中地址的变换只是在低5位上,比如0x2000_0000 — 0x200F_FFFF(有5个F),利用(A – 0x20000000)的目的是得到地址addr和0x2000_0000之间的偏移,也就是低5位的内容,所以我们通过 (addr & 0xFFFFF)得到了低5位的数据,也即是偏移量。公式中的乘以32,我们使用效率更高的左移5位,同理,之后的乘以4也是通过移位操作来实现的。
然后我们需要将上述地址转换为一个指针,也就是,我们要告诉编译器这是一个地址。
#define MEM_ADDR(addr) *((volatile unsigned long *) (addr))
其中使用到的volatile这个关键字是为了防止编译器进行优化。这是必须的。
完成上述两步之后,我们就可以使用位带操作了,比如我们要对GPIOA中的1管脚进行输出控制,我们需要控制GPIOA的ODR寄存器,通过手册我们知道它的地址是(GPIOA_BASE + 0x0C),所以我们定义:
#define GPIOA_ODR_Addr (GPIOA_BASE + 0x0C)
#define GPIOA(BitNum) MEM_ADDR( BITBAND(GPIOA_ODR_Addr,BitNum))
将GPIOA的1管脚置高,就可以这样写:
GPIOA(1) = 1;
同理,我们可以得到其他管脚控制的方法,或者获取其他管脚的输入。
以上,就是我对stm32的位带操作的实现的理解,有什么理解不到位的地方,请大家指证,希望和大家多多交流。
关键字:位带操作 stm32 C语言实现
引用地址:
位带操作在stm32中的C语言实现
推荐阅读最新更新时间:2024-03-16 14:57
STM32之DAC例程
#include stm32f10x.h /* RCC时钟配置 */ void RCC_config() { ErrorStatus HSEStartUpStatus; /* RCC寄存器设置为默认配置 */ RCC_DeInit(); /* 打开外部高速时钟 */ RCC_HSEConfig(RCC_HSE_ON); /* 等待外部高速时钟稳定 */ HSEStartUpStatus = RCC_WaitForHSEStartUp(); if(HSEStartUpStatus == SUCCESS) { /* 设置HCLK = SYSCLK */ RCC_HCLKConfig(RCC_SYSCL
[单片机]
stm32 的PA13,PA14, PA15做普通IO口的问题
这两天在玩oled屏,想用几个按键控制舵机,oled显示,于是把三个按键接到了PA13,14,15上发现没有任何反应后来一查手册发现有问题 可以看到PA13口的Main function是JTMS-SWDIO,不是PA13,所以要想使用PA13的普通IO口能力,就要先把IO口的复用功能打开,再把JTMS-SWDIO功能关掉就可以。 做输入,输出口都可以 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE); 再后来又发现了一个问题:就是单步调试的时候不能调试,
[单片机]
STM32系列第2篇--GPIO
STM32F103ZET6共有7组IO,每组有16个IO口,16×7=112,从GPIOA-GPIOG IO口标识带FT表示IO口可以接5V高电平 所有的IO口都可以直接作为中断输入 4种输入模式: 输入浮空 输入上拉 输入下拉 模拟输入(模拟电压转数字电压) 4种输出模式: 开漏输出 开漏复用功能 推挽输出 推挽复用功能 注:推挽输出可以输出强高低电平,开漏输出只能输出强低电平,输出强高电平需要外接上拉电阻。 7个寄存器: 两个32位配置寄存器(GPIOx_CRL,GPIOx_CRH) 两个32位数据寄存器(GPIOx_IDR和GPIOx_ODR) 一个32位置位/ 复位寄存器(GPIOx_BSR
[单片机]
使用STM32简单控制TMC5160驱动步进电机
首先先来了解一下TMC5160的3种工作模式 TMC5160通过两个引脚来控制它的工作模式: SD _MODE和S PI _MODE。 1、当SD_MODE接地,SPI_MODE拉高,TMC5160即工作在模式1(SPI控制模式)。在该模式下,用户通过SPI接口来设置TMC5160的 寄存器 。 TMC5160使用自己的梯形曲线发生器来控制 步进电机 转动,用户需要设置:开始运动速度VSTART、第一段折线末速度V1、最大速度VMAX、停止速度VSTOP、第一段折线的加速度A1、第二段折线加速度AMAX、第四段折线的减速度 DMA X、第五段折线的减速度D1。把上面的参数设置好,再设置工作模式:速度模式和位置模式。最后再设置
[单片机]
STM32单片机-增量式PID
一、什么是增量式PID 虽然PID不是什么牛逼的东西,但是真心希望以后刚刚接触这块的人能尽快进入状态。特地分享一些自己如何实现的过程。 PID控制算法介绍与C程序实现 首先说说增量式PID的公式,这个关系到MCU算法公式的书写,实际上两个公式的写法是同一个公式变换来的,不同的是系数的差异。 【教程】如何在STM32上实现增量式PID - STM32/STM8技术论坛 - 电子技术论坛 - 广受欢迎的专业电子论坛! 资料上比较多的是: 还有一种的算法是: 这里主要介绍第二种,具体会分析比例、积分、微分三个环节的作用。 ----------------------------------------------
[单片机]
寒假学习之stm32(16)----IIC通信协议
背景知识: https://zh.wikipedia.org/wiki/I%C2%B2C stm32中的IIC描述: I2C功能描述: I2C模块接收和发送数据,并将数据从串行转换成并行,或并行转换成串行。可以开启或禁止中断。接口通过数据引脚(SDA)和时钟引脚(SCL)连接到I2C总线。允许连接到标准(高达100kHz)或快速(高达400kHz)的I2C总线 模式选择 默认情况下,I2C接口总是工作在从模式。从从模式切换到主模式,需要产生一个起始条件。 接口可以下述4种模式中的一种运行: ● 从发送器模式 ● 从接收器模式 ● 主发送器模式 ● 主接收器模式 该模块默认地工作于从模式。接口在生成起始条件后自动地从从模
[单片机]
stm32 AD模数转换[操作寄存器+库函数]
stm32f103最少有2个AD模数转换器,每个ADC都有18个通道,可以测量16个外部和2个内部模拟量。最大转换频率为1Mhz,也就是转换时间为1us(在 ADCCLK = 14Mhz,采样周期为1.5个时钟周期时)。最大时钟超过14Mhz,将导致ADC转换准确度降低。stm32的ADC是12位精度的。 stm32的ADC转换有两种通道,规则通道和注入通道,注入通道可以抢占式地打断规则通道的采样,执行注入通道采样后,再执行之前的规则通道采样,和中断类似。本例只使用规则通道实现独立模式的中断采样,这里不再赘述两种通道区别。 stm32的ADC可以由外部事件触发(例如定时器捕获,EXTI线)和软件触发(即在配置相关寄存器时,
[单片机]
全面掌握stm32的GPIO知识
1 初学者重要提示 本文主要是以stm32H7系列为主。 对于不使用的引脚,推荐设置为模拟模式,悬空即可。 GPIO的速度等级高的时候,最好使能IO补偿单元。 2 GPIO功能简介 STM32H7的GPIO特性如下: 输出状态:开漏/推挽 + 上拉/下拉电阻。 通过输出数据寄存器(GPIOx_ODR)或者外设(GPIO设置为复用模式时)输出数据。 GPIO速度等级设置。 输入状态:浮空,上拉/下拉,模拟。 通过输入数据寄存器(GPIOx_IDR)或者外设(GPIO设置为复用模式)输入数据。 通过寄存器GPIOx_BSRR实现对寄存器GPIOx_ODR的位操作。 通过配置寄存器GPIOx_LCKR的锁机制,实现冻结IO口配置。 每两
[单片机]