GPIO,全称为General Purpose Input Output,意为通用输入输出,可配置八种输入输出模式。引脚电平:0 V − 3.3 V (VOL=0V,VOH=3.3V),部分引脚可以容忍 5 V(容忍的意思是可以在这个端口输入 5 V的电压,也认为是高电平,具体哪些端口可以容忍 5 V需要查找STM32的引脚定义。在引脚定义中带FT,意为Five Tolerate,就是可以输入 5 V 的端口)。
  GPIO在输出模式下可控制端口输出高低电平,用以驱动LED,控制蜂鸣器,模拟通信协议输出时序等。如果控制的是功率比较大的设备,只需要再加入驱动电路即可。
  GPIO在输入模式下可读取端口的高低电平(电压),用于读取按键输入,外界模块的(电平)信号输入,ADC电压采集,模拟通信协议接收数据等。

一、GPIO结构

gpio android 输入 高电平 gpio高电平电压_stm32

        在STM32中,所有的 GPIO都是挂载在APB2外设总线上的,其中GPIO外设的名称是按照GPIOA,GPIOB,GPIOC等等,每个GPIO外设总共有16个引脚,编号是从0到15,每个GPIO外设有16个引脚。以GPIOA为例,它的引脚编号分别为PA0,PA1,PA2 … PA15。其他GPIO的引脚也是这样命名的。

        在GPIO模块内部,主要包含了寄存器和驱动器两个模块。寄存器就是一段特殊的存储器,内核可以通过APB2总线对寄存器进行读写,以完成输出电平和读取电平的功能。
  STM32是32位的单片机,其中的寄存器都是32位的。而端口只有16个,故寄存器只有低16位有对应的端口,高16位没有用到。
  驱动器的作用是增加信号的驱动能力。寄存器只负责存储数据,需要用驱动器来增大驱动能力。

gpio android 输入 高电平 gpio高电平电压_学习_02

1、 I/O口接两个保护电阻,(VDD=3.3,VSS=0)

2、上面的上拉电阻和下拉电阻,如果上面导通、下面截止则为上拉输入模式,如果上面截止,下面导通,则为下拉输入模式,如果两个都断开,则为浮空输入模式,这里的上拉下拉的作用就是提供一个默认的电平,即如果这个引脚啥也没接,为了避免引脚悬空而导致的输入数据不确定,通过上拉下拉来给一个确定的电平

3、施密特触发器,给输入的波形整形,

4、输出数据寄存器:如果选择通过输出数据寄存器进行控制(采用基于寄存器开发的开发方法),即普通的IO口输出,对输出数据寄存器进行写操作就可以操作对应的端口了。输出数据寄存器同时控制16个端口(16位),且该寄存器只能整体读写。 如果想单独操作这个数据寄存器的某一位,需要先读出这个寄存器,然后按照按位与和按位或的方式更改该位,最后再将更改后的数据写入。

5、位设置/清除寄存器:可以用来单独操作输出数据寄存器的某一位,而不影响其他位。如果需要对输出数据寄存器的某一位写入1,则在位设置寄存器的对应位置写1,其他位置写0(表示不需要操作)即可;如果想对某一位写0,就在位清除寄存器的对应位置写1,其他位置写0(表示不需要操作)即可。在本课程中主要采用库函数进行操作,库函数使用的就是操作位设置/清除寄存器的方法。
  在STM32中,操作寄存器的某一位还可以操作 “位带” 区域,类似于51单片机中的位寻址。在STM32中,专门分配有一段地址区域,这段地址映射了RAM和外设寄存器所有的位。读写这段地址中的数据,就相当于读写所映射位置的某一位。在本课程中不会用到该种操作方式。

