STM32——GPIO输入

 传感器模块简介

 •传感器模块:传感器元件(光敏电阻/热敏电阻/红外接收管等)的电阻会随外界模拟量的变化而变化,通过与定值电阻分压即可得到模拟电压输出,再通过电压比较器进行二值化即可得到数字电压输出

硬件电路

下接方式

在这种接法下,当按键按下,PA0会直接下拉到GND,此时读取PA0口的电压是低电平;

在松开按钮后,PA0会悬空,会导致PA0口的电压不确定,所以此时PA0口必须是上拉输入模式,

所以按下按键,引脚为低电平,松开,引脚变高电平。

下图区别于上图加了一个上拉电阻,当按下按键,引脚接到GND为低电平,松手后,由于上拉作用,引脚变为高电平。所以此时PA0可以配置为浮空输入或者上拉输入模式。

上接方式

原理类似于下接方式

C语言知识

数据类型

 typedef

关键字: typedef
用途:将一个比较长的变量类型名换个名字,便于使用
定义 typedef

          typedef unsigned char uint8_t;

引用 typedef

           uint8_t a;  //等效于unsigned char a;

只能用于变量改名

结构体配合typedef可以做到快速定义结构体

在STM32中有体现

枚举

关键字: enum
用途:定义一个取值受限制的整型变量,用于限制变量取值范围(意思是只能赋值枚举中的常量,而不能赋值其他);宏定义的集合
定义枚举变量:

          enum{FALSE = 0, TRUE = 1} EnumName;

            因为枚举变量类型较长,所以通常用typedef更改变量类型名

引用枚举成员:

          EnumName = FALSE;

          EnumName = TRUE;

在STM32中有体现

启动时钟的代码中如是写道:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

其中函数中的第二个参数NewState就是枚举变量,在其定义中可以看到

 图二使用typedef简化了枚举变量的定义,在图一中NewState就是如此一个枚举变量

它只能被赋值于ENABLE和DISABLE

按键控制LED

为了模块化编程,我们可以再建立一个文件夹来存放模块化的代码

这里把LED驱动的代码模块化(要进行三个箱子和魔术棒的操作)

然后开始编写代码

如果编写代码时没有代码提示框,可以按快捷键Ctrl+Alt+空格

LED.c

#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_Pin = GPIO_Pin_1 | GPIO_Pin_2;
	//端口A0
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	//50MHz输出
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}	

 写好后在main函数中调用,编译下载后会发现LED亮起,这是因为GPIO默认配置好就是低电平,所以LED会亮,我们可以在初始化函数中加上

	GPIO_WriteBit(GPIOA, GPIO_Pin_1 | GPIO_Pin_2,Bit_SET);

把其设置为高电平,这样初始化之后LED就是关闭状态了

然后写出LED1和LED2的点亮和熄灭函数

void LED1_ON(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}

void LED1_OFF(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_1);
}

void LED2_ON(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}

void LED2_OFF(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_2);	
}

再写出按键的初始化函数(模块化编程)

 由接线图可知,按键是接在GPIOB上的,所以要初始化时钟和端口

#include "stm32f10x.h"                  // Device header

void Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	//初始化时钟
	
	GPIO_InitTypeDef GPIO_InitStructure1;
	
	GPIO_InitStructure1.GPIO_Mode = GPIO_Mode_IPU;
    //上拉输入
	GPIO_InitStructure1.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure1.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure1);
}

现在开始配置按键输出函数

先查看GPIO的头文件,查看相关函数

这是读取输入的数据,两个函数有所不同,第一个是读输入数据的某一位,参数用于指定端口

第二个是读取输入数据

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

 第一个是读取输出数据的某一位,第二个是读取输出数据

uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

我们将会用到这些函数

如下,和单片机的获取按键键码是同一个原理。

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

先验证

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


