目录
- 一、模块化
- 二、LED交替闪烁
- 1. LED.c
- 2. LED.h
- 3. 主函数
- 三、按键控制LED
- 1. Key.c
- 2. Key.h
- 3. LED.c
- 4. LED.h
- 5. 主函数
一、模块化
前篇介绍了如何向项目添加模块,本篇将进一步介绍模块的编写与封装。随着模块的增加,需要用到Manage Project Items
,以便于快速新建目录、添加已有文件和调整目录次序。
新建模块Hardware
,与第一篇创建主函数文件同理,在目录下新建两组C
语言源代码文件和头文件,拓展名分别为.c
和.h
,并在Path Include
完成路径添加。
二、LED交替闪烁
通过构建LED
驱动模块简化灯控程序的代码。在A1
和A2
端口接入LED
,完成模块构建后运行主函数。
1. LED.c
#include "stm32f10x.h"
// LED端口初始化
void LED_Init(void)
{
// 使能/失能APB2的外设时钟 -> 开启IO端口A时钟
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; // PA1和PA2引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 最大速度50MHz
// 配置端口模式 -> 初始化GPIOA外设时钟
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
// 点亮A1灯
void LED1_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
// 熄灭A1灯
void LED1_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
// 点亮A2灯
void LED2_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2); // 低电平:点亮LED2
}
// 熄灭A2灯
void LED2_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_2); // 高电平:熄灭LED2
}
2. LED.h
#ifndef __LED_H // 如果__LED_H未被定义,则执行关键字#define与#endif之间的命令
#define __LED_H
// 对模块外部声明以下函数可被调用
int main(void);
void LED1_ON(void);
void LED1_OFF(void);
void LED2_ON(void);
void LED2_OFF(void);
#endif
3. 主函数
#include "stm32f10x.h" // 器件模块
#include "Delay.h" // 延时模块
#include "LED.h" // LED驱动模块
// 双灯交替闪烁
int main(void)
{
LED_Init(); // LED端口初始化
while(1)
{
LED1_ON();
LED2_OFF();
Delay_ms(200);
LED1_OFF();
LED2_ON();
Delay_ms(200);
}
}
三、按键控制LED
通过两个按键分别控制两个LED
的亮灭,在A1
和A2
端口接入LED
,B1
和B11
端口与零线之间接入按键。(除了上篇提过的J-Link
调试端口,其他GPIO
均可随意使用)
按下按键时,开关闭合,电流导入零线,B
端输入低电平0
;松开按键时,开关断开,B
端输入高电平1
。由图可见,按键端口在常态下输入高电平,而在按键按下与松开的过程中存在电流波动,称为按键抖动,需要进行延时消除处理。
1. Key.c
根据上文分析,按键按下一次产生的电平变化可被程序检测,并向LED
驱动模块发出控制信号,其数据类型为uint8_t
,即unsigned char
.
#include "stm32f10x.h"
#include "Delay.h"
// 按键端口初始化
void Key_Init(void)
{
// 使能/失能APB2的外设时钟 -> 开启IO端口B时钟
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; // PBA1和PB11引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 最大速度50MHz
// 配置端口模式 -> 初始化GPIOB外设时钟
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
// 监控按键信号
uint8_t Key_GetNum(void)
{
// 初始化信号:松开
uint8_t KeyNum = 0;
// 检测到B1输入低电平
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)==0)
{
Delay_ms(20); // 消除按键抖动:按下
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)==0); // 持续按下,直至松开
Delay_ms(20); // 消除按键抖动:松开
KeyNum = 1; // B1端按键被按下了一次
}
// 检测到B11输入低电平
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)==0)
{
Delay_ms(20); // 消除按键抖动:按下
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)==0); // 持续按下,直至松开
Delay_ms(20); // 消除按键抖动:松开
KeyNum = 2; // B11端按键被按下了一次
}
return KeyNum; // 发送按键信号
}
2. Key.h
#ifndef __KEY_H // 如果__KEY_H未被定义,则执行关键字#define与#endif之间的命令
#define __KEY_H
// 对模块外部声明以下函数可被调用
void Key_Init(void);
uint8_t Key_GetNum(void);
#endif
3. LED.c
#include "stm32f10x.h"
// LED端口初始化
void LED_Init(void)
{
// 使能/失能APB2的外设时钟 -> 开启IO端口A时钟
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; // PA1和PA2引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 最大速度50MHz
// 配置端口模式 -> 初始化GPIOA外设时钟
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 端口电平初始化:高电平,熄灭
GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);
}
// LED1开关:切换电平输入
void LED1_Turn(void)
{
// A1端LED输出低电平:点亮
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)
{
// A1端LED输出低电平:点亮
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2)==0)
{
GPIO_SetBits(GPIOA, GPIO_Pin_2); // 熄灭
}
else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}
}
4. LED.h
#ifndef __LED_H // 如果__LED_H未被定义,则执行关键字#define与#endif之间的命令
#define __LED_H
// 对模块外部声明该函数可被调用
void LED_Init(void);
void LED1_Turn(void);
void LED2_Turn(void);
#endif
5. 主函数
#include "stm32f10x.h" // 器件模块
#include "Delay.h" // 延时模块
#include "LED.h" // LED驱动模块
#include "Key.h" // 按键监控模块
uint8_t KeyNum; // 定义全局变量:按键信号
// 按键控制LED![请添加图片描述](https://i-blog.csdnimg.cn/direct/ab1af9a1642b4efea4369bcebdbb7544.jpeg)
int main(void)
{
// 端口初始化
LED_Init();
Key_Init();
while(1)
{
// 监控并接收按键端口信号
KeyNum = Key_GetNum();
// B1按键控制A1灯:按下一次切换亮灭
if (KeyNum == 1)
{
LED1_Turn();
}
// B11按键控制A2灯:按下一次切换亮灭
if (KeyNum == 2)
{
LED2_Turn();
}
}
}