GPIO

全称:(General Purpose Input Output):通用输入输出口,也就是常说的I/O口

可配置为8种输入输出模式 引脚电平:输出0V~3.3V,部分引脚可容忍输入5V (带FT(Five Tolerate))

对于功率比较大的设备需要加入驱动电路

如果输入的是模拟信号,GPIO可以编程模拟输入的模式,再配合内部ADC外设,就能读取端口的模拟电压

GPIO基本结构

每一个GPIO外设上都有一个寄存器与一个驱动器,寄存器上有16个端口分别通过驱动器与十六个引脚相连,GPIO外设命名方式为GPIOX(X=A、B、C……),十六个引脚命名的方式为PX0,PX1,PX2……PX15,其中X=A、B、C,根据引脚所在外设决定。

STM32是32位的单片机,所以STM32内部的寄存器也是32位的,但这里只用了低16位,高16位并没有用到。

内核通过APB2外设总线控制寄存器进行读写操作,当读到寄存器某一位为1时,则可知道对应的引脚为高电平,当写入寄存器中的某一位为1时,就是把其对应的引脚输出高电平。

所有GPIO都是挂载在APB2外设总线上的。

驱动器负责增大驱动能力,寄存器只负责存储功能。

image.png

 GPIO位结构

image.png

 保护二级管工作原理:当I/O口输入高于3.3V的电压时,接VDD的二极管导通,电流从I/O口流向VDD,不流入后续电路,起到了保护作用;当I/O口的电压为负电压时,电流从VSS流向I/O口,不汲取后续电路的电流,同样起到了保护作用。若VDD改为VDD_FT,则表示电源为5V。

上拉电阻及下拉电阻:可以通过软件配置,当VDD导通VSS断开时,为上拉输入模式,引脚悬空时为高电平,反之为下拉输入模式,引脚悬空时为低电平,两者都断开时,为浮空输入模式,引脚悬空时电平不确定,极易受外界干扰而变化。

模拟输入:一般接ADC,接收模拟量。

施密特触发器:作用为对输入电压整形,设置有阈值上限和阈值下限,当I/O口的输入模拟信号超过上限时,施密特触发器输出高电平,当I/O口输入的模拟信号低于下限时,施密特触发器输出低电平,其余时候保持原有电平不变。整形后输入数据存储器保存,再用程序读取就可以知道某位的高低电平。

复用功能输入:一般接其他外设。

位设置/清除寄存器:可以对寄存器中的数据进行单独的位操作,不用整体进行&=或者/=,方便快捷。写1是设置或者清除,写0的位保持不变。高16位是用于位清除的,低16位是用于位设置的,还有一个单独的位清除寄存器,两者配合使用就能之用低16位就可以完成设置与清除,更加便捷,但缺点是不能同步进行,若想要同步进行,就只是采用设置/清除寄存器即可。

P-MOS和N-MOS:两者可以控制三种输出模式:推挽输出,开漏输出以及关闭。

当设置为推挽输出时,P-MOS和N-MOS都有效,当1信号通过输出控制进入MOS管,在P-MOS管被取反为0,在N-MOS管依旧是1,此时P-MOS管导通,N-MOS管断开,输出高电平,反之低电平。

当设置为开漏输出时,P-MOS管一直断开,当1信号通过输出控制进入MOS管,N-MOS管不导通,这时输出高阻态。当0信号通过输出控制进入MOS管,N-MOS管导通,输出高电平。当输入驱动器开启时,为关闭。可以设置开漏模式,外接5v电源加一个电阻,设置输出5v电压。

一个端口可以只能有一个输入,却可以有多个输出。

GPIO模式

image.png

器件原理解析

LED

image.png

 左边发光二极管高电平驱动,右边发光二极管低电平驱动。倘若单片机设置是高电平弱驱动,则不可用左边的接法,若为低电平弱驱动,则不可以用右边的接法。

面包板:

可以撕开后面看看哪里跟哪里导通的,避免踩坑。

蜂鸣器:

image.png

对于功率比较大的器件,一般使用三极管驱动的方法来连接电路,避免I/O口负担过重,有箭头是发射极,对左图,当基极给低电平时,三极管导通,蜂鸣器工作;对右图,当基极给高电平时,三极管导通,蜂鸣器工作; 需要注意的是,基极跟发射极之间需要一点开启电压,故而负载蜂鸣器一般不接在发射极一端。

小文件分享

小文件keilkill可以删减过程函数,因为工程文件一般比较大,主要内容就是这些过程量,故而想要实现高效率的分享,可以通过删减过程量,把原来的代码分享出去即可,需要编译后才能恢复如初。

LED闪烁

源代码百度云地址:

链接:https://pan.baidu.com/s/1ZL-6_cgzzKMiS8oxC2MA8Q 

提取码:0323

第一步:使用RCC开启GPIO时钟

第二步:使用GPIO_Init函数初始化GPIO

第三步:使用输出或者输入函数控制GPIO

RCC常用函数在rcc.h文件中692行,跳转查看RCC用法,若无法跳转,则重新编译再尝试

GPIO常用库函数在gpio.h的349行左右,跳转查看RCC用法,若无法跳转,则重新编译再尝试

Ctr+Shift+N 快速新建文件夹

Library文件夹中可以看到各种外设的函数使用方法

根据表中寻找要使用的外设连接到哪个总线上

GPIO_WriteBit(GPIOA, GPIO_Pin_2, Bit_SET);

GPIO_WriteBit(GPIOA, GPIO_Pin_2, Bit_RESET);

.c文件看内在逻辑,.h看怎么用

GPIO_WriteBit(GPIOA, GPIO_Pin_2,(BitAction)1);强制转换类型才能设置,不能直接设置1或者0.

image.png

第一步:使用RCC开启GPIO时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);   //使能APB2总线上的GPIOC上的所有引脚

第二步:使用GPIO_Init函数初始化GPIO

image.png

从上到下依次是:模拟输入,浮空输入,下拉输入,上拉输入,开漏输出,推挽输出,复用开漏输出,复用开漏输出。

 
    GPIO_InitTypeDef GPIO_InitStructure;              //定义结构体名为GPIO_InitStructure
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;    //推挽输出
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13;          //目标GPIOC_Pin_13,所以引脚选13
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;   //速读姑且选择50MHz
    GPIO_Init(GPIOC,&GPIO_InitStructure);             //注意第二个参数必须为指向结构名字的指针
  GPIO_InitTypeDef GPIO_InitStructure;中,设置的名字必须是GPIO_的格式,不然运行不了,因为在GPIO_Init();中,要求地址格式是那样子 。
第三步:使用输出或者输入函数控制GPIO
GPIO_SetBits(GPIOC,GPIO_Pin_13);   //PC13口输出高电平
GPIO_ResetBits(GPIOC,GPIO_Pin_13);  //PC13口输出低电平

#include "stm32f10x.h"            
#include "Delay.h"                                //延时函数头文件
 
int main(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOC,&GPIO_InitStructure);	
	
	while (1)
	{
		GPIO_SetBits(GPIOC,GPIO_Pin_13); 
		Delay_ms(500);		                    //延时500ms,可以任意修改
		GPIO_ResetBits(GPIOC,GPIO_Pin_13); 
		Delay_ms(500);	
      }
	}
代码大义:GPIOC_Pin_13端口输出高电平并且延时500ms,然后输出低电平并且保持500ms,不断循环反复。
把上述代码中的主体函数替换为以下代码之一也有相同效果:
其中BitAction是强制类型转换,这样才可以使用1跟0;
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
Delay_ms(500);
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
Delay_ms(500);



