GPIO输出、输入
GPIO(General Purpose Input Output) 通用输入输出口,也就是俗称的IO口
八种输入输出模式
- 浮空输入
- 上拉输入
- 下拉输入
- 模拟输入
- 开漏输出
- 推挽输出
- 复用开漏输出
- 复用推挽输出
引脚电平
- 引脚电平:0~3.3V,部分引脚可容忍5V(容忍5V表示某些端口可以输入5V,但是输出最大只能3.3V),可以查看STM32的引脚定义,带有FT的表示能容忍5V
- 数据0就是低电平,数据1是高电平
输出模式下:
可控制端口输出高低电平,用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等。
输入模式下:
可读取端口的高低电平或电压,用以读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通讯协议接收数据等。
GPIO结构
- 在SMT32中所有的GPIO都是挂载在 APB2 的总线上的
- GPIO外设名称是以 GPIOA、GPIOB、GPIOC 命名的,每个上面都有16个引脚,编号是 PA0、PA1、PA2...PA15, PB0、PB1...
名词:
-
VDD: 限定3.3V,限定电压用的
-
VSS: 限定0V,限定电压用的
-
上拉电阻: 默认为高电平的输入方式,如果什么也不输入,默认会给高电平
-
下拉电阻: 默认为低电平的输入方式,如果什么也不输入,默认会给低电平
-
上下都不拉: 浮空模式
-
施密特触发器: 整形波形,对波形进行整形,防止因电压波动导致的电平误判。他有两个阈值,高于高阈值就会显示高电平,低于低阈值就显示低电平(0),处于两个阈值中间时,就显示不变。这样如果是从高电平进入的中间区域,就会保持高电平,如果是从低电平进入的中间区域,就会保持低电平。直到碰到阈值线才会改变
-
模拟输入: 是要连接到ADC上的,需要模拟量,线是从施密特触发器之前接入
-
复用功能输入: 是连接到其他需要读取的外设上的,比如串口的输入引脚,接受的是数字量,线是从施密特触发器之后接入
GPIO操作二极管代码
写一个LED闪烁的代码
- 将 STM32F103C8T6 插到面包板上操作,
- 3.3V 引脚接入正极,将 GND 引脚接入负极。将二极管正极接入正极电路,将负极接入板子A0引脚
- 插入ST-Link
- 代码写完后,构建,构建成功后,下载到STM32里执行
- 代码:
#include <stm32f10x.h>
#include <Delay.h>
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_TypeStruct;
GPIO_TypeStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_TypeStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_TypeStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_TypeStruct);
// GPIO_SetBits(GPIOA, GPIO_Pin_0); // 高电平
// GPIO_ResetBits(GPIOA, GPIO_Pin_0);
// GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); // 高电平
// GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
while(1)
{
GPIO_SetBits(GPIOA, GPIO_Pin_0);
Delay_ms(200);
GPIO_ResetBits(GPIOA, GPIO_Pin_0);
Delay_ms(200);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
Delay_ms(200);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
Delay_ms(200);
}
}
写一个8个二极管的流水灯功能
- 将 STM32F103C8T6 插到面包板上操作
- 将3.3V接到正极,GND接到负极
- 将8个二极管的负极分别接到 A0,A1,A2,A3,A4,A5,A6,A7上
- 插入 ST-Link
- 代码:(Delay.h 里的 Delay_ms 是休眠xx毫秒)
#include <stm32f10x.h>
#include <Delay.h>
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
while(1)
{
// GPIO_Write 与 GPIO_SetBits 的区别是write可以一次控制16个引脚状态,
// SetBits只能通过|运算符写多个为高点位
// 这里 ~0x0001 是取反,并设置电位。1表示高电位,0表示低电位
GPIO_Write(GPIOA, ~0x0001);
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0002);
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0004);
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0008);
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0010);
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0020);
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0040);
Delay_ms(100);
}
}
/*
// 方法二比较笨
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_TypeStruct0;
GPIO_InitTypeDef GPIO_TypeStruct1;
GPIO_InitTypeDef GPIO_TypeStruct2;
GPIO_InitTypeDef GPIO_TypeStruct3;
GPIO_InitTypeDef GPIO_TypeStruct4;
GPIO_InitTypeDef GPIO_TypeStruct5;
GPIO_InitTypeDef GPIO_TypeStruct6;
GPIO_InitTypeDef GPIO_TypeStruct7;
GPIO_TypeStruct0.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_TypeStruct1.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_TypeStruct2.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_TypeStruct3.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_TypeStruct4.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_TypeStruct5.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_TypeStruct6.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_TypeStruct7.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_TypeStruct0.GPIO_Pin = GPIO_Pin_0;
GPIO_TypeStruct1.GPIO_Pin = GPIO_Pin_1;
GPIO_TypeStruct2.GPIO_Pin = GPIO_Pin_2;
GPIO_TypeStruct3.GPIO_Pin = GPIO_Pin_3;
GPIO_TypeStruct4.GPIO_Pin = GPIO_Pin_4;
GPIO_TypeStruct5.GPIO_Pin = GPIO_Pin_5;
GPIO_TypeStruct6.GPIO_Pin = GPIO_Pin_6;
GPIO_TypeStruct7.GPIO_Pin = GPIO_Pin_7;
GPIO_TypeStruct0.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_TypeStruct1.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_TypeStruct2.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_TypeStruct3.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_TypeStruct4.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_TypeStruct5.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_TypeStruct6.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_TypeStruct7.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_TypeStruct0);
GPIO_Init(GPIOA, &GPIO_TypeStruct1);
GPIO_Init(GPIOA, &GPIO_TypeStruct2);
GPIO_Init(GPIOA, &GPIO_TypeStruct3);
GPIO_Init(GPIOA, &GPIO_TypeStruct4);
GPIO_Init(GPIOA, &GPIO_TypeStruct5);
GPIO_Init(GPIOA, &GPIO_TypeStruct6);
GPIO_Init(GPIOA, &GPIO_TypeStruct7);
// GPIO_SetBits(GPIOA, GPIO_Pin_0); // 高电平
// GPIO_ResetBits(GPIOA, GPIO_Pin_0);
// GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); // 高电平
// GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
// 这种方式有点问题:
// GPIO_Init 时,默认是低电平,所以这种写法会在第一圈时所有灯都是亮的
// 要想默认都关闭,需要:
GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 |
GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7);
while(1)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_0);
Delay_ms(200);
GPIO_SetBits(GPIOA, GPIO_Pin_0);
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
Delay_ms(200);
GPIO_SetBits(GPIOA, GPIO_Pin_1);
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
Delay_ms(200);
GPIO_SetBits(GPIOA, GPIO_Pin_2);
GPIO_ResetBits(GPIOA, GPIO_Pin_3);
Delay_ms(200);
GPIO_SetBits(GPIOA, GPIO_Pin_3);
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
Delay_ms(200);
GPIO_SetBits(GPIOA, GPIO_Pin_4);
GPIO_ResetBits(GPIOA, GPIO_Pin_5);
Delay_ms(200);
GPIO_SetBits(GPIOA, GPIO_Pin_5);
GPIO_ResetBits(GPIOA, GPIO_Pin_6);
Delay_ms(200);
GPIO_SetBits(GPIOA, GPIO_Pin_6);
GPIO_ResetBits(GPIOA, GPIO_Pin_7);
Delay_ms(200);
GPIO_SetBits(GPIOA, GPIO_Pin_7);
}
}
*/
写一个蜂鸣器
#include <stm32f10x.h>
#include <Delay.h>
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_SetBits(GPIOB, GPIO_Pin_12);
// GPIO_ResetBits(GPIOB, GPIO_Pin_12);
while(1)
{
Delay_ms(100);
GPIO_ResetBits(GPIOB, GPIO_Pin_12);
Delay_ms(100);
GPIO_SetBits(GPIOB, GPIO_Pin_12);
Delay_ms(100);
GPIO_ResetBits(GPIOB, GPIO_Pin_12);
Delay_ms(100);
GPIO_SetBits(GPIOB, GPIO_Pin_12);
Delay_ms(700);
}
}