STM32入门之GPIO详解

一、GPIO基础知识

 大家在做单片机相关项目开发时候,相信大家拿到板子的第一件事就是点亮开发板上的LED指示灯。也就是说我们第一件事就是对单片机的IO口进行操作,不管是51单片机还是32单片机亦或是arduino,我们想要控制一个最基本的外围器件,或者是用单片机传递出一组数据,这些任务的前提都是我们要能够操作单片机的IO口。所谓的IO就是指的GPIO (general purpose input output)通用输入输出端口,简单来说就是软件可控制的引脚,STM32芯片的GPIO引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。
Alt
 在一个芯片上我们通常能够看到外围有很多引脚,但是这里的引脚并不是所有的引脚都可以作为IO口使用,里边还包含供电和调试以及时钟输入等引脚
引脚分类

二、GPIO的电平标准

 在STM32的数据手册中我们可以查到,STM32单片机的IO口电平兼容CMOS电平和TTL电平,逻辑电平0所代表得电压范围在0.8v以下,大于2v的话就代表逻辑1。
在这里插入图片描述
在这里插入图片描述
 这里提到了两个电平标准一个是TTL电平,一个是CMOS电平。下面咱们简单说一下两者的区别:

  1.CMOS是场效应管构成,TTL为双极晶体管构成
  2.CMOS的逻辑电平范围比较大(3~15V),TTL只能在5V下工作
  3.CMOS的高低电平之间相差比较大、抗干扰性强,TTL则相差小,抗干扰能力差
  4.CMOS功耗很小,TTL功耗较大(1~5mA/门)
  5.CMOS的工作频率较TTL略低,但是高速CMOS速度与TTL差不多相当

 简单的来说,TTL的电源工作电压是5V,所以TTL的电平是根据电源电压5V来定的。CMOS的电源工作电压是3V - 18V,CMOS的电源工作电压范围宽,如果你的CMOS的电源工作电压是12V,那么这个CMOS的输入输出电平电压要适合12V的输入输出要求。即CMOS的电平,要看你用的电源工作电压是多少,3v - 18V,都在CMOS的电源工作电压范围内,具体数值,看你加在CMOS芯片上的电源工作电压是多少。

 常见的电平标准还有RS232电平和RS485电平,需要注意的是RS485采用的是差分信号,需要对应的芯片,单片机无法直接输出。
 其中RS232电平规定逻辑“1”的电平为-5V~-15 V,逻辑“0”的电平为+5 V~+15 V。选用该电气标准的目的在于提高抗干扰能力,增大通信距离。RS -232的噪声容限为2V,接收器将能识别高至+3V的信号作为逻辑“0”,将低到-3 V的信号作为逻辑“1”。
 RS485的电平逻辑“1”以两线间的电压差为+(2—6)V表示;逻辑“0”以两线间的电压差为-(2—6)V表示。接口信号电平比RS-232-C降低了,就不易损坏接口电路的芯片, 且该电平与TTL电平兼容,可方便与TTL 电路连接。

三、GPIO框图

在这里插入图片描述

1、保护二极管

 在芯片内部连接引脚的地方首先有两个保护二极管,当引脚电压高于VDD 时,上方的二极管导通,防止过高电压进入芯片内部烧坏芯片。当引脚电压低于 VSS 时,下方的二极管导通防止电压过低,从芯片内部汲取电流。
电压过高在这里插入图片描述

2、施密特触发器

 施密特触发器就像但于是一个开关,可以将输入的电压由缓慢变化的过程变为一个图片的过程,也就是说经过施密特触发器之后只有电平1或电平0,不会再有中间那个变化的过程,而且触发器还具有一定的滤波功能。
在这里插入图片描述

四、GPIO的工作模式

 不同于51单片机,在STM32中IO口需要配置为对应的模式才能够实现输入或者输出,具体的工作模式有以下几种,接下来我们会对每一种模式进行详细分析。
在这里插入图片描述

1、浮空输入模式

 当IO口配置为浮空输入模式的时候,两个开关都处于打开状态,输入信号直接经过施密特触发器将数据传递给输入数据寄存器或者外设,此时,IO口的电平完全由外部输入决定,所以一般用做按键输入。

2、上拉输入模式

 当配置为上拉输入模式时,单片机内部的上拉电阻起作用,此时由于上拉电阻的存在,IO口得电平默认为高电平。上拉电阻是用来解决总线驱动能力不足时提供电流的。一般说法是拉电流、或者说是提高高电平的驱动能力。

3、下拉输入模式

 当配置为下拉输入模式时,单片机内部的下拉电阻起作用,此时由于下拉电阻的存在,IO口得电平默认为低电平。下拉电阻是用来吸收电流的,也就是通常所说的灌电流,能够提高低电平的驱动能力。
在这里插入图片描述

4、模拟输入

 当配置为模拟输入模式的时候,禁止施密特触发输入,实现了每个模拟I/O引脚上的零消耗。施密特触发输出值被强置为’0’;输入数据直接到片上外设也就是芯片内部的ADC。
在这里插入图片描述

5、推挽输出

 当配置输出模式时,单片机内部的施密特触发器依旧被激活,仍可以通过读取输入数据寄存器的状态来判断当前IO口的电平是高还是低。当配置为推挽电路时,两个MOS管同时工作,寄存器输出1时,P-MOS管激活,IO口输出高电平,寄存器输出0时,N-MOS管激活,IO口输出低电平。
在这里插入图片描述

具体推挽电路分析可以看下图:

在这里插入图片描述
在这里插入图片描述

6、开漏输出

 当配置为开漏输出时,P-MOS管不工作,输出寄存器上的’0’激活N-MOS,而输出寄存器上的’1’将端口置于高阻状态(P-MOS从不被激活,就相当于是断路)。
在这里插入图片描述
具体工作方式参考下图
寄存器输出1时:
在这里插入图片描述
寄存器输出0时:
在这里插入图片描述

7、复用推挽输出和复用开漏输出

 复用推挽输出和复用开漏输出两种工作模式其核心部分和上述两种模式无差异,只有输入数据源发生了改变,由寄存器变成了由外设输出,这里的外设可以有很多,例如串口,定时器等
在这里插入图片描述

五、IO口相关寄存器

1、配置寄存器

 了解了IO口的工作模式,接下来我们就可以去学习如何去配置IO口了,这里我们需要了解的有两个寄存器,一个是配置高位寄存器,一个是配置低位寄存器
 可以看到,两个寄存器内部和名称都差不多,都有MODE和CNF构成,GPIOx_CRL负责MOED0-MODE7也就是0到7号引脚,GPIOx_CRH负责MOED8-MODE15也就是8到15号引脚,两个寄存器共同管理一个端口的16个引脚。
在这里插入图片描述
在这里插入图片描述

2、输出数据寄存器

 通过向输出数据寄存器写入数据1或者0,就可以控制单片机的引脚输出高低电平。
在这里插入图片描述

3、输入数据寄存器

 通过读取对应的位,就可以知道单片机的引脚的电平状态了。
在这里插入图片描述

部分内容引用该博主的文章

  • 12
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,我可以为您解答这个问题。 在STM32上使用GPIO模拟UART来打印log,需要用到两个GPIO口,一个用于作为TX(发送)口,另一个用于作为RX(接收)口。 首先,需要在STM32的代码中定义两个GPIO口作为TX和RX口,并初始化它们的状态。然后,可以使用GPIO口的输出和输入功能来模拟UART的发送和接收。 在发送数据时,需要将数据转换为二进制格式,并将其逐位地发送到TX口。在接收数据时,需要从RX口逐位地读取数据,并将其转换为ASCII字符格式。 下面是一个使用GPIO模拟UART打印log的示例代码: ```c #include "stm32f10x.h" GPIO_InitTypeDef GPIO_InitStructure; void GPIO_UART_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /* Configure USART Tx as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure USART Rx as input floating */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); } void GPIO_UART_SendChar(char ch) { uint8_t i; GPIO_WriteBit(GPIOA, GPIO_Pin_9, Bit_RESET); for(i=0;i<8;i++) { GPIO_WriteBit(GPIOA, GPIO_Pin_9, (BitAction)(ch & 0x01)); ch >>= 1; } GPIO_WriteBit(GPIOA, GPIO_Pin_9, Bit_SET); } void GPIO_UART_SendString(char *str) { while(*str) { GPIO_UART_SendChar(*str++); } } char GPIO_UART_ReceiveChar(void) { uint8_t i; char ch = 0; while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10)); for(i=0;i<8;i++) { ch >>= 1; if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10)) { ch |= 0x80; } while(!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10)); } return ch; } int main(void) { GPIO_UART_Init(); GPIO_UART_SendString("Hello, world!\r\n"); while(1) { char ch = GPIO_UART_ReceiveChar(); GPIO_UART_SendChar(ch); } } ``` 在这个示例代码中,我们使用GPIOA的Pin9作为TX口,使用GPIOA的Pin10作为RX口。我们在GPIO_UART_Init()函数中初始化这两个GPIO口,并在GPIO_UART_SendChar()和GPIO_UART_ReceiveChar()函数中实现了模拟UART的发送和接收功能。在main()函数中,我们首先使用GPIO_UART_SendString()函数发送一条“Hello, world!”的log,然后使用GPIO_UART_ReceiveChar()函数循环接收并打印log。 希望这个示例代码可以帮助您理解如何在STM32上使用GPIO模拟UART来打印log。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值