《GPIO那点事》

GPIO

- 基于8086指令集的51单片机

51单片机有4个双向并行IO口:P0、P1、P2、P3

  • P0为三态双向口,其驱动能力比较大,可驱动高达8个TTL电路
  • P1、P2、P3为准双向口,其负载能力比较低,只能驱动4个TTL电路

PS:作为输入时,IO总线需要被拉成高电平,故称准双向口

- 基于ARM cortex M3 的STM32单片机

当单片机类型从8位升级到32位之后,51的io口寄存器驱动方法就不再适合32系列的单片机,ARM便采用GPIO的形式驱动io口。

General Purpose Input Output (通用输入/输出接口)简称为GPIO,或总线扩展器,人们利用工业标准I2C、SMBus或SPI接口简化了I/O口的扩展。当微控制器或芯片组没有足够的I/O端口,或当系统需要采用串行通信或控制时,GPIO产品能够提供额外的控制和监视功能。

STM32 的 IO 口相比 51 而言要复杂得多,所以使用起来也困难很多。首先 STM32 的 IO 口 可以由软件配置成如下 8 种模式:

  1. 输入浮空 IN_FLOATING
  2. 输入上拉 IPU
  3. 输入下拉 IPD
  4. 模拟输入 AIN
  5. 开漏输出 OD
  6. 推挽输出 PP
  7. 推挽式复用功能 AF_PP
  8. 开漏复用功能AF_OD

一般常用的就是PP、IPU和IPD,AF_PP用在复用gpio的功能上,stm32的每个io口都是可以自由编程的,但每一个io口寄存器都是要32位访问,这里就带来了和51完全不同的操作方式,因为八个位是一个一个,对于16进制来说,就是四位。也就是没操作一次io口,用寄存器的方法配置输出模式:


IO寄存器.png

但是对于嵌入式开发来说,如此庞大的寄存器配置,无疑对工程师来说是负担。所以st专门开发了标准库SPL、硬件抽象层库HAL和底层库LL。
其中的LL是兼容SPL和HAL的,所以最新推出,原因是HAL库对于大部分32芯片是完全兼容的,但是是面向底层的,所以相比于SPL来说,还是比较难读懂的。不像SPL是通俗易懂的,完全可以通过函数名来打包自己的硬件库函数进行操作。

例如:
使用寄存器对stm32的PB5和PE5进行io配置高电平:

void LED_Init(void) {
GPIOB->BRR=GPIO_Pin_5;//LED0亮

GPIOE->BRR=GPIO_Pin_5;//LED1亮
 }

使用SPL库对stm32的PB5和PE5进行io配置高电平:

void LED_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd
(
RCC_APB2Periph_GPIOB| RCC_APB2Periph_GPIOE, 
ENABLE
);//使能 PB,PE 端口时钟 

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
GPIO_Init(GPIOB, &GPIO_InitStructure); 
GPIO_SetBits(GPIOB,GPIO_Pin_5);//PB.5 输出高

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOE, &GPIO_InitStructure); 
GPIO_SetBits(GPIOE,GPIO_Pin_5);//PE.5 输出高
}

使用HAL库对stm32的PB0和PB1进行io配置高电平:

void LED_Init(void)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOB_CLK_ENABLE();           //开启GPIOB时钟
    
GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1; //PB1,0
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
    
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);   
//PB0置1,默认初始化
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);   
//PB1置1,默认初始化
}

对于操作io口的配置方式,st给出了三种方法来编程io口,各有各的优点和缺点,在使用过程中要考虑实际情况来使用。

GPIO位操作

位操作代码在 sys.h 文件中,实现对 STM32 各个 IO 口的位操作,包括读入和输出。当然 在这些函数调用之前,必须先进行 IO 口时钟的使能和 IO 口功能定义。此部分仅仅对 IO 口进 行输入输出读取和控制。
位带操作简单的说,就是把每个比特膨胀为一个 32 位的字,当访问这些字的时候就达到了 访问比特的目的,比如说 BSRR 寄存器有 32 个位,那么可以映射到 32 个地址上,我们去访问 这 32 个地址就达到访问 32 个比特的目的。这样我们往某个地址写 1 就达到往对应比特位写 1 的目的,同样往某个地址写 0 就达到往对应的比特位写 0 的目的。位带操作在实际开发中可能只是用来 IO 口的输入输出还比较方便,其他操作在日常开发中也基本很少用。

//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum)   ((addr & 0xF0000000)
+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)     *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)     MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#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)  //输入

GPIO的小tips

  1. stm32的io口虽然很多支持ft格式的电平,但是电流比较小,难以带的动大功率的电机,例如步进和空心杯等等
  2. stm的io口和其他类型的单片机一样,对于SPI和IIC都可以进行模拟电平时间进行模拟通信协议进行通信,对于初学者来说,最好照着时序图操作一遍,对于io口和通信协议的配置的记忆有着很大的帮助。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,640评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,254评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,011评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,755评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,774评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,610评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,352评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,257评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,717评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,894评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,021评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,735评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,354评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,936评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,054评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,224评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,974评论 2 355

推荐阅读更多精彩内容

  • 姓名:朱小鹏 学号:16010130023 转载:STM32输入输出模式理解 http://www.opened...
    小鵬_956f阅读 1,263评论 0 0
  • 1 GPIO概述 1.1 功能描述 STM32的GPIO端口相对比较复杂,所以使用起来也困难许多,STM32的GP...
    hackvilin阅读 4,300评论 0 5
  • 其实这篇文章主要是介绍自己为其写的GPIO库,自己借鉴了原子写的STM32,野火写的K60,还有LPC官方库,然后...
    杨奉武阅读 768评论 0 0
  • 标准库占绝大多数,自己买的板子跟的资料也一般是标准库,HAL库很少,不过要是使用STM32CubeMx配置,那么就...
    停下浮躁的心阅读 6,177评论 0 3
  • 交通灯控制设计 一、选题背景 每个城市的交通就犹如人体的血管,人类生命的持续需要心脏为血液提供动力,依靠血液来在人...
    Rik_personal阅读 1,665评论 0 0