输出驱动器:由输出数据寄存器和其他片上外设控制,通过一个(二选一)数据选择器链接到输出控制模块。通过设置可以选择推挽、开漏或关闭三种输出方式。
推挽输出模式:又称为“推拉”,“互补”的输出模式。当数据寄存器(复用功能输出)为1时,P-MOS导通,N-MOS截止,输出高电平;数据选择器(复用功能输出)为0时,P-MOS截止,N-MOS导通,输出低电平。在这种模式下,高低电平均有较强的驱动能力 ,所以推挽输出模式也称作强推输出模式。在推挽输出模式下,STM32对IO口具有绝对的控制权 ,高低电平都由STM32说了算。
开漏输出模式:意为N-MOS的漏极和V D D V_{DD}V 
DD

 是开路的,即P-MOS开路(无效)。数据寄存器(复用功能输出)为1时,N-MOS断开,这时IO口呈现高阻模式(没有驱动能力);数据寄存器(复用功能输出)为0时,N-MOS导通,输出低电平。这种模式下只有低电平有驱动能力。 开漏输出模式可以作为通信协议的驱动方式,例如I2C。在多机通信的情况下,这个模式可以避免各个设备的相互干扰。此外,开漏输出可以通过外接上拉电源和电阻以提高端口的带载能力,或兼容一些 5 V 5V5V 输入的设备(输出 5 V 5V5V 的电平信号)。
关闭状态:意为当引脚配置为输入模式时,两个MOS管都无效(开路),端口的电平由外部信号控制。(高阻态,没有驱动能力)

gpio android 输入 高电平 gpio高电平电压_gpio android 输入 高电平_03

端口配置寄存器 GPIOx_CRL/GPIOx_CRH (Configuration Register Low/High)
  在一个GPIO中,每一个端口需要4位进行配置,16个端口就需要64位进行配置。由于STM32的寄存器都是32位的,故一共需要两个寄存器,分为端口配置低寄存器和端口配置高寄存器。在端口配置寄存器中还可以定义GPIO输出的速度,即限制输出引脚的最大翻转频率,设计输出速度的目的是调节功率和稳定性。
端口输入数据寄存器 GPIOx_IDR (Input Data Register)
  端口输入数据寄存器的低16位对应16个引脚,高16位没有使用。
端口输出数据寄存器 GPIOx_ODR (Output Data Register)
  与输入数据寄存器相同,端口输出数据寄存器的低16位对应16个引脚,高16位没有使用。
端口位设置/清除寄存器 GPIOx_BSRR (Bit Set/Reset Register)
  该寄存器的高16位实现位清除,低16位实现位设置。如果想对多个端口同时进行位设置和位清除,即对GPIO信号的同步性要求较高,可以只使用这一个寄存器。
端口位清除寄存器 GPIOx_BRR (Bit Reset Register)
  该寄存器的低16位实现位清除,高16位没有使用。它可以与上面一个寄存器配合使用,使用时两个寄存器都只使用寄存器的低16位,操作更为方便。
端口配置锁定寄存器 GPIO_LCKR (Configuration Lock Register)
  该寄存器可以对端口的配置进行锁定,防止意外更改。
 

二、实例

gpio android 输入 高电平 gpio高电平电压_单片机_04

void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);

GPIO外设也有很多库函数,目前需要了解和学习的是以下函数(其中最重要的是GPIO_Init和八个读写函数)

// 使指定的GPIO外设复位
void GPIO_DeInit(GPIO_TypeDef* GPIOx);

// 使指定的AFIO外设复位	
void GPIO_AFIODeInit(void);

// 用结构体的参数初始化GPIO口
// 基本上STM32的所有外设都使用Init函数进行初始化
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

// 给结构体变量赋一个默认值
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);

// 下面四个是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);

// 下面四个是GPIO的输出函数
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);	// 这个函数可以对16个端口同时进行写入操作

配置GPIO的工作模式需要对GPIO_InitStructure.GPIO_Mode赋值,其对应的枚举的值的定义如下

typedef enum
{ GPIO_Mode_AIN = 0x0,	// Analog_Input 模拟输入
  GPIO_Mode_IN_FLOATING = 0x04,	// IN_FLOATING 浮空输入
  GPIO_Mode_IPD = 0x28, // Input_Pull_Down 下拉输入
  GPIO_Mode_IPU = 0x48, // Input_Pull_Up 上拉输入
  GPIO_Mode_Out_OD = 0x14,	// Output_Open_Drain 开漏输出
  GPIO_Mode_Out_PP = 0x10,	// Output_Push_Pull 推挽输出
  GPIO_Mode_AF_OD = 0x1C,	// Alternate_function_Open_Drain 复用开漏
  GPIO_Mode_AF_PP = 0x18	// Alternate_function_Push_Pull 复用推挽
}GPIOMode_TypeDef;

1.1、GPIO实现LED闪烁

gpio android 输入 高电平 gpio高电平电压_学习_05

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

int main()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 定义结构体变量,它是一个局部变量,有些过时的编译器不支持在程序中间定义局部变量,需要在最前面声明定义
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 接下来是GPIO输入函数的使用
	// GPIO_SetBits(GPIOA, GPIO_Pin_0);		// 给相应端口设置高电平
	// GPIO_ResetBits(GPIOA, GPIO_Pin_0);	// 给相应端口设置低电平
	// GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);	// 在相应端口写入数据 (Bit_RESET是一个枚举,它就是写入的数据,意为写入低电平)
	GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);	// 在相应端口写入数据,意为写入高电平
	while(1)
	{
		// 下面三种方式都可以实现LED闪烁
		GPIO_ResetBits(GPIOA, GPIO_Pin_0);
		Delay_ms(500);
		GPIO_SetBits(GPIOA, GPIO_Pin_0);
		Delay_ms(500);
		
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
		Delay_ms(500);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
		Delay_ms(500);
		
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);	// 第三个参数直接写1,或者写0会报出一个警告,原因是1和0不是BitAction这个枚举类型,所以需要用到强制类型转换
		Delay_ms(500);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);
		Delay_ms(500);
	}
}

1.2、LED流水灯

gpio android 输入 高电平 gpio高电平电压_学习_06

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

int main()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;	// 选中所有引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	
	while(1)
	{
		// GPIO_Write函数可以对16个端口同时进行写入操作
		GPIO_Write(GPIOA, ~0x0001);	// 0000 0000 0000 0001 低电平驱动,PA0置低电平
		Delay_ms(500);
		GPIO_Write(GPIOA, ~0x0002);	// 0000 0000 0000 0010 低电平驱动,PA1置低电平
		Delay_ms(500);
		GPIO_Write(GPIOA, ~0x0004);	// 0000 0000 0000 0100 低电平驱动,PA2置低电平
		Delay_ms(500);
		GPIO_Write(GPIOA, ~0x0008);	// 0000 0000 0000 1000 低电平驱动,PA3置低电平
		Delay_ms(500);
		GPIO_Write(GPIOA, ~0x0010);	// 0000 0000 0001 0000 低电平驱动,PA4置低电平
		Delay_ms(500);
		GPIO_Write(GPIOA, ~0x0020);	// 0000 0000 0010 0000 低电平驱动,PA5置低电平
		Delay_ms(500);
		GPIO_Write(GPIOA, ~0x0040);	// 0000 0000 0100 0000 低电平驱动,PA6置低电平
		Delay_ms(500);
	}
}

 其中~是所有位取反,因为该示例是低电平点亮

1.3、蜂鸣器

gpio android 输入 高电平 gpio高电平电压_gpio android 输入 高电平_07

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

int main()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

	GPIO_InitTypeDef GPIO_InitStructure_B;
	GPIO_InitStructure_B.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure_B.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure_B.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(GPIOB, &GPIO_InitStructure_B);
	
	while(1)
	{
		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);
	}
}

 本小节实现两个现象:按键控制LED亮灭和光敏传感器控制蜂鸣器模块。在之后的编程实践中,用Delay函数一样,对外设功能的实现都采用模块化编程的方式
  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);

新建工程组Hardware,对各个外设模块化的过程可以分为以下四步:

在工程组中方新建模块化文件xxx.c/.h,在xxx.c中首先添加#include "stm32f10x.h",在xxx.h中添加#ifndef防止重定义格式;
定义xxx_Init初始化函数,在该函数中完成对GPIO工作模式的配置和默认电平的选择;
在xxx.c文件定义外设对应的功能函数;
将xxx.c文件中所有的函数头添加到xxx.h文件中,以声明这些函数可供外部调用。
 

2.1 按键实验

gpio android 输入 高电平 gpio高电平电压_gpio android 输入 高电平_08

LED.h

#ifndef __LED_H__
#define __LED_H__

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

#endif

 LED.c

#include "stm32f10x.h"                  // Device header

/**
  * @brief  LED的初始化函数,将GPIOA配置为推挽输出模式
  * @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;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 如果不加入以下操作,GPIO配置完成后默认为低电平
	
	GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);	// 默认将GPIO设置为高电平
}

/**
  * @brief  点亮LED1,将PA1置低电平
  * @param  无
  * @retval 无
  */
void LED1_ON(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}

/**
  * @brief  熄灭LED1,将PA1置高电平
  * @param  无
  * @retval 无
  */
void LED1_OFF(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_1);
}

/**
  * @brief  点亮LED2,将PA2置低电平
  * @param  无
  * @retval 无
  */
void LED2_ON(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}

/**
  * @brief  熄灭LED2,将PA2置高电平
  * @param  无
  * @retval 无
  */
void LED2_OFF(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_2);
}

/**
  * @brief  LED1的翻转函数,实现按一下点亮,再按一下熄灭
  * @param  无
  * @retval 无
  */
void LED1_Turn(void)
{
	if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0)	// GPIOA处于输出模式,如果此时GPIOA_Pin_1输出0(LED1亮)
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_1);	// 将灯熄灭
	}
	else	// 如果此时GPIOA_Pin_1输出为1(LED1灭)
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_1);	// 将灯点亮
	}
}

/**
  * @brief  LED2的翻转函数,实现按一下点亮,再按一下熄灭
  * @param  无
  * @retval 无
  */
void LED2_Turn(void)	// LED2的翻转函数,实现按一下点亮,再按一下熄灭
{
	if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0)	// GPIOA处于输出模式,如果此时GPIOA_Pin_2输出0(LED2亮)
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_2);	// 将灯熄灭
	}
	else	// 如果此时GPIOA_Pin_2输出为1(LED2灭)
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);	// 将灯点亮
	}
}

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_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	// 这里的速度是GPIO的输出速度,在输入模式下这个参数选择没有用处
	
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/**
  * @brief  返回按下按键的值,若不按下按键默认返回0
  * @param  无
  * @retval KeyNum 按键对应的值
  */
uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;
	
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)	// 读取1端口的值
	{
		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;
}

main.c

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

uint8_t KeyNum;	// 全局变量,用于存储按键对应的值

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

2.2光敏传感器控制蜂鸣器

gpio android 输入 高电平 gpio高电平电压_学习_09

Buzzer.c

#include "stm32f10x.h"                  // Device header

/**
  * @brief  蜂鸣器的初始化函数,将GPIOB配置为推挽输出模式
  * @param  无
  * @retval 无
  */
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配置完成后默认为低电平
	
	GPIO_SetBits(GPIOB, GPIO_Pin_12);	// 默认将PB12设置为高电平(蜂鸣器为低电平驱动)
}

/**
  * @brief  蜂鸣器报警,将PB12置低电平
  * @param  无
  * @retval 无
  */
void Buzzer_ON(void)
{
	GPIO_ResetBits(GPIOB, GPIO_Pin_12);
}

/**
  * @brief  蜂鸣器不报警,将PB12置高电平
  * @param  无
  * @retval 无
  */
void Buzzer_OFF(void)
{
	GPIO_SetBits(GPIOB, GPIO_Pin_12);
}

/**
  * @brief  蜂鸣器的翻转函数
  * @param  无
  * @retval 无
  */
void Buzzer_Turn(void)
{
	if (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12) == 0)	// GPIOB处于输出模式,如果此时GPIOB_Pin_12输出0(蜂鸣器报警)
	{
		GPIO_SetBits(GPIOB, GPIO_Pin_12);	// 蜂鸣器不报警
	}
	else	// 如果此时GPIOB_Pin_12输出为1(蜂鸣器不报警)
	{
		GPIO_ResetBits(GPIOB, GPIO_Pin_12);	// 蜂鸣器报警
	}
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Buzzer.h"
#include "LightSensor.h"

int main()
{
	Buzzer_Init();
	Light_Sensor_Init();
	
	while(1)
	{
		if (Light_Sensor_Get() == 1)	// 如果感光模块输出为1(光线暗)
		{
			Buzzer_ON();
		}
		else	// 如果光线明亮
		{
			Buzzer_OFF();
		}
	}
}

 LightSensor.c 

#include "stm32f10x.h"                  // Device header

/**
  * @brief  光敏传感器初始化函数(GPIO配置)
  * @param  无
  * @retval 无
  */
void Light_Sensor_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);
}

/**
  * @brief  获取当前的输入数据
  * @param  无
  * @retval 输入寄存器对应位的数据
  */
uint8_t Light_Sensor_Get(void)
{
	return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
}