GPIO输入与输出及相关实验

GPIO基本结构

GPIO 挂载在 APB2 上,每个 GPIO 口都有 16 个引脚,每个引脚对应32位输入输出寄存器中的一位,其命名方式为 Pxx。

当某引脚的输出寄存器为1,就代表该引脚输出高电平,而如果输入高电平,则输入寄存器置为1,反之相反。

image

对于 GPIO 口的端口位结构的电路图,其基本电路结构我们没必要了解,有兴趣可以看看,这里只需要知道有哪些输入输出模式即可,后面能在程序中进行配置,具体配置方式参见:STM32F103参考手册中文.pdf,前面也有提到过。

image

1、输入模式

  • 浮空输入:逻辑器件与引脚既不接高电平,也不接低电平,电平就不确定了
  • 上拉输入:把电位拉高,因此默认高电平
  • 下拉输入:把电位拉低,因此默认低电平
  • 模拟输入:用于芯片引脚模拟信号输入到内部的模数转换器(ADC)

2、输出模式

  • 开漏输出:此时只控制 N-MOS管 开闭,外部可以接更大的电压,来实现导通和断开,因为 N-MOS管是低电平闭合,所以寄存器输入 0,N-MOS 导通接地,那么外界接高电平,此时就可以实现导通
  • 复用开漏输出:由片上外设控制,高电平接高阻态,低电平接入 VSS
  • 推挽输出:可以输出高、低电平,连接数字器件
  • 复用推挽输出:可以理解为 GPIO 口被用作第二功能时的配置情况

新建项目

这里就不再进行操作了,需要新建3个文件夹,start​,Library​,User​,具体的工程模板可参见前一篇文章:STM32工程创建与点灯实验-CSDN博客(ps:这里可以在 manage project item 中快速建立起 group 和对应文件,比前面自己一点点添加要方便一些)

注意:添加的时候别把启动文件给添加多了,添加多了会报错的😭,本课程需要添加的是startup_stm32f10x_md.s

image

删除过程文件,快速缩减文件体积的方式在前面的文章:STM32工程创建与点灯实验-CSDN博客,其中已经介绍过了,主要是同添加一个windows批量处理脚本keilkill.bat 来实现的,这里就直接略过了。

GPIO输出实验

这里通过 LED 二级发光管来直观的了解 GPIO 的输出

LED 相关硬件接线图

发光二极管长引脚为正,接入正极,负极接到 PA0 引脚,这时候如果 PA0 引脚输出低电平,那么就会亮,输出高电平就会熄灭。

image

LED 相关程序与结果

点灯

编写代码的时候一开始要善用函数说明,毕竟初始化配置是根本记不住的。

image

ps:LED还挺容易坏的,一开始接了一个红色的LED没亮,有一股烧焦的味道,看样子直接烧坏了,这应该就是为什么要加电阻,后面换了个才亮😭。

LED闪烁实验

1、原理:通过在循环中添加延时函数,并交替亮灭来完成闪烁,由于需要间隔时间,所以要用到 delay 函数

该函数的创建步骤如下所示

在自己的工程文件夹内再新建一个 system,这个文件用来存放系统资源,目前需要存放的资源就是延时函数 delay

image​​image

同样将它们都给添加到 keil 的 group 中。

我把江科大中的延时函数程序源码贴在这里

delay.h 文件

#ifndef __DELAY_H
#define __DELAY_H

void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);

#endif

delay.c 文件

#include "stm32f10x.h"

/**
  * @brief  微秒级延时
  * @param  xus 延时时长,范围:0~233015
  * @retval 无
  */
void Delay_us(uint32_t xus)
{
	SysTick->LOAD = 72 * xus;				//设置定时器重装值
	SysTick->VAL = 0x00;					//清空当前计数值
	SysTick->CTRL = 0x00000005;				//设置时钟源为HCLK,启动定时器
	while(!(SysTick->CTRL & 0x00010000));	//等待计数到0
	SysTick->CTRL = 0x00000004;				//关闭定时器
}

