第13章     GPIO—位带操作

全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn

野火视频教程优酷观看网址:http://i.youku.com/firege

本章参考资料:《STM32F4xx 中文参考手册》存储器和总线构架章节、GPIO章节,《Cortex®-M4内核编程手册》2.2.5 Bit-banding。学习本章时,配套这些参考资料学习效果会更佳。

13.1 位带简介

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

在F429中,有两个地方实现了位带,一个是SRAM区的最低1MB空间,另一个是外设区最低1MB空间。这两个1MB的空间除了可以像正常的RAM一样操作外,他们还有自己的位带别名区,位带别名区把这1MB的空间的每一个位膨胀成一个32位的字,当访问位带别名区的这些字时,就可以达到访问位带区某个比特位的目的。

图 131 F429位带地址

13.1.1 外设位带区

外设位带区的地址为:0X40000000~0X400F0000,大小为1MB,这1MB的大小包含了APB1/2和AHB1上所以外设的寄存器,AHB2/3总线上的寄存器没有包括。AHB2总线上的外设地址范围为:0X50000000~0X50060BFF,AHB3总线上的外设地址范围为:0XA0000000~0XA0000FFF。外设位带区经过膨胀后的位带别名区地址为:0X42000000~0X43FFFFFF,这部分地址空间为保留地址,没有跟任何的外设地址重合。

13.1.2 SRAM位带区

SRAM的位带区的地址为:0X2000 0000~X200F 0000,大小为1MB,经过膨胀后的位带别名区地址为:0X2200 0000~0X23FF FFFF,大小为32MB。操作SRAM的比特位这个用得很少。

13.1.3 位带区和位带别名区地址转换

位带区的一个比特位经过膨胀之后,虽然变大到4个字节,但是还是LSB才有效。有人会问这不是浪费空间吗,要知道F429的系统总线是32位的,按照4个字节访问的时候是最快的,所以膨胀成4个字节来访问是最高效的。

我们可以通过指针的形式访问位带别名区地址从而达到操作位带区比特位的效果。那这两个地址直接如何转换,我们简单介绍一下。

1.    外设位带别名区地址

对于片上外设位带区的某个比特,记它所在字节的地址为 A,位序号为 n(0<=n<=7),则该比特在别名区的地址为:

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

			

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

2.    SRAM位带别名区地址

对于SRAM位带区的某个比特,记它所在字节的地址为 A,位序号为 n(0<=n<=7),则该比特在别名区的地址为:

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

			

公式分析同上。

3.    统一公式

为了方便操作,我们可以把这两个公式合并成一个公式,把"位带地址+位序号"转换成别名区地址统一成一个宏。

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

addr & 0xF0000000是为了区别SRAM还是外设,实际效果就是取出4或者2,如果是外设,则取出的是4,+0X02000000之后就等于0X42000000,0X42000000是外设别名区的起始地址。如果是SRAM,则取出的是2,+0X02000000之后就等于0X22000000,0X22000000是SRAM别名区的起始地址。

addr & 0x00FFFFFF 屏蔽了高三位,相当于减去0X20000000或者0X40000000,但是为什么是屏蔽高三位?因为外设的最高地址是:0X2010 0000,跟起始地址0X20000000相减的时候,总是低5位才有效,所以干脆就把高三位屏蔽掉来达到减去起始地址的效果,具体屏蔽掉多少位跟最高地址有关。SRAM同理分析即可。<<5相当于*8*4,<<2相当于*4,这两个我们在上面分析过。

最后我们就可以通过指针的形式操作这些位带别名区地址,最终实现位带区的比特位操作。

 1 // 把一个地址转换成一个指针
			
 2 #define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))
				
 3
			
 4 // 把位带别名区地址转换成指针
			
 5 #define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))

13.2 GPIO位带操作

外设的位带区,覆盖了全部的片上外设的寄存器,我们可以通过宏为每个寄存器的位都定义一个位带别名地址,从而实现位操作。但这个在实际项目中不是很现实,也很少人会这么做,我们在这里仅仅演示下GPIO中ODR和IDR这两个寄存器的位操作。

从手册中我们可以知道ODR和IDR这两个寄存器对应GPIO基址的偏移是20和16,我们先实现这两个寄存器的地址映射,其中GPIOx_BASE在库函数里面有定义。

1.    GPIO 寄存器映射

代码 9 GPIO ODR 和 IDR 寄存器映射

1 // GPIO ODR 和 IDR 寄存器地址映射

 2 #define GPIOA_ODR_Addr    (GPIOA_BASE+20)
				
 3 #define GPIOB_ODR_Addr    (GPIOB_BASE+20)
				
 4 #define GPIOC_ODR_Addr    (GPIOC_BASE+20)
				
 5 #define GPIOD_ODR_Addr    (GPIOD_BASE+20)
				
 6 #define GPIOE_ODR_Addr    (GPIOE_BASE+20)
				
 7 #define GPIOF_ODR_Addr    (GPIOF_BASE+20)
				
 8 #define GPIOG_ODR_Addr    (GPIOG_BASE+20)
				
 9 #define GPIOH_ODR_Addr    (GPIOH_BASE+20)
				
