STM32(5):轮训方式让按键点亮LED

发布者:WhisperingGlow最新更新时间:2024-12-31 来源: jianshu关键字:STM32  按键  点亮LED 手机看文章 扫描二维码
随时随地手机看文章

概述

CPU和外设通信的方式有轮训和中断两种方式;所谓轮训就是主动询问某个状态,看看是否是某个值,如果是则采取行动;中断则是一旦发生了,会主动通知CPU;
本章来研究一下通过如何轮训的方式来响应按键事件。


代码概览

#include 'stm32f10x_gpio.h'

#include 'stm32f10x_rcc.h'

#include '../lib/STM32F10x_StdPeriph_Driver/inc/stm32f10x_exti.h'

#include '../lib/STM32F10x_StdPeriph_Driver/inc/misc.h'

#include '../lib/STM32F10x_StdPeriph_Driver/inc/stm32f10x_gpio.h'


void delay(unsigned int time)

{

    unsigned int i = 0;

    while (time--)

    {

        i = 1000000;

        while (i--)

            ;

    }

}


u8 key_read()

{

    u8 result = 0;

    result = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);


    return result;

}


void led_init()

{

    GPIO_InitTypeDef led;


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    led.GPIO_Pin = GPIO_Pin_13;

    led.GPIO_Mode = GPIO_Mode_Out_PP;

    led.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOC, &led);

    GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);

}


void key_init()

{

    GPIO_InitTypeDef key;


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    key.GPIO_Pin = GPIO_Pin_12;

    key.GPIO_Mode = GPIO_Mode_IPD;

    // led.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOB, &key);

    // GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_RESET);

}


void led_opr(int opr){

    if(1 == opr){

        GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);

    }else{

        GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);

    }

}


int main(void)

{

    led_init();

    key_init();

    key_nvid_init();

    while (1)

    {

        if (1 == key_read())

        {

            GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);

        }

        else

        {

            GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);

        }

    }

    return 1;

}


Main函数

从main函数入手,来抽丝剥茧,把轮训方式的实现搞掂。

int main(void)

{

    led_init();

    key_init();

    while (1)

    {

                if (1 == key_read())

                {

                        GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);

                }

                else

                {

                        GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);

                }

    }

    return 1;

}


LED初始化

void led_init()

{

    GPIO_InitTypeDef led;


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    led.GPIO_Pin = GPIO_Pin_13;

    led.GPIO_Mode = GPIO_Mode_Out_PP;

    led.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOC, &led);

    GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);

}


这个在“STM32(4):基于构件库的点亮LED”有详细介绍,左拐即可看到,使能总线,做PC13的初始化/配置工作,然后配置生效,最后执行了一步操作设置PC13为SET,即高电平,这样实现了灭灯的效果,这样,在操作按下按键的时候,可以实现点亮效果。


键盘操作初始化

void key_init()

{

    GPIO_InitTypeDef key;


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    key.GPIO_Pin = GPIO_Pin_12;

    key.GPIO_Mode = GPIO_Mode_IPD;

    GPIO_Init(GPIOB, &key);

}


可以看到,键盘初始化和LED初始化非常类似:

第一步是定义初始化GPIO配置结构体;

第二步是配置GPIO;

第三步是生效GPIO配置;

使用到的引脚

键盘某个按键和GPIOB12引脚相连,另外一端和3v3端口相连;当按键按下的时候,PB12和3.3v电源相连,于是PB12变成了高电平(取值为1),后面就可以根据PB12的值是高电平还是低电平来决定灯的亮灭。


file

上拉电阻 vs. 下拉电阻

GPIO的工作模式为IPD,即Input Push Down,下拉电阻,为什么选择这个工作模式呢?首先是外设要将电平信息传输到GPIO引脚,所以方向是输入(Input),按键在没有按下的情况下是浮空,所以需要通过下拉电阻将浮空电平下拉倒低电平。