GPIO_WriteBit(GPIOC,GPIO_Pin_13,(BitAction)0;
Delay_ms(500);
GPIO_WriteBit(GPIOC,GPIO_Pin_13,(BitAction)1);
Delay_ms(500);
流水灯

第一步:使用RCC开启GPIO时钟

第二步:使用GPIO_Init函数初始化GPIO

第三步:使用输出或者输入函数控制GPIO

第一步:使用RCC开启GPIO时钟
第二步:使用GPIO_Init函数初始化GPIO
GPIO_Pin_All  可以选择开启所有端口,当要用到的引脚比较多的时候,不方便一个一个列举进行配置,故而可以把所有的端口都开启,不用的不进行配置就行。

也可以如下:


————————————————
版权声明:本文为CSDN博主「笔下觅封侯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_63148816/article/details/125805677目标:使用PA0到PA5的所有端口,LED低电平亮起,依次从0到5引脚亮起。

第一步:使用RCC开启GPIO时钟

第二步:使用GPIO_Init函数初始化GPIO

第三步:使用输出或者输入函数控制GPIO

第一步:使用RCC开启GPIO时钟
第二步:使用GPIO_Init函数初始化GPIO
GPIO_Pin_All  可以选择开启所有端口,当要用到的引脚比较多的时候,不方便一个一个列举进行配置,故而可以把所有的端口都开启,不用的不进行配置就行。

也可以如下:


————————————————
版权声明:本文为CSDN博主「笔下觅封侯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_63148816/article/details/125805677

目标:使用PA0到PA5的所有端口,LED低电平亮起,依次从0到5引脚亮起。

第一步:使用RCC开启GPIO时钟

第二步:使用GPIO_Init函数初始化GPIO

第三步:使用输出或者输入函数控制GPIO

第一步:使用RCC开启GPIO时钟

第二步:使用GPIO_Init函数初始化GPIO

GPIO_Pin_All  可以选择开启所有端口,当要用到的引脚比较多的时候,不方便一个一个列举进行配置,故而可以把所有的端口都开启,不用的不进行配置就行。

也可以如下:

GPIO_InitStucture.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;
第一步第二步完整代码如下: 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitTypeDef GPIO_InitStucture;
	GPIO_InitStucture.GPIO_Mode= GPIO_Mode_Out_PP;
	GPIO_InitStucture.GPIO_Pin=GPIO_Pin_All;
	GPIO_InitStucture.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStucture);
 第三步:使用输出或者输入函数控制GPIO
GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);控制多个端口,其中uint16_t PortVal表示十六位二进制数的十六进制表示,直接写到ODR寄存器中,C语言不支持直接写二进制,所以以十六进制代替。
比如:0000 0000 0000 0001 用0x0001表示
GPIO_Write(GPIOA,~0x0001);~为各位取反符号,就是0变1,1变0;
比如:~0x0001=~(0000 0000 0000 0001)=1111 1111 1111 1110
二进制的十六位分别代表PA0到PA15的16个端口。
要配置多个端口,可以选择GPIO_Pin_All;或者GPIO_Pin_1|GPIO_Pin_2这种格式,应为寄存器的每一位都相当于一个端口,设置为1高电平,0低电平,所以还可以加上个取反符号。GPIO_Pin_1|GPIO_Pin_2代表0x0001或0x0002(十六进制,换成二进制理解即可)
GPIO_Write(GPIOA,~0x0001);//1111 1111 1111 1110 十六位依次对应十六个引脚,意思就是PA0置0,其余置1.
        Delay_ms(500);
        GPIO_Write(GPIOA,~0x0002);
        Delay_ms(500);
        GPIO_Write(GPIOA,~0x0004);
        Delay_ms(500);
        GPIO_Write(GPIOA,~0x0008);
        Delay_ms(500);
        GPIO_Write(GPIOA,~0x0010);//0000 0000 0001 0000

这是流水灯的主要部分的函数,其原理为把引脚从0开始,依次置0,当其中一个为0时,其他置1,这样的话在引脚处不断输出低电平,在对应的引脚灯不断亮起熄灭。

总代码:

#include "stm32f10x.h"         

#include "Delay.h"   

int main(void)

{

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

GPIO_InitTypeDef GPIO_InitStucture;

GPIO_InitStucture.GPIO_Mode= GPIO_Mode_Out_PP;

GPIO_InitStucture.GPIO_Pin=GPIO_Pin_All;

GPIO_InitStucture.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitStucture);

while (1)

{

GPIO_Write(GPIOA, ~0x0001);

Delay_ms(500);

GPIO_Write(GPIOA, ~0x0002);

Delay_ms(500);

GPIO_Write(GPIOA, ~0x0004);

Delay_ms(500);

GPIO_Write(GPIOA, ~0x0008);

Delay_ms(500);

GPIO_Write(GPIOA, ~0x0010);

Delay_ms(500);

 

}

注意:A15 B3 B4调试端口,不能直接作为普通I/O口进行作用,要进行重映射后方可正常使用,尽量不适用这三者进行I/O口调用。

————————————————

版权声明:本文为CSDN博主「笔下觅封侯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/m0_63148816/article/details/125805677