/**
  * @brief  毫秒级延时
  * @param  xms 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_ms(uint32_t xms)
{
	while(xms--)
	{
		Delay_us(1000);
	}
}
 
/**
  * @brief  秒级延时
  * @param  xs 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_s(uint32_t xs)
{
	while(xs--)
	{
		Delay_ms(1000);
	}
} 

LED闪烁 main 函数代码

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    
    while(1)
    {
        GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
        Delay_ms(500);
        GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
        Delay_ms(500);
    }
}

最终效果如下

9月28日1

LED流水灯

LED 流水灯就需要打开 PA 的所有引脚,然后再通过 for 循环遍历每一个引脚,并添加延时函数即可实现

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    
    while(1)
    {
        for(int i = 0; i < 8; i++) 
        {
            GPIO_Write(GPIOA,~(0x0001<<i));
            Delay_ms(500);
        }
    }
}

最终效果如下

请添加图片描述

蜂鸣器

蜂鸣器就跟前面的流水灯差不多的操作,低电平触发,蜂鸣器声音太响了,这个实验就略过了。

GPIO输入实验

这里需要再新建 Hardware 文件夹来存放驱动程序。
在这里插入图片描述

按键控制

按键是通过内部的弹簧片来完成的,那么使用弹簧片就会出现抖动,这里可以直接通过延时来进行消抖,基本上是按照江科大的思路来编写的程序,不过由于面包板部分插口接触不良(排查了半天),所以按键引脚换成了 PB0。
程序编写思路大体如下

  • LED(PA1, PA2) 初始化:这里初始化就仍然用推挽输出模式即可
  • LED 相关功能实现:亮灭操作,
  • 按键(PB0,PB11)初始化:因为这里我按键接入的是3,3V高电平,所以输入模式需要使用下拉输入,让该引脚始终保持低电平,那么按键接通的时候才会输入高电平,这时候就能使用stm32 中相应的库函数GPIO_ReadInputDataBit()来读取当前引脚电平的变化,从而知道哪个按键按下。
  • 按键功能:按键的定位操作,也就是得到哪个按键被按下。
  • 最后在 main.c 中调用对应的函数实现即可

源码如下

key.c

#include "stm32f10x.h"
#include "delay.h"

void Key_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_11;
 
    GPIO_Init(GPIOB,&GPIO_InitStructure);
}

uint8_t Key_GetNum(void)
{
    uint8_t KeyNum = 0;
    if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 1)
    {
        Delay_ms(20);
        while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 1);
        Delay_ms(20);
        KeyNum = 1;
    }
    if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 1)
    {
        Delay_ms(20);
        while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 1);
        Delay_ms(20);
        KeyNum = 2;
    }
    return KeyNum;
}

key.h

#ifndef __KEY_H
#define __KEY_H

void Key_Init(void);
uint8_t Key_GetNum(void);

#endif

led.h

#include "stm32f10x.h"                  // Device header

void LED_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
 
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    GPIO_WriteBit(GPIOA, GPIO_Pin_1 | GPIO_Pin_2, Bit_RESET);
}

void LED1_ON(void)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_RESET);
}

void LED1_OFF(void)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_SET);
}

void LED1_Turn(void)
{
    if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 1)
    {
        GPIO_ResetBits(GPIOA, GPIO_Pin_1);
    } 
    else
    {
        GPIO_SetBits(GPIOA, GPIO_Pin_1);
    }
}

void LED2_ON(void)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, Bit_RESET);
}

void LED2_OFF(void)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, Bit_SET);
}

void LED2_Turn(void)
{
    if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 1)
    {
        GPIO_ResetBits(GPIOA, GPIO_Pin_2);
    } 
    else
    {
        GPIO_SetBits(GPIOA, GPIO_Pin_2);
    } 
}

led.h

#ifndef __LED_H
#define __LED_H

void LED_Init(void);
void LED1_Turn(void);
void LED1_OFF(void);
void LED1_ON(void);
void LED2_Turn(void);
void LED2_ON(void);
void LED2_OFF(void);
#endif

最终效果如下
在这里插入图片描述
按下 PB0 处的按键,LED1(对应 PA1引脚) 会熄灭或点亮
按下 PB11 处的按键,LED2(对应PA2引脚)会熄灭或点亮

光敏传感器控制蜂鸣器

光敏电阻如图所示,这里我们使用三根杜邦线来控制光敏传感器

在这里插入图片描述

接电后,蓝色的部分用来调节其发光阈值,当光照强度到达一定强度时,光敏电阻就会亮,如动图所示
请添加图片描述
电路接线实物图如下图所示
在这里插入图片描述

这里用到了 PB12 和 PB13 引脚,PB12引脚接蜂鸣器,PB13引脚接光敏传感器,其余就是接VCC和GND的了

功能:当光照达到一定程度时,蜂鸣器会发出警报,流程图如下图所示

在这里插入图片描述

具体代码实现如下

buzzer.c

#include "stm32f10x.h"

void Buzzer_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    GPIO_SetBits(GPIOB, GPIO_Pin_12);
}

void Buzzer_OFF(void)
{
    GPIO_SetBits(GPIOB, GPIO_Pin_12);
}
void Buzzer_On(void)
{
    GPIO_ResetBits(GPIOB, GPIO_Pin_12);
}

void Buzzer_Turn(void)
{
    if(GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12) == 0)
    {
        GPIO_SetBits(GPIOB, GPIO_Pin_12);
    }
    else
    {
        GPIO_ResetBits(GPIOB, GPIO_Pin_12);
    }
}

buzzer.h

#ifndef __BUZZER_H
#define __BUZZER_H

void Buzzer_Init(void);
void Buzzer_OFF(void);
void Buzzer_On(void);
void Buzzer_Turn(void);


#endif

LightSensor.c

#include "stm32f10x.h"

void LightSensor_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

uint8_t LightSensor_Get(void)
{
    return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
}

LightSensor.h

#ifndef __LIGHTSENSOR_H
#define __LIGHTSENSOR_H

void LightSensor_Init(void);
uint8_t LightSensor_Get(void);

#endif

main.c: main函数部分就是实现了当光照达到一定程度,蜂鸣器会发出警报的功能,通过一个 if 判断语句即可实现

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "buzzer.h"
#include "LightSensor.h"

uint8_t KeyNum;

int main(void)
{
    Buzzer_Init();
    LightSensor_Init();
    
    while(1)
    {
        if(LightSensor_Get() == 1)
        {
            Buzzer_OFF();
        }
        else
        {
            Buzzer_On();
        }
    }
}

参考

  1. STM32学习记录——光敏传感器的使用_stm32光敏传感器-CSDN博客
  2. [3-4] 按键控制LED&光敏传感器控制蜂鸣器_哔哩哔哩_bilibili
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值