10 #define GPIOI_ODR_Addr    (GPIOI_BASE+20)
				
11 #define GPIOJ_ODR_Addr    (GPIOJ_BASE+20)
				
12 #define GPIOK_ODR_Addr    (GPIOK_BASE+20)
				
13
			
14 #define GPIOA_IDR_Addr    (GPIOA_BASE+16)
				
15 #define GPIOB_IDR_Addr    (GPIOB_BASE+16)
				
16 #define GPIOC_IDR_Addr    (GPIOC_BASE+16)
				
17 #define GPIOD_IDR_Addr    (GPIOD_BASE+16)
				
18 #define GPIOE_IDR_Addr    (GPIOE_BASE+16)
				
19 #define GPIOF_IDR_Addr    (GPIOF_BASE+16)
				
20 #define GPIOG_IDR_Addr    (GPIOG_BASE+16)
				
21 #define GPIOH_IDR_Addr    (GPIOH_BASE+16)
				
22 #define GPIOI_IDR_Addr    (GPIOI_BASE+16)
				
23 #define GPIOJ_IDR_Addr    (GPIOJ_BASE+16)
				
24 #define GPIOK_IDR_Addr    (GPIOK_BASE+16)

			

现在我们就可以用位操作的方法来控制GPIO的输入和输出了,其中宏参数n表示具体是哪一个IO口,n(0,1,2...16)。这里面包含了端口A~K ,并不是每个单片机型号都有这么多端口,使用这部分代码时,要查看你的单片机型号,如果是176pin的则最多只能使用到I端口。

2.    GPIO位操作

代码 10 GPIO 输入输出位操作

 1 // 单独操作 GPIO的某一个IO口,n(0,1,2...16),n表示具体是哪一个IO口
				
 2 #define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)
									//输出
				
 3 #define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)
									//输入
				
 4
			
 5 #define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)
									//输出
				
 6 #define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)
									//输入
				
 7
			
 8 #define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)
									//输出
				
 9 #define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)
									//输入
				
10
			
11 #define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)
									//输出
				
12 #define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)
									//输入
				
13
			
14 #define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)
									//输出
				
15 #define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)
									//输入
				
16
			
17 #define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)
									//输出
				
18 #define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)
									//输入
				
19
			
20 #define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)
									//输出
				
21 #define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)
									//输入
				
22
			
23 #define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)
									//输出
				
24 #define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)
									//输入
				
25
			
26 #define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)
									//输出
				
27 #define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)
									//输入
				
28
			
29 #define PJout(n)   BIT_ADDR(GPIOJ_ODR_Addr,n)
									//输出
				
30 #define PJin(n)    BIT_ADDR(GPIOJ_IDR_Addr,n)
									//输入
				
31
			
32 #define PKout(n)   BIT_ADDR(GPIOK_ODR_Addr,n)
									//输出
				
33 #define PKin(n)    BIT_ADDR(GPIOK_IDR_Addr,n)
									//输入

				
3.    主函数

该工程我们直接从LED-库函数操作移植过来,有关LED GPIO 初始化和软件延时等函数我们直接用,修改的是控制GPIO输出的部分改成了位操作。该实验我们让相应的IO口输出高低电平来控制LED的亮灭,负逻辑点亮。具体使用哪一个IO和点亮方式由硬件平台决定。

代码 11 main 函数

 1 int main(void)
				
 2 {
				
 3
								/* LED 端口初始化 */
				
 4     LED_GPIO_Config();
				
 5
			
 6
							while (1) {
				
 7
								// PH10 = 0,点亮LED
				
 8         PHout(10)= 0;
				
 9         SOFT_Delay(0x0FFFFF);
				
10
			
11
								// PH10 = 1,熄灭LED
				
12         PHout(10)= 1;
				
13         SOFT_Delay(0x0FFFFF);
				
14     }
				
15
			
16 }

			

13.3 每课一问

1、利用位带操作的方法,写一个GPIO输入的例程,比如按键采集。

2、如果使用的不是GPIO这个外设,而是其他的外设,那么公式该怎么改,比如要使用的外设是ADC。

开源共享,共同进步。

第13章 GPIO—位带操作的更多相关文章

  1. (stm32学习总结)—GPIO位带操作

    本章参考资料:<STM32F10X-中文参考手册>存储器和总线构架章节.GPIO 章节,<CM3 权威指南 CnR2>存储器系统章节. 位带简介 位操作就是可以单独的对一个比特 ...

  2. GPIO—位带操作

    GPIO—位带操作本章参考资料:< STM32F4xx 中文参考手册>存储器和总线构架章节. GPIO 章节,< Cortex®-M4 内核编程手册> 2.2.5 Bit-ba ...

  3. 玩转X-CTR100 | STM32F4 l GPIO位带操作

    更多塔克创新资讯欢迎登陆[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ]       STM32F4位带概念,及位带的GPIO操作实践应用. 原理介 ...

  4. GPIO位带操作点亮LED,且使用按键控制开关

    1. 项目 类似与C51单片机的位操作使能引脚来点亮LED. 例如,sbit P0^0 = 0 LED1 = P0^0; 2. 代码 main.c #include "stm32f10x.h ...

  5. 玩转X-CTR100 l STM32F4 l 基础例程printf、LED、蜂鸣器、拨码开关、位带操作

    我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ]      本文介绍X-CTR100控制器基础板载资源 ...

  6. STM32之GPIO端口位带操作

    #ifndef __SYS_H #define __SYS_H #include "stm32f10x.h" //位带操作 //把“位带地址+位序号”转换别名地址宏 #define ...

  7. 位带操作—GPIO输出和输入

    GPIOC->ODR |=(0<<2);  // 总线操作,即操作整个寄存器. 在51单片机中 P0=0xFE;   //总线操作. sbit LED1=P0^0;  //位操作,即 ...

  8. STM32F030系列实现仿位带操作

    1.闲言 最近开发的时候,用到了STM32F030F4P6型号的单片机,它只有20个引脚,价格非常便宜,但是功能齐全:定时器.外部中断.串口.IIC.SPI.DMA和WWDG等等,应用尽有,非常适合用 ...

  9. STM32位带操作总结---浅显易懂

    正在准备做毕业设计,配置LED_Config()的时候,又看到了位带操作的宏定义,我又嘀咕了,什么是位带操作,一年前在使用位带操作的时候,就查阅过好多资料,Core-M3也看过,但是对于博主这种“低能 ...

随机推荐

  1. layui点击弹框页面 表单请求

    $("#addSite").click(function () { layer.open({ title: '添加站点', type: 1, area: ['700px', '40 ...

  2. BZOJ2707: [SDOI2012]走迷宫(期望 tarjan 高斯消元)

    题意 题目链接 Sol 设\(f[i]\)表示从\(i\)走到\(T\)的期望步数 显然有\(f[x] = \sum_{y} \frac{f[y]}{deg[x]} + 1\) 证明可以用全期望公式. ...

  3. 如何将水晶报表(Crystal Report)导入葡萄城报表

    当从旧的报表平台迁移到葡萄城报表工具时,意味着有大量的报表设计工作要重复去做,如果有一款工具能够在这些工具之间进行自由转换,就能省去报表开发几乎一半的工作量. 葡萄城报表为兼容其他报表控件,提供了简单 ...

  4. 【Redis】Redis学习(二) master/slave、sentinel、Cluster简单总结

    项目中用到Redis,所以准备学习一下,感觉Redis的概念还是很多的,什么主从模式.sentinel模式.集群模式的,一下子都晕了,我觉得还是有必要先理清这些基本概念再说. 一.单节点实例 单节点实 ...

  5. [随时更新] Git的过滤规则 .gitignore 配置

    往github上传代码的时候,很多文件没必要都传,这就需要在.gitignore文件里配置一下过滤规则.在此记录一下各种项目的配置参数,先从最近做的android开始. 原文地址请保留http://w ...

  6. 如何借助 NoSQL 提高 JPA 应用性能

    [编者按]关注 NoSQL 的动态发展很重要.NoSQL 的好处并不仅限于新的应用开发.在某些案例中,你可以见识到重新访问现有的.传统的框架带来的积极效果,比如说你的 JPA 的实现.本文系国内 IT ...

  7. Python之Pandas知识点

    很多人都分不清Numpy,Scipy,pandas三个库的区别. 在这里简单分别一下: NumPy:数学计算库,以矩阵为基础的数学计算模块,包括基本的四则运行,方程式以及其他方面的计算什么的,纯数学: ...

  8. 前端开发使用Photoshop切图详细步骤

    切图的主要目的是从设计师提供的psd中获取网页制作所要的资源 一.界面设置 1. 新建文件,调整界面大小,背景设置为透明 2. 自动选择,把组切换为图层 3. 添加窗口内容,一共四项:图层.历史纪录. ...

  9. continue break exit用法说明

    1,continue用法 2,break用法 3,sys.exit用法 1,continue用法(跳出本次循环,继续下次循环) for i in xrange(10): if i == 8: cont ...

  10. SQL Server Management Studio记住的密码丢失的问题

    不知道各位经常使用SSMS的时候有没有碰到过这样的烦恼: 记住的密码总是丢失: 步骤如下: 登陆时,选择记住密码 在任何一个存储过程上点击右键,选择修改 这时候再次连接对象资源管理器时,刚刚记住的密码 ...