什么是浮空?前面我们看到一个引脚,比如LED的PC13,一端要么接着电源(VCC),要么接地;接电源是高电平,接地是低电平,泾渭分明,但是还有一种情况就是既没有接地也没有接电源,其中按键就是这样情况,下按情况下,PB12和3V3的电源联通,PB12是高电平;但是,没有下按的情况下,其实一种未知的装态,电平介于高低电平之间,且电压值未知的一种状态;

对于浮空状态需要明确电平状态,比如在本次按键点亮等的场景,因为按键在按下的状态,明确应该是高电平,所以没有按下的状态应该是低电平的状态;所以需要通过设置工作模式下拉电阻的,这样浮空状态,因为有下拉电阻电路,将会被处理为低电平。

那么什么是下拉电阻?如下图所示,如果外设在联通的时候,GPIO端口(x取值范围是A,B,C等端口组,不同级别的STM32提供的端口组数量不一样,y的取值范围是0~15,共计16个引脚)应该高电平,那么在浮空/ 悬空(开关断开)的时候状态就应该低电平,怎么能够让断开的时候是低电平呢?就是在GPIO上面增加一个下拉电阻,因为开关断开,所以相当于串联了一个无限大的电阻,处于懒惰,或者说前软怕硬的电路特性,电路走的就是下拉电阻支路,于是GPIOxy在接口浮空的请跨年,处于低电平装填;


file

类似的是上拉电阻,使用的场景正好和下拉电阻相反,适合于开关另一端接地,浮空的状态应该是高电平状态的场景(开关接通,因为接地,所以铁定端口呈现的是低电平),如下所示,需要构造一个上拉电阻电路,依据电路的欺软怕硬的特性,走的是上拉电阻的支路,于是开关断开,指定的接口呈现的是高电平:


file


下面是完整的物理电路图


file


可以看到在电路内部会有上拉/下拉电阻电路,来实现浮空处理;

GPIO速度

在LED的配置中,是需要指定工作速度,但是在KEY的配置中却没有了工作速度,这个是因为指定的GPIO_Speed其实是一个采样速度,即采样GPIO引脚的状态,例如如果指定为10MHz,即每秒10x1000000次采样,用来获取信号量,所以GPIOSpeed按照奎斯特定理,采样频率至少是要信号频率的2倍以上才能够比较准确地还原原始信号,一般实际的工作中,是5~10倍;

所以只有引脚为输出模式的引脚需要设定速度,因为一旦一个引脚被配置为输出模式,就代表是有信号输入到这个引脚,然后再从这个引脚中输出;既然是有信号,那么如果一个引脚想要表达这个信号就需要采样,采样就需要指定速度;

比如我们在点亮LED的源码解读中,信号就是在while循环里面灯的亮灭,信号的频率就是由while语句里面的delay函数决定的,然后把信号写入到PC13上面:

int main(void){
        ... ...
        while (1)
        {
                GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
                delay_2(1);
                GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);
                delay_2(1);
        }}

芯片的CPU将会将会基于采样频率(GPIO_Speed)来采集,即由硬件层面来进行采样;其实真正起作用的是采样的结果,采样结果直接决定了LED灯的亮灭:


file

输入vs.输出

那么,回过头来,再来看我们键盘的GPIO配置,作为PB13输入引脚,代表引脚的数据并不是由软件主动写入,输入输出是站在STM32内部芯片的角度来说的,所谓的输入是指,外设将数据到写入GPIO口,需要STM32芯片获取,比如本节按键相应,就是由外设(按键)将自己的电平状态写入到PB12;
输出,则是由STM32内部电路产生信号,写到GPIO口;比如LED灯里面控制PC13的高低电平,就是由软件层面直接控制到STM32电路实现的,所以如果是软件层面直接来配置GPIO口(寄存器)的值,就是输出;


file

封装灯的亮灭

void led_opr(int opr){
if(1 == opr){
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
}else{
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);
}
}