uint8_t KeyNumber;
int main(void)
{
	LED_Init();
	Key_Init();
	
	while(1)
	{
		KeyNumber = Key_GetNum();
		
		if(KeyNumber == 1)
		{
			LED1_ON();
		}
		if(KeyNumber == 2)
		{
			LED1_OFF();
		}
	}
	
}

效果是按一个按键可以点亮LED1,按另一个按键可以熄灭LED1。

验证得出按键结果没问题之后可以继续写代码。

要实现按按键1点亮LED1,再按一下熄灭按键1,将会用到之前所说的读取输出数据的函数

可以在LED.c文件中编写该函数。

读取输出数据的函数使用方法与读取输入的数据类似

这里很巧妙地使用这个函数来给LED状态取反,依靠读取LED的状态来设置按下按键后的状态。

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

void LED2_Turn(void)
{
	if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0)
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_2);
	}
	else
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);
		
	}
}
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"


uint8_t KeyNumber;
int main(void)
{
	LED_Init();
	Key_Init();
	
	while(1)
	{
		KeyNumber = Key_GetNum();
		
		if(KeyNumber == 1)
		{
			LED1_Turn();
		}
		if(KeyNumber == 2)
		{
			LED2_Turn();
		}
	}
	
}

 总体

Key.c

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

/**
  * @brief  按键初始化,在使用前添加在主函数中
  * @param  
  * @retval 
  */

void Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	//初始化时钟
	
	GPIO_InitTypeDef GPIO_InitStructure1;
	
	GPIO_InitStructure1.GPIO_Mode = GPIO_Mode_IPU;
	//上拉输入
	GPIO_InitStructure1.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure1.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure1);
}

/**
  * @brief  获取按键键码并返回特殊值
  * @param  无
  * @retval 如果按下GPIO_Pin_1返回1,按下GPIO_Pin_11,返回2
  */

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

LED.c

#include "stm32f10x.h"                  // Device header

/**
  * @brief  LED初始化,在使用时添加在主函数中
  * @param  无
  * @retval 无
  */

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_Pin = GPIO_Pin_1 | GPIO_Pin_2;
	//端口A0
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	//50MHz输出
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_WriteBit(GPIOA, GPIO_Pin_1 | GPIO_Pin_2, Bit_SET);
}	

/**
  * @brief  读取LED的状态并取反
  * @param  无
  * @retval 无
  */

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

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

main.c

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


uint8_t KeyNumber;
int main(void)
{
	LED_Init();
	Key_Init();
	
	while(1)
	{
		KeyNumber = Key_GetNum();
		
		if(KeyNumber == 1)
		{
			LED1_Turn();
		}
		if(KeyNumber == 2)
		{
			LED2_Turn();
		}
	}
	
}

光敏传感器控制蜂鸣器

理解了以上原理后,这就变简单了

只需稍稍按照接线方式修改代码即可

Buzzer.c

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


uint8_t LightNum;
int main(void)
{
	Buzzer_Init();
	Light_Init();
	
	while(1)
	{
		if(Light_GetNum())
		{
			Buzzer_ON();
		}
		else
		{
			Buzzer_OFF();
		}
	}
	
}

Light.c

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

/**
  * @brief  光敏传感器初始化,在使用前添加在主函数中
  * @param  
  * @retval 
  */

void Light_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	//初始化时钟
	
	GPIO_InitTypeDef GPIO_InitStructure1;
	
	GPIO_InitStructure1.GPIO_Mode = GPIO_Mode_IPU;
	//上拉输入
	GPIO_InitStructure1.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStructure1.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure1);
}

/**
  * @brief  获取光敏传感器状态并返回特殊值
  * @param  无
  * @retval 
  */

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

main.c

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


uint8_t LightNum;
int main(void)
{
	Buzzer_Init();
	Light_Init();
	
	while(1)
	{
		if(Light_GetNum())
		{
			Buzzer_ON();
		}
		else
		{
			Buzzer_OFF();
		}
	}
	
}

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值