STM8S103F2P2外部触摸按钮实验 |【触摸按钮检测,事件有:单击、双击、长按】| 记录时间:2020-4-23

 

一、首先明确需要实现的功能:通过STM8S103F2P2这颗单片机来扫描检测触摸板是否被触摸,然后实现如下功能

       1.触摸3s可实现开关安卓系统

       2.单次触摸可以实现唤醒屏幕,继续单次触摸可以熄灭屏幕

       3.连续触摸并保证第二次触摸在第一次触摸后的1s内,则可以实现双击控制LED灯光亮度

流程框架如下图:

STM8S103F2P2外部触摸按钮实验 |【触摸按钮检测,事件有:单击、双击、长按】| 记录时间:2020-4-23_第1张图片

二、程序设计

        定义触摸返回的四种事件类型 和 触摸事件处于触摸时间段的四种状态,分别是:

enum  _KEY_TYPE
{
    NONE_KEY = 0, //0 //无键 
    SHORT_KEY,    //1 //单键 
    LONG_KEY,     //2 //长键 
    DOUBLE_KEY,   //3 //双键 
};

enum  _KEY_STATE
{
    key_state_0 = 0,//0 
    key_state_1,    //1 
    key_state_2,    //2 
    key_state_3,    //3 
};

在主函数中编写switch-case语句来实现当处于某种状态下对应的操作:

void main(void)
{
    unsigned char keyVal;
    short brightTime = 50;
    Key_GpioInit();                     //1.按键初始化
    PWM_Init();                         //2.PWM初始化
    SetTIM2_PWM_DutyCycle(brightTime);
    while (1)
    {
        delay_ms(20);
        keyVal = Key_Scan();
        switch(keyVal)
        {
            case SHORT_KEY:
                Key_PowerCtrl(1);    //power on
                break;
            case LONG_KEY:
                Key_PowerCtrl(3);    //power on/off
                break;
            case DOUBLE_KEY:
                SetTIM2_PWM_DutyCycle(brightTime);
                brightTime+=500;
                if(brightTime>1000)
                {
                   brightTime = 0;
                }
                break;
        }
    }
}

分别编写对应状态下的具体操作函数

/*
    参数 : dlyms
    说明 :这个时间参数单位是秒,1s可以亮屏息屏,3s可以开关机

    POWERKEY_PORT 这个是STM8的PC3引脚,通过对其拉高拉低操作来给SC20的POWER_ON引脚进行相应的操作
*/
void Key_PowerCtrl(unsigned short dlyms)
{
    
    GPIO_WriteHigh(POWERKEY_PORT, (GPIO_Pin_TypeDef)POWERKEY_PINS);
    delay_s(dlyms);
    GPIO_WriteLow(POWERKEY_PORT, (GPIO_Pin_TypeDef)POWERKEY_PINS);
}

PWM驱动LED灯带

#include "timer.h"
#define ARR ((uint16_t)1000)
void PWM_Init(void)
{
    TIM2->PSCR=0x04;
    TIM2->ARRH = (uint8_t)(ARR >> 8);
    TIM2->ARRL = (uint8_t)(ARR);
    TIM2_OC1Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE,0, TIM2_OCPOLARITY_HIGH);
    TIM2_OC3Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE,0, TIM2_OCPOLARITY_HIGH);
    TIM2->CR1 |= 0x01;
}
​//设置Timer2的PWM占空比
void SetTIM2_PWM_DutyCycle( uint16_t TIM2_Pulse)
{
    TIM2->CCR1H = (uint8_t)(TIM2_Pulse >> 8);
    TIM2->CCR1L = (uint8_t)(TIM2_Pulse);
    TIM2->CCR3H = (uint8_t)(TIM2_Pulse >> 8);
    TIM2->CCR3L = (uint8_t)(TIM2_Pulse);
}

接下来设计KeyVal这个返回值,怎样从触摸的代码中返回来

static unsigned char key_driver(void)
{
    static unsigned char key_state_buffer1 = key_state_0;
    static unsigned char key_timer_cnt1 = 0;
    unsigned char key_return = NONE_KEY;
    unsigned char key;
    key = key_input;  //read the I/O states
    switch(key_state_buffer1)
    {
        case key_state_0:
          if(key == 0)
              key_state_buffer1 = key_state_1; 
              //按键被按下,状态转换到按键消抖和确认状态//
        break;
        case key_state_1:
            if(key == 0)
            {
                key_timer_cnt1 = 0;
                key_state_buffer1 = key_state_2;
                //按键仍然处于按下状态
                //消抖完成,key_timer开始准备计时
                //状态切换到按下时间计时状态
            }
            else
                key_state_buffer1 = key_state_0;
                //按键已经抬起,回到按键初始状态
        break;  //完成软件消抖
        case key_state_2:
            if(key == 1) 
            {
                key_return = SHORT_KEY;  //按键抬起,产生一次click操作
                key_state_buffer1 = key_state_0;  //转换到按键初始状态
            }
            else if(++key_timer_cnt1 >= 150)  //按键继续按下,计时超过1500ms
            {
                key_return = LONG_KEY;  //送回长按事件
                key_state_buffer1 = key_state_3;  //转换到等待按键释放状态
            }
        break;
        case key_state_3:  //等待按键释放
            if(key == 1)  //按键释放
                key_state_buffer1 = key_state_0;  //切回按键初始状态
        break;
    }
    return key_return;
}

//Key_Scan(void)函数调用上面key_driver(void)这个函数
unsigned char Key_Scan(void)
{
    static unsigned char key_state_buffer2 = key_state_0;
    static unsigned char key_timer_cnt2 = 0;
    unsigned char key_return = NONE_KEY;
    unsigned char key;
    key = key_driver();
    switch(key_state_buffer2)
    {
        case key_state_0:
        if(key == SHORT_KEY)
        {
            key_timer_cnt2 = 0;  //第一次单击,不返回,到下个状态判断是否会出现双击
            key_state_buffer2 = key_state_1;
        }
        else 
            key_return = key;  //对于无键、长按,返回原事件
        break;
        case key_state_1:
        if(key == SHORT_KEY)  //又一次单击,时间间隔小于500ms
        {
            key_return = DOUBLE_KEY;  //返回双击事件,回到初始状态
            key_state_buffer2 = key_state_0;
        }
        else if(++key_timer_cnt2 >= 50)
        {
            //这里500ms内肯定读到的都是无键事件,因为长按大于1000ms
            //在1s前底层返回的都是单击
            key_return = SHORT_KEY;  //500ms内没有再次出现单击事件,返回单击事件
            key_state_buffer2 = key_state_0;  //返回初始状态
        }
        break;
    }
    return key_return;
}

到此,根据流程图所示的程序设计就结束了,该程序的优点:

1.主函数的while程序每20ms运行一次,提高了触摸按钮的检测效率

2.判断触摸按钮的触摸时长来进行上报,提高代码的执行效率,不让代码跑飞

3.运用Linux资源上报思维,代码简洁明了

 

此篇博客仅作为程序设计参考,具体逻辑关系及细节设计,还应当根据具体的硬件进行设计!

你可能感兴趣的:(工作简书,单片机,操作系统,项目开发)