这个函数实现了根据参数,决定向PC13写高电平还是低电平;这里面的写法在“STM32(4):基于构件库的点亮LED”里面有说明,这里将其封装为一个函数,就是为了便于重复调用;Bit_Set就是设置高电平,Bit_Rest就是低电平,还记得LED的物理电路图吗?

如果PC13设置为1,和VCC3V3端电压一致,形成不了电压差,所以LED灯处于熄灭的状态,设置PC13为0,LED2两端有电压差,于是产生电流(电流方向是VCC到PC13,电子方向是PC13到VCC,高中物理知识哦)。

GPIO_WriteBit则是(STM32固件库的)库函数,用于向GPIO引脚写入高低电平值。

轮训方式通信

while (1)
{
        if (1 == key_read())
        {
                GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);
        }
        else
        {
                GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
        }
}

下面这一段就是通过轮训方式获取PB12的状态(通过key_read函数),然后根据PB12的状态来设置PC13的状态;所谓的轮训方式,就是不断的获取指定引脚的状态;

轮训和后面要将的中断形成鲜明对比;就像上海的有的快递,送到了指定地点,不通知你,于是你只能一遍一遍的刷新手机,看看是否已经送到,送到了下去去取,这个就是类似于“轮训通信”;而有的良心快递送到之后,回短信或者电话通知你,接到通知之后,你直接下楼取快递即可,这个就是“中断通信”;

读取引脚状态

我们看一下key_read()的实现:

u8 key_read(){
        u8 result = 0;
        // delay(1);
        result = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);

        return result;}

这里直接调用的(STM32固件库的)库函数GPIO_ReadInputDataBit函数实现了对于PB12的读取,这里如果担心频繁调用影响性能,可以在key_read或者main主函数的while轮训实现通过调用delay函数实现延迟;轮训方式的缺点就是耗费CPU时间,需要CPU不断的进行轮训;不同中断的主动通知,需要主动的不断的访问;中断优点就会节省CPU时间,但是并非所有事件都能够采用中断通知,在STM32里面预制的中断种类只有256个(其中16个内部中断,240个外部中断)。


总结

本章中主要介绍了通过轮训的方式实现基于按键来实现LED等亮灭控制;主要的步骤有LED初始化,按键初始化以及轮训读取PB12的引脚状态;

需要掌握的是轮训通信机制的原理以及实现,还有引脚控制相关上拉/ 下拉电阻,GPIO速度以及引申出来的输入/ 输出概念,


关键字:STM32  按键  点亮LED 引用地址:STM32(5):轮训方式让按键点亮LED

上一篇:[从智能锁谈STM32安全技术 学习笔记] 二. 加解密技术
下一篇:STM32(4):基于构件库的点亮LED

推荐阅读最新更新时间:2026-03-25 11:32

