3.GPIO开发简单程序-输出

4 阅读6分钟

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);
	}
}