一、LED模块
(1)LED回顾
在上一次的学习中,我们学习了如何点亮LED灯,并且实现了LED灯的闪烁,如果我们想要通过按键来控制LED灯的亮灭,假设按键按下我们会检测到一个信号,此时如果灯是亮的那么就让灯熄灭,如果灯是灭的就让灯亮,这样就可以通过一个按键来控制一个LED灯的亮灭了,可以发现,如果我们把所有的函数都放在主函数里,那代码将非常长,既不利于阅读也不利于代码的移植,因此我们新建一个led.c文件来存放LED有关的函数,新建一个led.h文件作为此文件的头文件
(2)LED模块
我们在文件开始前先做一些准备工作,以便后面的编程,首先我们先把需要的头文件引入,再定义一下我们要初始化的端口,这样当我们需要修改LED的位置时只要修改前面的define就可以了
#include "stm32f10x.h" // Device header
#define io_clock RCC_APB2Periph_GPIOA
#define io GPIOA
#define led_1 GPIO_Pin_1
#define led_2 GPIO_Pin_2
然后我们和上次的思路一样,我们先要把LED的那几个GPIO口初始化,我们把它写成一个函数,在这个函数内对端口初始化,在操作LED之前,先调用这个函数来对LED进行初始化,这样其他函数才能正确使用
void led_init()
{
RCC_APB2PeriphClockCmd(io_clock, ENABLE);
GPIO_InitTypeDef gpio_init;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_init.GPIO_Pin = led_1 | led_2;
gpio_init.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(io, &gpio_init);
GPIO_SetBits(io, led_1 | led_2);
}
我们把LED需要初始化的代码封装成了一个函数,这样我们要使用LED的时候只要在主函数中条用一下这个初始化函数就可以完成对LED灯的初始化了。
那么接下来我们要实现的就是LED状态翻转函数了,如果LED是亮的话,那么调用这个函数就可以使其灭,反之亦然,我们之前学习的都是LED的输出函数,GPIO也有一些常见的输入函数,便于我们信号的读取,下面是GPIO的一些常用的输入函数
同样我们可以用跳转定义的方法来了解这四个函数,其实从函数名上也可以知道大概,第一个是读取某一位的输入数据,第二个是读取输入寄存器,也就是读取所有位的输入数据,第三个读取的是某一位的输出数据,第四个读取的是输出寄存器的所有值,也就是读取所有位的输出数据,那么这里我们只用第三个来读取LED灯位置的输出数据就可以完成翻转,我们的两个LED位置翻转可以分成两个函数写
void led1_flip()
{
if (GPIO_ReadOutputDataBit(io, led_1))
{
GPIO_ResetBits(io, led_1);
}
else
{
GPIO_SetBits(io, led_1);
}
}
void led2_flip()
{
if (GPIO_ReadOutputDataBit(io, led_2))
{
GPIO_ResetBits(io, led_2);
}
else
{
GPIO_SetBits(io, led_2);
}
}
到这里我们的LED程序模块就写好了,我们在主程序中只要先初始化,然后在有按键信号来的时候调用一下对应的LED翻转程序就可以了,那我们把这些函数在头文件上声明,使其成为外部可调用函数
#ifndef __LED_H__
#define __LED_H__
void led_init(void);
void led1_flip(void);
void led2_flip(void);
#endif
二、按键模块
经过之前的分析我们知道,按键模块要实现的功能无非就是一个,那就是我们在对应的端口有按键信号时告诉主程序,我们把两个按键分别接在PB6和PB14口上;
先写好初始化按键的程序,和之前写LED的初始化程序思路一样,注意的是这里我们的按键是接在PB口上,因此我们要使能的是GPIOB
#include "stm32f10x.h" // Device header
#include "Delay.h"
#define io_clock RCC_APB2Periph_GPIOB
#define io GPIOB
#define key1 GPIO_Pin_6
#define key2 GPIO_Pin_14
void button_init()
{
RCC_APB2PeriphClockCmd(io_clock, ENABLE);
GPIO_InitTypeDef gpio_init;
gpio_init.GPIO_Pin = key1 | key2;
gpio_init.GPIO_Mode = GPIO_Mode_IPU;
gpio_init.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(io, &gpio_init);
}
按键的一端连接低电平,一端连接到单片机的IO口上,所以我们选择的是上拉输入模式(gpio_init.GPIO_Mode = GPIO_Mode_IPU)这样我们在按键按下时得到的信号位低电平信号,在按键没有按下的时候得到的信号位默认的高电平信号;
在检测IO口高低电平时,我们还要注意一下按键的消抖问题,我们暂停20ms再进行检测,这里了解之前读取IO口的函数后,程序的设计和51单片机的差不多
unsigned char get_button()
{
unsigned char key = 0;
if (GPIO_ReadInputDataBit(io, key1) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(io, key1) == 0);
Delay_ms(20);
key = 1;
}
else if (GPIO_ReadInputDataBit(io, key2) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(io, key2) == 0);
Delay_ms(20);
key = 2;
}
return key;
}
之后我们和LED一样在头文件上把这两个函数做好声明就完成了按键模块的程序编写
三、主程序
有了按键模块和LED模块后,主程序的设计就显得明朗了,我们无非是读取按键的值,判断按键是否按下,如果按下就调用LED的翻转函数,可以这样设计
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "led_light.h"
#include "key_button.h"
int main()
{
unsigned char button;
led_init();
button_init();
while(1)
{
button = get_button();
if (button == 1)
{
led1_flip();
}
else if (button == 2)
{
led2_flip();
}
}
return 0;
}
四、自动开灯
通过之前的学习我们已经熟悉了IO口的输入输出操作了,我们可以用光敏传感器模块来实现一个当环境亮度变暗就自动开灯的程序,我们把光敏传感器模块的DO(数字输出口)接入PB14中,当光线亮时其输出值为0,光线暗时输出为1(可以设置相对的光线比较),我们用之前一样的思路来构建其模块
#include "stm32f10x.h" // Device header
#define io_init RCC_APB2Periph_GPIOB
#define io GPIOB
#define sensor_loc GPIO_Pin_14
void sensor_init()
{
RCC_APB2PeriphClockCmd(io_init, ENABLE);
GPIO_InitTypeDef gpio_init;
gpio_init.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio_init.GPIO_Pin = sensor_loc;
gpio_init.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &gpio_init);
}
unsigned char get_sensor()
{
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14);
}
同样我们在头文件对以上函数进行声明,在主函数上对其调用就可以了,当我们检测到PB14口输入高电平时,我们开启LED灯,当我们检测到低电平时熄灭LED灯,通过这样的一个简单地输入输出IO口数据我们就实现了一个黑暗自动开灯的程序
五、总结
通过按键按下来操控LED和黑暗自动开灯程序。我们了解了GPIO口的输入函数,结合之前的知识,我们应该有了对IO口输入和输出的能力。