STM32实战1:按键点亮LED小灯 hh
#include sys.h #include key.h void KEY_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//初始化时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOB, &GPI
[单片机]
基于STM32利用按键点亮LED
基于STM32利用按键点亮LED灯的基本步骤: (1)打开stm32CubeMX,创建新工程文件 (2)选择需要的芯片,本次实验采用的是STM32F411RETx (3)黄色代表可被使用的引脚,绿色代表已被确定功能的引脚。左侧设置栏中的红色部分表示:IO口复用造成的重叠,以至不能继续使用。 (4)选好芯片,设置好相关系数参量后,选择与keil5相对应的MDK—ARM V5。 源程序: 1.按键按下LED灯点亮 int main { if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13) == 0){ HAL_Delay(10); //延时去抖
[单片机]
STM32实战1:按键点亮LED小灯
理论知识已经学习完成,之后我们进入实战篇,在实战的学习中,我完成了第一个项目,用按键点亮了led灯下面是我的程序 led主程序 #include sys.h #include led.h void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE);//初始化PCIO时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_I
[单片机]
MSP430F5529LP按键点亮LED
代码 #include msp430.h void Key11_GPIO_Init(); void Key21_GPIO_Init(); void LED_Init(); void main(void) { WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer Key11_GPIO_Init(); //按键1.1初始化 Key21_GPIO_Init(); //按键2.1初始化 LED_Init(); //LED初始化 _enable_interrupts(); //使能中断 while(1) { } return 0; } voi
[单片机]
OK6410按键中断点亮lED
首先理清楚要准备的几个方面 1.LED初始化 2.按键初始化 3.中断初始化 4.中断处理程序 首先初始化LED,以前说过了,不说 按键初始化,这里既然要用到中断,就不用传统的延时消抖的办法了,直接用中断。 只要把对应的位设置成10,就是外部中断了 这里用XEINT0和XEINT5,有理由的,为什么选这两个后面会说 void button_init() { *(GPNCON)=0x802; //配置按键位外部中断 } 接下来中断初始化,一下说的比较清楚了,寄存器的名字直接在s3c6410里面查找就可以了,为什么选XEINT0和XEINT5的原因在注释最长的那一行里面
[单片机]
OK6410<font color='red'>按键</font>中断<font color='red'>点亮</font><font color='red'>lED</font>
Visual Studio 2022 开发 STM32 单片机 - 环境搭建点亮LED
安装 VS2022社区版 软件 选择基础的功能就好 安装 VisualGDB 软件(CSDN资源) 按照提示一步一步安装就好 VisualGDB激活软件(CSDN资源) 将如下软件放在VisualGDB的安装目录下直接运行就好 打开VisualStudio软件 创建新项目 选择Embedded ProjectWizard项目 设置工程参数 按照默认的参数不修改 以上参数不修改 如果在filter中没有搜到芯片,在Download more devices下载对应设备 查看开发板的LED灯的硬件链接引脚 设置对应的参数
[单片机]
Visual Studio 2022 开发 <font color='red'>STM32</font> 单片机 - 环境搭建<font color='red'>点亮</font><font color='red'>LED</font>灯
stm32填坑之旅一 - stm32f103c8t6点亮板载贴片蓝色LED
开篇 没有时间只是自己找的借口罢了! 开篇一定要精彩,不然路人不理睬!下述是笔者作为arm小白的填坑之旅 没错,这个之前一直从事软件开发的笔者,开始搞硬件了,当然仅仅是数电!模电需要有很扎实的电路基础,而笔者有的只有“扎实”的逻辑基础。 那为什么笔者要开始搞硬件呢? 其实早在大学期间,笔者所在专业(计算机科学与技术)中就有一门课就专门讲了硬件-软件的连接以及实现,只怪当初没有好好学,只是心中有那么个印象,就是时钟驱动逻辑电路去处理每一个指令然后完成整个逻辑(当然,这个印象很重要,在arm中,时钟就是它的心脏!)。 毕业后若干年,物联网行业开始兴起,于是手痒痒了,仅凭这一印象,开始入手了人生中的第一块板子——树莓派3B,用来做了一
[单片机]
STM32(4):基于构件库的点亮LED
概述 第一、二章节中,STM32是纯裸开发,通过自定义地址来进行写寄存器;STM32其实提供了底层固件库,定义好了通用功能,所以如果是常规功能只需要调用固件库的API即可实现功能。所以我在番外篇说了,其实熬过了前两章,后面的内容反而要简单。 从本章开始,我们的绝大多数的开发内容都是基于STM32的固件库进行的。 从main函数说起 用c编写函数,都知道入口函数是main函数,程序跑起来一定会找main函数;所以我们的编译器在编译的时候还会做强制的main函数重复检测,避免定义多个main函数执行的时候导致不可预知的结果; 但是,为什么选择的是main呢?我们觉得理所当然,其实有人替你负重前行,如果你做gcc编译的c代码,然后在Li
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved