第13章 GPIO-位带操作—零死角玩转STM32-F429系列
第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-位带操作—零死角玩转STM32-F429系列的更多相关文章
- 第13章 GPIO—位带操作
第13章 GPIO—位带操作 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fire ...
- 第12章 GPIO输入-按键检测—零死角玩转STM32-F429系列
第12章 GPIO输入—按键检测 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fi ...
- GPIO—位带操作
GPIO—位带操作本章参考资料:< STM32F4xx 中文参考手册>存储器和总线构架章节. GPIO 章节,< Cortex®-M4 内核编程手册> 2.2.5 Bit-ba ...
- (stm32学习总结)—GPIO位带操作
本章参考资料:<STM32F10X-中文参考手册>存储器和总线构架章节.GPIO 章节,<CM3 权威指南 CnR2>存储器系统章节. 位带简介 位操作就是可以单独的对一个比特 ...
- 玩转X-CTR100 | STM32F4 l GPIO位带操作
更多塔克创新资讯欢迎登陆[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ] STM32F4位带概念,及位带的GPIO操作实践应用. 原理介 ...
- 第44章 MPU6050传感器—姿态检测—零死角玩转STM32-F429系列
第44章 MPU6050传感器—姿态检测 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.co ...
- 第42章 电源管理—实现低功耗—零死角玩转STM32-F429系列
第42章 电源管理—实现低功耗 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...
- GPIO位带操作点亮LED,且使用按键控制开关
1. 项目 类似与C51单片机的位操作使能引脚来点亮LED. 例如,sbit P0^0 = 0 LED1 = P0^0; 2. 代码 main.c #include "stm32f10x.h ...
- 第39章 ETH—Lwip以太网通信—零死角玩转STM32-F429系列
第39章 ETH—Lwip以太网通信 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...
随机推荐
- appium连接夜神模拟器方法总结
使用appium连接模拟器前提条件:appium环境已经搭建完毕,搭建步骤请参考我的博客:appium手机自动化环境搭建 1.下载并安装夜神模拟器:https://www.yeshen.com/ 2. ...
- Sqlite操作的一些关键类的官方说明与Intent的startactivityforresult方法
Intent: 该功能可以用于通过intent来跳转界面时候传递信号给原理的页面,以便做出一些处理: sqlite的使用: 该方法得到的sqlitedatabase可读可写,而getreadabled ...
- Emacs学习笔记1
Emacs笔记-Emacs基本的文本操作 使用命令时要在minibuffer缓冲区中 关于文件 注意 在对单词的操作中C开头的控制范围要比M开头的控制范围要下 对于文件的撤销操作, 不要使用C-x, ...
- 基础10 多进程、协程(multiprocessing、greenlet、gevent、gevent.monkey、select、selector)
1.多进程实现方式(类似于多线程) import multiprocessing import time,threading def thread_run():#定义一个线程函数 print(&quo ...
- c# 远程连接sql server 2008问题
http://hi.baidu.com/lzghxjt/item/d42bd8f7066a3ad86325d280 远程连接不上可以在防火墙新建入站规则
- 浅谈SQL Server中的三种物理连接操作(Nested Loop Join、Merge Join、Hash Join)
简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...
- SQLSERVER 2012的多维数据库浏览 ,不能多维的显示
网上搜索后发现,原来ssms2012不支持这种方式,要使用Excel的方式 参考地址:http://www.flybi.net/question/12567
- Spring-cloud微服务 Eureka学习教程-分布式搭建EurekaServer、EurekaClient(中级)
我们这里只有一台服务器,所以我们先仿集群搭建. 完整demo项目代码:https://github.com/wades2/EurekaDemo2 在这之前我们先分析分析Eureka相比其他注册中心的好 ...
- easyui datagrid 动态加载数据 渲染问题,表格错位问题
$('#dg').datagrid({ url:'datagrid_data.json', columns:[[ {field:'code',title:'Code',width:100}, {fie ...
- Apache Module mod_ssl
http://httpd.apache.org/docs/current/mod/mod_ssl.html Description: Strong cryptography using the Sec ...