GPIO
基本结构-toc" style="margin-left:40px;">GPIO基本结构
GPIO位结构
GPIO模式
设备原理分析
LED
面包板:
蜂鸣器:-toc" style="margin-left:80px;">蜂鸣器:
小文件分享
LED闪烁
源代码百度云地址:
第一步:使用RCC开启GPIO时钟
第二步:使用GPIO_Init函数初始化GPIO
第三步:使用输出或输入函数控制GPIO
流水灯
第一步:使用RCC开启GPIO时钟
第二步:使用GPIO_Init函数初始化GPIO
第三步:使用输出或输入函数控制GPIO
GPIO
全称:(General Purpose Input Output):通用输入输出口,俗称I/O口
可配置为8种输入输出模式 引脚电平:输出0V~3.3V,部分引脚可容忍输入5V(带FT(Five Tolerate))
对于功率较大的设备,需要增加驱动电路
若输入模拟信号,GPIO可编程模拟输入模式,然后与内部配合ADC外设可以读取端口的模拟电压
GPIO基本结构
每一个GPIO外设上有一个寄存器和一个驱动器。寄存器上有16个端口,通过驱动器与16个引脚相连。GPIO外设命名为GPIOX(X=A、B、C...),16个引脚命名的方法是PX0,PX1,PX2...PX15,其中X=A、B、C,根据引脚所在外设。
STM32是32位单片机,所以STM内部寄存器也是32位,但这里只用了低16位,高16位没用。
内核通过APB2.外设总线控制寄存器进行读写操作。当读寄存器中的一个是1时,可以知道相应的引脚是高电平的。当写入寄存器中的一个是1时,就是输出相应的引脚高电平。
所有GPIO都是挂载在APB2外设总线。
驱动器负责提高驱动能力,寄存器只负责存储功能。
GPIO位结构
二级管工作原理的保护:I/O口输入高于3.3V电压时,连接VDD电流从二极管导通I/O口流向VDD,不流入后续电路,起到保护作用;当I/O当口的电压为负电压时,电流从VSS流向I/O不吸收后续电路电路的电流,也起到保护作用。VDD改为VDD_FT,这意味着电源V。
当软件配置时,可以配置上拉电阻和下拉电阻VDD导通VSS断开时,为上拉输入模式,引脚悬挂时为高电平,相反为下拉输入模式,引脚悬挂时为低电平,两者都断开时为浮动输入模式。
模拟输入:一般连接ADC,接收模拟量。
施密特触发器:用于输入电压整形手术,设置阈值上限和阈值下限I/O当口的输入模拟信号超过上限时,施密特触发器输出高电平I/O当口腔输入的模拟信号低于下限时,施密特触发器输出低电平,其余时间保持原电平不变。整形手术后,输入数据存储器进行保存,然后通过程序读取来了解某个电平。
复用功能输入:一般接收其他外设。
位置设置/清除寄存器:寄存器中的数据可以单独操作,无需整体操作&=或者/=,方便快捷。写1是设置或者清除,写0的位保持不变。高16位用于位置清除,低16位用于位置设置。还有一个单独的位置清除寄存器。可以用低16位完成设置和清除,比较方便,但缺点是不能同步。如果你想同步,你只能使用设置/清除寄存器。
P-MOS和N-MOS:两者可控制三种输出模式:推拉输出、开漏输出和关闭。
当设置为推挽输出时,P-MOS和N-MOS当1信号通过输出控制进入时,都是有效的MOS管,在P-MOS在N-MOS此时管道还是1P-MOS管导通,N-MOS断管,输出高电平,反之亦然。
当设置为泄漏输出时,P-MOS当1信号通过输出控制进入时,管道一直断开MOS管,N-MOS当0信号通过输出控制进入时,输出高阻态。MOS管,N-MOS管导通,输出高电平。输入驱动器打开时关闭。可设置泄漏模式,外接5v电源增加电阻,设置输出5v电压。
一个端口只能有一个输入,但可以有多个输出。
GPIO模式
数字输出
模式名称 |
性质 |
特征 |
浮空输入 |
数字输入 |
可读取引脚电平。如果引脚悬空,则电平不确定 |
上拉输入 |
数字输入 |
可读取引脚电平,内部连接上拉电阻,悬挂时默认高电平 |
下拉输入 |
数字输入 |
可读取引脚电平,内部连接下拉电阻,悬挂时默认低电平 |
模拟输入 |
模拟输入 |
GPIO无效,引脚直接进入内部ADC |
开漏输出 |
可输出引脚电平,高电平为高阻态,低电平接VSS |
|
推挽输出 |
数字输出 |
可输出引脚电平,高电平接VDD,低电平接VSS |
复用开漏输出 |
数字输出 |
由片上外设控制,高电平为高阻态,低电平接VSS |
复用推挽输出 |
数字输出 |
由片上外设控制,高电平接VDD,低电平接VSS |
器件原理解析
LED
左边发光二极管高电平驱动,右边发光二极管低电平驱动。倘若单片机设置是高电平弱驱动,则不可用左边的接法,若为低电平弱驱动,则不可以用右边的接法。
面包板:
可以撕开后面看看哪里跟哪里导通的,避免踩坑。
蜂鸣器:
对于功率比较大的器件,一般使用三极管驱动的方法来连接电路,避免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.
第一步:使用RCC开启GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //使能APB2总线上的GPIOC上的所有引脚
第二步:使用GPIO_Init函数初始化GPIO
从上到下依次是:模拟输入,浮空输入,下拉输入,上拉输入,开漏输出,推挽输出,复用开漏输出,复用开漏输出。
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,不断循环反复。
把上述代码中的主体函数替换为以下代码之一也有相同效果:
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);
流水灯
目标:使用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_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口调用。