写在前面:本系列内容均为自学笔记,参考资料为野火指南者开发板资料及芯片参考手册等,使用野火指南者开发板进行学习,该系列内容仅用于记录笔记,不做其他用途,笔记的内容可能会存在不准确或者错误等,如有大佬看到错误内容还望能够评论指正,感谢各位。
本节包括前几节的程序,请参考野火开发板资料,里面由更加清晰的教学,野火B站账号:野火官方B站账号链接。
修改记录:
各位在复制程序时注意一下下面的小问题,程序中部分注释是笔者复制程序过来之后才注释的,可能会有所疏漏
1、对bsp_key.c中的注释修改,注释时有一个标点未注释掉;已更改
学习目标
1、检测一个按键,并通过按键控制LED灯的亮灭;
2、检测两个按键,并用按键控制LED灯的亮灭,且两个按键的功能不可以相互影响(本节用的灯与上一节相同,是一个红绿蓝三色混色灯(RGB灯),该灯最多可组合出256中颜色,本节只使用红绿两种颜色)。
电路图
本电路图仅供参考。
一、检测一个按键,并控制LED灯亮灭
由于学习目标二的程序是紧接着目标一的,所以在定义函数及声明时会连带目标二所需要的函数及声明一起定义好;
bsp_key.c中的程序如下:
#include "bsp_key.h"
void KEY_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义变量,方便赋值
//初始化GPIOA
RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK,ENABLE); //打开APB2时钟,GPIOA挂载在APB2
GPIO_InitStruct.GPIO_Pin = KEY1_GPIO_PIN; //设置需要用到的管脚,KEY1_GPIO_PIN看.h文件
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设置输入模式为浮空输入
GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStruct); //加上&,方便取值 //初始化GPIOA
//初始化GPIOC
RCC_APB2PeriphClockCmd(KEY2_GPIO_CLK,ENABLE); //打开APB2时钟,GPIOC挂载在APB2
GPIO_InitStruct.GPIO_Pin = KEY2_GPIO_PIN; //设置需要用到的管脚,KEY2_GPIO_PIN看.h文件
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设置输入模式为浮空输入
GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStruct); //加上&,方便取值 //初始化GPIOC
}
uint8_t Key_Scan(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{//按键检测
if(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == KEY_ON) //GPIO状态读取函数
{
while(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == KEY_ON);//松手检测
return KEY_ON;
}
else
return KEY_OFF;
}
bsp_key.h中的程序如下:
#ifndef _BSP_KEY_H
#define _BSP_KEY_H
#include "stm32f10x.h" //要包含固件库的.h文件
#define KEY_ON 1
#define KEY_OFF 0
//按键1的声明
#define KEY1_GPIO_PIN GPIO_Pin_0 //按键1管脚
#define KEY1_GPIO_PORT GPIOA //定义用到的GPIO
#define KEY1_GPIO_CLK RCC_APB2Periph_GPIOA //定义RCC时钟寄存器
//按键2的声明
#define KEY2_GPIO_PIN GPIO_Pin_13 //按键2管脚
#define KEY2_GPIO_PORT GPIOC //定义用到的GPIO
#define KEY2_GPIO_CLK RCC_APB2Periph_GPIOC //定义RCC时钟寄存器
void KEY_GPIO_Config(void);
uint8_t Key_Scan(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
#endif
上述两程序是关于按键的定义,由于是定义按键,在实际操作时,单片机只需要读取按键所在管脚的状态即可,所以对于单片机来说,按键属于输入信号,因此按键管脚要定义为输入模式,而通过电路图可知,按键是由接下拉电阻的,所以设置为浮空输入即可;按键检测函数Key_Scan()中的程序表示当识别按键按下时,将1返回,此时单片机就可以读取到返回值,进而可以通过程序进行控制,反之则返回0,此时将不能进行控制(这是return的用法,本人不是很熟悉,应该是这个意思);另外Key_Scan()函数中的while循环是松手检测用的,当手按下按键,按键端口电平变为1,就会进入该循环,当检测到手松开按键即按键弹起,按键端口电平重新变为0时,将会退出循环并将检测到的值1返回,同理反之,返回0;
bsp_led.c中的程序如下:
//BSP:board support package 板级支持包,仅适用于野火开发板
#include "bsp_led.h"
void LED_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义变量,方便赋值
RCC_APB2PeriphClockCmd(LED_G_GPIO_CLK,ENABLE); //打开APB2时钟,GPIO挂载在APB2
//GPIO_PIN的部分用或将用到的管脚初始化为一个十六进制数据,原本是三个十六进制
GPIO_InitStruct.GPIO_Pin = (LED_G_GPIO_PIN|LED_R_GPIO_PIN); //设置需要用到的管脚,LED_G_GPIO_PIN看.h文件
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //设置输出模式为推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //设置输出速率为50MHz,LED_G_GPIO_CLK看.h文件
GPIO_Init(LED_G_GPIO_PORT, &GPIO_InitStruct); //加上&,方便取值 //初始化GPIO
}
bsp_led.h中的程序如下:
#ifndef _BSP_LED_H
#define _BSP_LED_H
#include "stm32f10x.h" //要包含固件库的.h文件
#define LED_G_GPIO_PIN GPIO_Pin_0 //定义绿灯管脚号
#define LED_R_GPIO_PIN GPIO_Pin_5 //定义红灯管脚号
#define LED_G_GPIO_PORT GPIOB //定义用到的GPIO
#define LED_G_GPIO_CLK RCC_APB2Periph_GPIOB //定义RCC时钟寄存器
//下面这个声明是用于将PIN0取反的,“^”为异或符号,同0不同1
#define LED_G_TOGGLE {LED_G_GPIO_PORT->ODR ^= LED_G_GPIO_PIN;}
#define LED_R_TOGGLE {LED_G_GPIO_PORT->ODR ^= LED_R_GPIO_PIN;}
void LED_GPIO_Config(void); //.c文件中的函数声明
#endif /*_BSP_LED_H*/
上述程序主要是对LED灯所在的端口进行初始化定义,配置端口为推挽输出模式
main.c中的程序如下:
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_key.h"
int main(void)
{
// 来到这里的时候,系统的时钟已经被配置成72M。
LED_GPIO_Config(); //LED端口初始化
KEY_GPIO_Config(); //按键端口初始化
while(1)
{
if(Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON)
{
LED_G_TOGGLE;
}
}
}
在上述程序中,通过Key_Scan()函数来检测按键状态,当检测到KEY_ON时,此时表示按键已经按下,当按键松开后就会执行LED_G_TOGGLE;程序,该程序在bsp_led.h文件中有定义,当执行该程序时,GPIO_ODR寄存器就会与相关GPIO_Pin的值相异或,我们用到的GPIO_Pin为16位的数值,其中只有1位为1,当ODR寄存器与之相异或时,若相对应位的数值相同,则ODR中相应位的值变为0,反之如果不同,则ODR寄存器相应位变为1,以此来实现对LED灯的控制;
二、检测两个按键,并分别控制1种颜色的灯
这个学习目标我们只改变两个文件的程序,其他按照上面的即可,程序如下:
bsp_led.c中的程序
//BSP:board support package 板级支持包,仅适用于野火开发板
#include "bsp_led.h"
void LED_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义变量,方便赋值
RCC_APB2PeriphClockCmd(LED_G_GPIO_CLK,ENABLE); //打开APB2时钟,GPIO挂载在APB2
//GPIO_PIN的部分用或将用到的管脚初始化为一个十六进制数据,原本是三个十六进制
GPIO_InitStruct.GPIO_Pin = (LED_G_GPIO_PIN|LED_R_GPIO_PIN); //设置需要用到的管脚,LED_G_GPIO_PIN看.h文件
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //设置输出模式为推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //设置输出速率为50MHz,LED_G_GPIO_CLK看.h文件
GPIO_Init(LED_G_GPIO_PORT, &GPIO_InitStruct); //加上&,方便取值 //初始化GPIO
//由于默认开灯,所以先关闭红灯和绿灯,防止混色
//下面这两段程序最好放在初始化函数里,放main主函数灯上电会闪一下
GPIO_SetBits(GPIOB,LED_G_GPIO_PIN);
GPIO_SetBits(GPIOB,LED_R_GPIO_PIN);
}
这个文件中我们增加了最后两行程序,这两行是为了将灯关闭,由于GPIO_ODR寄存器复位值为0,所以默认GPIO输出0,此时在我们所用的电路中灯会上电点亮,由于我们只有一个灯,为了防止两种灯混色所以先将灯熄灭,当然这两行程序也可以放在主函数中,不过可能会出现上电灯闪一下立即灭的状况;
main.c中的程序如下:
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_key.h"
int main(void)
{
// 来到这里的时候,系统的时钟已经被配置成72M。
LED_GPIO_Config(); //GPIO初始化
KEY_GPIO_Config();
while(1)
{
if(Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON)
{//按键1,控制绿灯
GPIO_SetBits(GPIOB,LED_R_GPIO_PIN);
LED_G_TOGGLE;
}
if(Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON)
{//按键2,控制红灯
GPIO_SetBits(GPIOB,LED_G_GPIO_PIN);
LED_R_TOGGLE;
}
}
}
该程序中需要注意的是当按下其中一个按键的时候会将另一个按键所控制的灯熄灭,使用GPIO_SetBits()函数实现,这是因为如果不熄灭,灯就有可能会混色成其他颜色,这与我们目标颜色不符,所以先将另外一个灯熄灭,再点亮自己控制的灯,就可以稳定实现两个按键控制两个灯的功能,在该程序下,当按下按键1时,将会亮起绿灯,再次按下,绿灯熄灭;同理按下按键2将亮起红灯,再次按下按键2,红灯熄灭;假设先按下按键1,此时绿灯亮起,在这种状态下按下按键2,绿灯将被熄灭,而红灯将被点亮,再次按下按键2,红灯熄灭,当然此时绿灯由于之前的熄灭所以并不会亮起,反之同理。
以上仅作笔记参考,不作教学,感谢观看。