传感器模块简介
•传感器模块:传感器元件(光敏电阻/热敏电阻/红外接收管等)的电阻会随外界模拟量的变化而变化,通过与定值电阻分压即可得到模拟电压输出,再通过电压比较器进行二值化即可得到数字电压输出
硬件电路
下接方式
在这种接法下,当按键按下,PA0会直接下拉到GND,此时读取PA0口的电压是低电平;
在松开按钮后,PA0会悬空,会导致PA0口的电压不确定,所以此时PA0口必须是上拉输入模式,
所以按下按键,引脚为低电平,松开,引脚变高电平。
下图区别于上图加了一个上拉电阻,当按下按键,引脚接到GND为低电平,松手后,由于上拉作用,引脚变为高电平。所以此时PA0可以配置为浮空输入或者上拉输入模式。
上接方式
原理类似于下接方式
C语言知识
数据类型
typedef
typedef unsigned char uint8_t;
uint8_t a; //等效于unsigned char a;
只能用于变量改名
结构体配合typedef可以做到快速定义结构体
在STM32中有体现
枚举
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();
}
}
}