1 GPIO输出
1.1 按键简介
按键:常见的输入设备,按下导通,松手断开
按键抖动:由于按键内部使用的是机械式弹簧片来进行通断的,所以在按下和松手的瞬间会伴随有一连串的抖动
1.2 传感器模块简介
传感器模块:传感器元件(光敏电阻/热敏电阻/红外接收管等)的电阻会随外界模拟量的变化而变化,通过与定值电阻分压即可得到模拟电压输出,再通过电压比较器进行二值化即可得到数字电压输出
分别是光敏电阻传感器(光线越强,光敏电阻的阻值就越小)
热敏电阻传感器(温度越强,热敏电阻的阻值就越小)
对射式红外传感器(红外越强,红外接收管的阻值就越小)
反射式红外传感器
滤波电容:保持电路稳定
硬件电路
一般是这种(下接模式)
第一张图,当K1按下,PA0被下拉到GND,此时读取PAO口的电压就是低电平;
当K1松开,PA0被悬空,引脚的电压不确定,此时必须要求PA0是上拉输入,否则会出现引脚电压不稳定的错误现象。
第二张图多了一个上拉电阻。当按键按下时,PA0被下拉到GND,此时读取PAO口的电压就是低电平;
当按键松开时,引脚由于上拉作用,自然保持高电平。
这种接法下,PA0需要配置成上拉输入或者浮空输入。
所以上面这两种接法,按键按下是低电平,松手是高电平。
上接模式
第三张图,PA0通过按键接到3.3V,要求PA0必须配置成下拉输入的模式。
当按键按下时,引脚为高电平;松手时,引脚为低电平。(一般单片机可能没有下拉输入模式)
第四张图,PA0需要配置成下拉输入或者浮空输入。
下面这两种接法,按键按下是高电平,松手是低电平。
传感器模块
DO是数字输出;AO是模拟输出(ADC模拟转换器)。
C语言数据类型
|--------------------|--------|---------------------------|-------------------|---------------|
| 关键字 | 位数 | 表示范围 | stdint****关键字 | ST****关键字 |
| char | 8 | -128 ~ 127 | int8_t | s8 |
| unsigned char | 8 | 0 ~ 255 | uint8_t | u8 |
| short | 16 | -32768 ~ 32767 | int16_t | s16 |
| unsigned short | 16 | 0 ~ 65535 | uint16_t | u16 |
| int | 32 | -2147483648 ~ 2147483647 | int32_t | s32 |
| unsigned int | 32 | 0 ~ 4294967295 | uint32_t | u32 |
| long | 32 | -2147483648 ~ 2147483647 | | |
| unsigned long | 32 | 0 ~ 4294967295 | | |
| long long | 64 | -(2^64)/2 ~ (2^64)/2-1 | int64_t | |
| unsigned long long | 64 | 0 ~ (2^64)-1 | uint64_t | |
| float | 32 | -3.4e38 ~ 3.4e38 | | |
| double | 64 | -1.7e308 ~ 1.7e308 | | |
2 GPIO输入之按键控制LED灯
2.1 接线图
低电平点亮
2.2 封装模块
新建文件夹HardWare,模块化代码
先封装GPIO。LED.c,记得加上LED.h
cpp
#include "stm32f10x.h" // Device header
// LED初始化函数
void LED_Init(void)
{
// 1使用RCC开启GPIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 2使用GPIO_Init函数初始化GPIO[推挽输出50MHz]
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 3初始化熄灭
GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);
}
// 点亮LED1函数
void LED1_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
// 熄灭LED1函数
void LED1_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
// 点亮LED2函数
void LED2_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}
// 熄灭LED2函数
void LED2_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_2);
}
// LED1反转
void LED1_Turn(void)
{
// 读取当前端口输出状态,如果输出是0,就置1;否则置0
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
}
// LED2反转
void LED2_Turn(void)
{
// 读取当前端口输出状态,如果输出是0,就置1;否则置0
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0)
{
GPIO_SetBits(GPIOA, GPIO_Pin_2);
}
else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}
}
再封装按键。KEY.c,记得加上KEY.h
cpp
#include "stm32f10x.h" // Device header
#include "Delay.h"
// 按键初始化函数
// 上拉输入模式
void KEY_Init(void)
{
// 1使用RCC开启GPIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 2使用GPIO_Init函数初始化GPIO[推挽输出50MHz]
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_Init(GPIOB, &GPIO_InitStructure);
}
// 读取按键的值
uint8_t KEY_GetNum(void)
{
uint8_t KeyNum = 0;
// 1号端口
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
// 刚按下,有抖动
Delay_ms(20);
// 检查按键松手
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
Delay_ms(20);
KeyNum = 1;
}
}
// 11号端口
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;
}
2.3 主函数
测试代码,主函数
cpp
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
uint8_t keyNum;
int main()
{
LED_Init();
KEY_Init();
while (1)
{
keyNum = KEY_GetNum();
// 按键1按下,点亮LED1
if (keyNum == 1)
{
LED1_Turn();
}
// 按键2按下,熄灭LED1
if (keyNum == 2)
{
LED2_Turn();
}
}
}
代码结构图
我的按键11不起作用,不能控制GPIOA_Pin_2的亮灭。