IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32F429入门(十一):位带操作 -> 正文阅读

[嵌入式]STM32F429入门(十一):位带操作

什么是位带操作?

首先联系熟悉的51单片机,还记得之前很熟悉的点亮led灯的操作:

sbit LED = P0^0;
LED = 0;  
P0 = 0xFE;  //一个io口控制8个口,这种操作叫做总线操作
P0^0 = 0;   //设置单个io口,这种叫做位操作

//stm32单片机
GPIOH_ODR &= ~(1<<10);  //总线操作
//stm32没有与51相同的sbit这类写法,不可以通过sbit选中一个端口而去操作它

????????位操作就是可以单独的对一个比特位读和写,这个在 51 单片机中非常常见。51 单片机中通过关键字 sbit 来实现位定义,F429 中没有这样的关键字,而是通过访问位带别名区来实现。

??? ?在 F429 中,有两个地方实现了位带,一个是 SRAM 区的最低 1MB 空间,另一个是外设区最低 1MB 空间。这两个 1MB 的空间除了可以像正常的 RAM 一样操作外,他们还有自己的位带别名区,位带别名区把这 1MB 的空间的每一个位膨胀成一个 32 位的字,当访 问位带别名区的这些字时,就可以达到访问位带区某个比特位的目的。也就是说,下面蓝色的部分可进行位带操作,而绿色的部分则不可以,而操作SRAM比特位的用得很少。

?

那要如何访问呢?可以通过指针的形式访问**位带别名区地址**从而达到操作位带区比特位的效果。那 这两个地址直接如何转换。

?外设位带别名区地址: AliasAddr = ?0x42000000 + ?(A-0x40000000) * 8 * 4 +n*4?

0X42000000 是外设位带别名区的起始地址,0x40000000 是外设位带区的起始地址, (A-0x40000000)表示该比特前面有多少个字节,相当于 偏移 ,一个字节有 8 位,所以* 8,一个位膨胀后是 4 个字节,所以* 4,n 表示该比特在 A 地址的序号,因为一个位经过膨胀后是四个字节,所以也*4。

?SRAM位带别名区地址:AliasAddr = 0x22000000+ (A-0x20000000) * 8 * 4 +n*4?

我们将以上两个地址统一地址:

?((addr & 0xF0000000)+0x02000000+((addr & 0x000FFFFF)<<5)+(bitnum<<2))?

addr:要操作的位所在寄存器的地址,也就是我们之前在第二篇文章中所提及到的外设基地址+偏移地址

bitnum:位号,即在寄存器的第几位。

我们将公式进行解析:

addr & 0xF0000000:目的是取出4和2,用于区分是外设还是SRAM。然后再加上0x02000000就等于外设/SRAM位带别名区的起始地址。

addr &0x000FFFFF?:屏蔽掉高3位。外设位带区的最高地址为0X400F 0000,SRAM位带区的最高地址为 0X200F 0000,(0X400F 0000 – 0X4000 0000)与(0x200F 0000 – 0X2000 0000)在求偏移地址相减的时候只有低5位有效,所以就把剩下的高三位屏蔽掉,剩下的5位与F做与运算即可,左移是乘以32。

那我们现在就以操作GPIO为例,来理解这个位带操作,同样,我们来点亮led灯:

//SRAM 位带区:      0X2000 0000~0X200F 0000
//SRAM 位带别名区:   0X2200 0000~0X23FF FFFF

//外设 位带区:    0X4000 0000~0X400F FFFF
//外设 位带别名区:0X4200 0000~0X43FF FFFF

#define GPIOH_ODR_ADDR 		(GPIOH_BASE+0X14)

// 把“位带地址+位序号”转换成别名地址的宏
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0x000FFFFF)<<5)+(bitnum<<2)) 

// 把一个地址转换成一个指针
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))

// 把位带别名区地址转换成指针
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 

int main()
{
    LED_GPIO_Config();
    
    BIT_ADDR(GPIOH_ODR_ADDR,10) = 0;
}

为了使程序更加方便操作,我们可以将程序进行以下梳理:

// GPIO ODR 和 IDR 寄存器地址映射 
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) 
#define GPIOB_ODR_Addr    (GPIOB_BASE+20)   
#define GPIOC_ODR_Addr    (GPIOC_BASE+20)  
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20)      
#define GPIOG_ODR_Addr    (GPIOG_BASE+20)
#define GPIOH_ODR_Addr    (GPIOH_BASE+20)      
#define GPIOI_ODR_Addr    (GPIOI_BASE+20)
#define GPIOJ_ODR_Addr    (GPIOJ_BASE+20)      
#define GPIOK_ODR_Addr    (GPIOK_BASE+20)

#define GPIOA_IDR_Addr    (GPIOA_BASE+16)  
#define GPIOB_IDR_Addr    (GPIOB_BASE+16)  
#define GPIOC_IDR_Addr    (GPIOC_BASE+16)   
#define GPIOD_IDR_Addr    (GPIOD_BASE+16)  
#define GPIOE_IDR_Addr    (GPIOE_BASE+16)    
#define GPIOF_IDR_Addr    (GPIOF_BASE+16)    
#define GPIOG_IDR_Addr    (GPIOG_BASE+16)  
#define GPIOH_IDR_Addr    (GPIOH_BASE+16)
#define GPIOI_IDR_Addr    (GPIOI_BASE+16)
#define GPIOJ_IDR_Addr    (GPIOJ_BASE+16)
#define GPIOK_IDR_Addr    (GPIOK_BASE+16)


// 单独操作 GPIO的某一个IO口,n(0,1,2...16),n表示具体是哪一个IO口
#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)  //输入 

#define PJout(n)   BIT_ADDR(GPIOJ_ODR_Addr,n)  //输出   
#define PJin(n)    BIT_ADDR(GPIOJ_IDR_Addr,n)  //输入  

#define PKout(n)   BIT_ADDR(GPIOK_ODR_Addr,n)  //输出   
#define PKin(n)    BIT_ADDR(GPIOK_IDR_Addr,n)  //输入  

那么今天的位带学习就到这啦,明天就可以从入门到初级了!!

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-13 09:25:42  更:2021-09-13 09:25:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 2:54:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码