×
嵌入式 > 技术百科 > 详情

STM8学习笔记---按键KEY

发布时间:2020-06-12 发布时间:
|

用按键来控制LED灯的亮灭。按键接在PC4口,LED灯接在PD4口,LED灯由IO口高低电平控制亮灭,所以对于LED来说,IO口为输出口。按键是由外部电路来决定高低电平,假设按键未按下时默认为高电平,按键按下时为低电平。对于KEY来说,IO口为输入口,IO口要读取外部电平状态,根据电平状态来判断按键是否按下。


首先要设置IO口的状态。

端口方向寄存器, LED口要设置为输出模式, 所以PD4设置为1。按键KEY口要设置为输入模式,所以PC4设置为0。

端口控制寄存器,LED口需要输出高低电平,所以PD4口设置为1,推挽输出。

按键KEY口要读取外部电平,按键未按下时为高电平,按键按下时为低电平。所以PC4口设置为1,带上拉电阻输入,将IO口电平默认状态用上拉电阻拉为高电平。

LED口为输出模式,设置PD4口为1,输出最大速度10MHz。

按键KEY口为输出模式,设置PC4口为0,禁止外部中断。判断按键用查询方式,不需要开中断。

LED口初始化代码为:


#include "led.h"


void LED_GPIO_Init( void )

{

    PD_DDR |= ( 1 << 4 );        //PD4 输出 led

    PD_CR1 |= ( 1 << 4 );        //PD4 推挽输出

    PD_CR2 |= ( 1 << 4 );

}


控制LED亮灭要通过位操作来实现,所以要在头文件中对LED进行位定义。


#ifndef __LED_H

#define __LED_H

#include "iostm8s103F3.h"

#define  LED  PD_ODR_ODR4 //位定义 PD4定义为输出 LED

void LED_GPIO_Init(void);

#endif


用 LED 来表示PD4口的输出状态寄存器,这样在操作LED的时候就相当于操作PD口的输出寄存器 ODR4位。

按键口KEY的初始化代码为:


#include "key.h"


void KEY_GPIO_Init( void )

{

    PC_DDR &= ~( 1 << 4 );        //PC4 输入

    PC_CR1 |= ( 1 << 4 );         //带上拉电阻输入

    PC_CR2 &= ~( 1 << 4 );        //禁止外部中断

}


按键判断也要通过位操作实现,要在头文件中位定义。


#ifndef __KEY_H

#define __KEY_H

#include "iostm8s103F3.h"

#define  KEY  PC_IDR_IDR4 //位定义 PC4 定义为按键输入  

void KEY_GPIO_Init( void );

#endif


用 KEY 来表示PC4口的输入状态寄存器,这样在操作KEY的时候就相当于操作PC口的输入寄存器 IDR4位。

LED和按键KEY的初始化已经完成,下来开始写主函数。主函数要实现的功能主要是按键按下一次LED灯亮,按键再按下一次LED灯灭。也就是说按键 按下一次 LED灯的状态取反一次。主程序代码如下:


 while( 1 )

    {

        if( KEY == 0 )

        {

                LED = !LED;

        }

    }


按键按下为低电平,所以在循环中判断KEY的状态,若KEY为0,说明按键按下,此时将LED状态取反。将程序烧入单片机中测试,在按键的过程中发现有时候按键按下后LED灯的亮灭没发生变化,感觉是按键失灵了。用示波器看看按键IO口的波形。

通过波形可以看到,按键按下后,确实为低电平,但是在按键真正按下前出现了一个向下的脉冲。为什么会出现这个向下的脉冲呢?因为一般的按键内部结构是两个金属片,按键按下时两个金属片挨在一起形成通路,按键弹起时两个金属片分开形成断路。人用手指按键时,在按下的一瞬间手指可能会抖动,导致两个金属片短暂的接触后,又瞬间断开。然后手指将按键真正按下后,两个金属片稳定的接触在一起,形成一个稳定的低电平。


程序中按键失灵的感觉就是这个短暂的向下脉冲造成的。当按键时手指发生抖动,在IO口出现了一个瞬间的低电平,这时候如果程序刚好捕捉到了这个低电平,就会被当做一个按键事件处理,这时将状态取反。当按键真正被按下时,又出现一个低电平,这时程序认为是新的按键事件发生,又对LED状态取反一次。相当于真正的按键只按下去一次,但是程序中捕捉到了两次按键。也就是说按键真正的按下了一次,但是程序中对灯的状态取反了两次。相当于LED状态没变。由于按键按下时间非常短,LED灯状态在中间发生变化的时间太短,人眼观察不到,所以感觉LED状态没变。那么如何避免在按键时出现抖动的情况呢,一种方法时在按键的时候一瞬间按下去,不要出现抖动情况。一种是硬件上换更好的按键,从硬件上避免抖动出现。但是这两种方法都不太现实,能不能用软件方法解决这个问题呢?


通过观察上面按键的波形可以发现,按键按下后低电平会持续很长时间,在程序判断的时候可以通过两次低电平来确认按键按下,这两次低电平判断中间要等待一段时间。比如说判断到一次低电平后,延时一段时间,在判断一次,若此时还是低电平说明是按键正真的按下了。于是程序修改为:


 while( 1 )

    {

        if( KEY == 0 )

        {

            delay_ms( 10 );

            if( KEY == 0 )

            {

                LED = !LED;

            }

        }

    }


按键按下后,延时10ms,然后再判断按键状态,若按键状态没变,说明按键是真的被按下。此时在对LED灯的状态取反。将将程序烧到单片机中测试,发现增加延时后,按键的识别率大大的增强了。

修改后的主程序为:


#include "iostm8s103F3.h"

#include "led.h"

#include "key.h"

void SysClkInit( void )

{

    CLK_SWR = 0xe1;       //HSI为主时钟源  16MHz CPU时钟频率

    CLK_CKDIVR = 0x00;    //CPU时钟0分频,系统时钟0分频

}

void delay_ms( unsigned int ms )

{

    unsigned int  i, j;

    while( ms != 0 )

    {

        for( i = 0; i < 61; i++ )

            for( j = 0; j < 50; j++ );

        ms--;

    }

}

void main( void )

{

    SysClkInit();                         //时钟初始化

    __asm( "sim" );                       //禁止中断

    LED_GPIO_Init();                      //LED 初始化

    KEY_GPIO_Init();                      //KEY初始化

    __asm( "rim" );                       //开启中断

    LED = 0;

    while( 1 )

    {

        if( KEY == 0 )

        {

            delay_ms( 10 );

            if( KEY == 0 )

            {

                LED = !LED;

            }

        }

    }

}


如果实际测试中按键还会失灵,根据实际情况可以增加或者减小两次按键判断中间的延时。


当然除了软件上增加延时外,也可以给按键口增加一个滤波电容,通过电容将按键时的小毛刺滤掉。




『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
实时控制.安全.如何加速实现未来工厂落地?