历史上的今天
返回首页

历史上的今天

今天是:2024年09月11日(星期三)

正在发生

2019年09月11日 | STM32 嵌入式学习入门(2)——STM32的GPIO介绍

2019-09-11 来源:eefocus

GPIO:General Purpose Input Output ,即通用输入/输出,简称为GPIO。


GPIO应该是学习单片机、学习嵌入式、学习STM32的第一个知识点了。在介绍GPIO相关的内容前,这里先总得说一下自己对GPIO的理解。对于初学者,可以把GPIO的作用想象成C语言里面的做输入输出的函数(scanf(); printf(); gets(); puts();等等),在C语言里面scanf()和printf()这两个函数是做输入输出的,对于几乎所有的C语言程序,都可以看成是用输入函数读取了一些输入,然后进行程序的逻辑处理,最后通过输出函数把程序最后执行的结果显示出来的过程。


同样地,这可以类比到嵌入式系统上面。比如循迹小车、避障小车、平衡小车、四旋翼等等,我们其实都可以看成这样的结构:


1)首先通过外部模块(这里主要是指各种传感器)读取系统的相关参数。比如循迹小车,就是利用红外模块去探测小车当前的行驶状态,并实时地将小车的行驶状态发送给主控制器(STM32)。而这种数据的发送就是将红外模块的特定引脚与STM32的GPIO相连,以高低电平的形式向STM32传递信息的。


2)主控制器对接收到的数据进行判断。接着上面循迹小车的例子,在主控制器的程序中,每过一定的时间(比如10ms)就会扫描并一下接收传感器信号的那几个引脚(IO口)上的高低电平的信息。然后对这些信息进行分析判断,判断的结果是小车当前是否还沿着预定轨迹行驶,如果偏离了预定的轨迹,应该怎么调整。


3)主控制器将判断结果通过IO口传出。上面第2点,最后的判断结果会通过IO口将调整信息发出到电机驱动部分,电机驱动部分会根据主控模块发来的数据对电机转速进行调整,从而达到让小车循迹行驶的目的。


总结一下,上面这三点主要是想让大家了解GPIO的作用,在一个项目、一个系统中的作用。说简单了就是输出高低电平和读取高低电平输入的。


下面进入正文,介绍GPIO的初始化和使用方法。


首先从最简单的角度介绍GPIO是什么东西。


首先GPIO最基本、最简单的作用是我们可以通过编程的方式让它作输入或者输出,而输入/输出的形式为高低电平(通常0V为低电平,3.3V为高电平)。要让GPIO作输入或者输出,首先就需要对IO口相关的寄存器进行配置。先介绍一下什么是寄存器,寄存器是中央处理器内的组成部分,寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。因此对IO口的初始化就是向相关寄存器里面写不同的值,从而确定使用哪一个IO口(IO口标号)、以及IO口工作模式(输入还是输出)、输出速度等参数。在经过初始化之后就可以正常使用IO口了,比如如果IO口设置成了某个输入模式,就可以通过调用相关函数或者直接操作相关寄存器去得到IO口的电平是高电平还是低电平。


下面从库函数的层面来说明如何初始化IO口。




typedef struct

{

uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.

  This parameter can be any value of @ref GPIO_pins_define */

 

GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.

  This parameter can be a value of @ref GPIOSpeed_TypeDef */

 

GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.

  This parameter can be a value of @ref GPIOMode_TypeDef */

}GPIO_InitTypeDef;

首先看这个结构体的定义,里面有三个变量,首先这三个变量的类型是通过类型重命名得到的,具体如下:


typedef unsigned short     int uint16_t;

typedef enum

  GPIO_Speed_10MHz = 1,

  GPIO_Speed_2MHz, 

  GPIO_Speed_50MHz

}GPIOSpeed_TypeDef;

typedef enum

{ GPIO_Mode_AIN = 0x0, //模拟输入

  GPIO_Mode_IN_FLOATING = 0x04, //浮空输入

  GPIO_Mode_IPD = 0x28, //下拉输入

  GPIO_Mode_IPU = 0x48, //上拉输入

  GPIO_Mode_Out_OD = 0x14, //开漏输出

  GPIO_Mode_Out_PP = 0x10, //推挽输出

  GPIO_Mode_AF_OD = 0x1C, //复用开漏输出

  GPIO_Mode_AF_PP = 0x18 //复用推挽输出

}GPIOMode_TypeDef;


所以实际上,GPIO_InitTypeDef这个结构体第一个变量类型为一种无符号的整形,变量名为GPIO_Pin,即为确定是哪一个IO口。GPIO_InitTypeDef的第二个变量类型是用枚举定义的,根据变量名很容易知道它是确定IO口的输入或输出的速度的。GPIO_InitTypeDef的第三变量同样是枚举定义的,是确定IO口作输入还是输出,当然这里输入和输出又可以各自细分为好几种,所以这里看到这个结构体中八种模式(mode)。这八种模式中,最常用的也是应该掌握的有三种:推挽输出、开漏输出、上拉输入。


推挽输出:可以输出高、低电平,连接数字器件;推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止。高低电平由IC的电源低定。


开漏输出:输出端相当于三极管的集电极.要得到高电平状态需要上拉电阻才行.适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内) 。


上拉输入:IO口内部输入时由上拉电阻上拉。


具体八种IO口工作模式的解释,可以参考这个帖子:http://www.openedv.com/posts/list/21980.htm


比如说我们需要将PB5这个IO口设置为推挽输出,输入速度为50MHz,实现的代码如下:



 GPIO_InitTypeDef  GPIO_InitStructure;

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟 ①

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PB.5 端口配置

 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出

 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz

 GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5 ②

//void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);


这里可能不懂的地方是我用圆圈标出来的两个地方。首先第①行,对于STM32而言,外设和IO口是很多的,默认状态下这些外设和IO口的状态都是关闭的(未使能的),这样可以节约CPU的资源,在使用的时候就要使能(开启)相关时钟。②的位置是调用IO口初始化函数,这是一个库函数,是官方提供的,初学者没有必要了解函数实现的细节。但需要掌握该函数调用时的入口参数。我们的例子是初始化PB5,所以第一个确定IO分组的参数应该写GPIOB,第二个参数就是传入刚才配置好的变量的地址。

再举一个例子,比如我们要初始化PA8这个IO口为下拉输入,输入速度为50MHz,实现的代码如下:,代码如下:



 GPIO_InitTypeDef  GPIO_InitStructure;

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //PA.8 端口配置

 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉输入

 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz

 GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA.8



通过上面的操作,就对IO口完成初始化了。下面我们可以开始对IO口进行相关操作了,比如读取IO口的电平(当IO口设置为某个输入模式的时候),或者通过IO口输出高低电平(当IO口设置为某个输出模式的时候)。这里介绍这么三个库函数:


uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

第一个函数用于读取相关IO口的电平的高低,比如我要读 GPIOA.5 的电平状态, 那么方法是:GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);返回值是 1(Bit_SET)或者 0(Bit_RESET)。

后面两个函数用于设置IO口的电平的高低,GPIO_SetBits()用于设置IO口电平为高,GPIO_ResetBits();用于设置IO口电平为低。


比如我们要设置 GPIOB.5 输出 1,那么方法为:GPIO_SetBits(GPIOB, GPIO_Pin_5);反之如果要设置GPIOB.5 输出位 0,方法为:GPIO_ResetBits (GPIOB, GPIO_Pin_5);


以上的介绍就是GPIO最最基本的内容。掌握了这些,就可以试着写一个跑马灯一类的实验了。


推荐阅读

史海拾趣

EM Microelectronic-Marin SA公司的发展小趣事

1995年,Philips Semiconductors收购了Mikron Graz,这一事件标志着EM Microelectronic-Marin与Philips在半导体领域的深度合作。此后,两家公司共同推动了RFID(射频识别)技术的发展,使其逐渐成为电子行业中不可或缺的一部分。EM Microelectronic-Marin凭借其在低功耗技术方面的优势,为RFID技术提供了强有力的支持。

ADI(亚德诺半导体)公司的发展小趣事

随着RFID技术的广泛应用,制定统一的国际标准变得尤为重要。EM Microelectronic-Marin积极参与了RFID标准制定机构的讨论,与其他企业一起提交了RFID标准建议。这一过程中,公司不断推动技术创新,力求在标准制定中占据有利地位。虽然最终的标准之争结果未知,但EM Microelectronic-Marin的技术实力和创新精神得到了业界的广泛认可。

BOPLA公司的发展小趣事

为了进一步提升公司的竞争力,BOPLA积极寻求与其他企业的合作机会。通过与上下游企业建立紧密的合作关系,公司实现了产业链的协同发展。同时,BOPLA还与其他创新型企业进行技术交流和合作研发,共同推动电子行业的发展。这种合作模式不仅提升了公司的技术水平,还为公司带来了更多的商业机会和发展空间。

以上便是关于BOPLA公司在电子行业中发展的几个可能的故事情节。这些故事展示了BOPLA在创业初期、技术突破、市场拓展、绿色转型以及合作与共赢等方面的努力和成就。当然,实际的发展过程可能更加复杂和多变,但无论如何,BOPLA都以其坚韧不拔的精神和不断创新的态度,在电子行业中留下了深刻的印记。

浙江东亚电子(DongYa)公司的发展小趣事

浙江东亚电子注重企业文化的建设,致力于为员工提供一个良好的工作环境和发展平台。公司关注员工的学习和成长,为员工提供持续长效的发展机会和有竞争力的薪酬。同时,公司还积极开展各类文化活动和社会公益活动,增强员工的归属感和凝聚力。

这些故事框架展示了浙江东亚电子在电子行业中发展起来的几个重要方面。通过技术创新、产业布局拓展、国际市场开拓、品质管理提升和企业文化建设等方面的努力,公司不断壮大自身实力,成为行业内的佼佼者。

Analogic Corporation公司的发展小趣事

浙江东亚电子一直将品质管理作为公司发展的重要基石。公司建立了完善的质量管理体系,从原材料采购到产品制造、销售等各个环节都严格把关。此外,公司还积极参与行业标准和规范的制定工作,不断提升自身的品质管理水平。

Hong Kong X'Tals Ltd公司的发展小趣事
由于环境温度和元件参数的变化,实际定时时间可能会有所偏差。在设计时需要考虑这一因素,并留出适当的裕量。

问答坊 | AI 解惑

调试与故障检测

调试与故障检测…

查看全部问答>

我用内嵌TCP/IP协议的GPRS模块进行数据传输,其它命令都是正确的回复,但是最后一个上网的命令不正确

大家好,希望能帮帮我。我用西门子公司的MC55进行GPRS中的TCP/IP数据传输,用51单片机控制,现在TCP/IP设置的命令都回复的OK,但是最后一条连网命令不正确,经查证发现连网的命令是发送正确的,就是连不上网,是怎么回事啊?…

查看全部问答>

DS18B20 初始化失败 纠结中

为了单独测试这个DS18B20的初始化,弄了个最小化的电路如下: DS18B20接P1.7,LED接P1.0 如果初始化成功,则LED应该点亮. 程序: #include sbit DQ = P1^7; sbit LED = P1^0; void delay2us(unsigned char t) {      whil ...…

查看全部问答>

说说大家WCE的产品

交流下大家的Windows CE产品,看看目前市场上用到的Windows CE产品有哪些? 注:标明Windows CE版本号、产品名及简要介绍、工资。 先说我自己的: Windows CE 5.0、Windows CE 6.0 终端——类似电脑,主要用户行业的窗口柜台(如银行、邮政 ...…

查看全部问答>

UC/OS-II 无法屏蔽串口中断问题 1138开发板

用的是已经移植好的UCOS工程模板,在调用 OS_ENTER_CRITICAL();  进入临界段执行后,当串口发出中断时,依然转到串口中断服务函数。 难道不能屏蔽硬件中断?   OS_ENTER_CRITICAL();        / ...…

查看全部问答>

请教:支持2440,nand flash的Jtag的图形下载软件?

H-jtag对nand flash的下载支持的好像不够好! SJF又不是很好用,请问那里有更好的下载工具捏? …

查看全部问答>

USB摄像头 OV511+OV7620,采集图像不清晰问题

环境:WINCE ARM11 设备:网眼V2000, OV511+USB摄像头 资源:参考网上的WINCE_OV511,带驱动+上位机+PPT讲解的那个 测试结果:YUV420->RGB图像如下。 请了解或者做过的朋友指点下,为什么图像不清晰,而且是花的。谢谢! …

查看全部问答>

cortex-m0社区热闹程度大减!

关于M0的讨论不是很热闹呀! 发帖顶一下!…

查看全部问答>