一、首先明确需要实现的功能:通过STM8S103F2P2这颗单片机来扫描检测触摸板是否被触摸,然后实现如下功能
1.触摸3s可实现开关安卓系统
2.单次触摸可以实现唤醒屏幕,继续单次触摸可以熄灭屏幕
3.连续触摸并保证第二次触摸在第一次触摸后的1s内,则可以实现双击控制LED灯光亮度
流程框架如下图:
二、程序设计
定义触摸返回的四种事件类型 和 触摸事件处于触摸时间段的四种状态,分别是:
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资源上报思维,代码简洁明了
此篇博客仅作为程序设计参考,具体逻辑关系及细节设计,还应当根据具体的硬件进行设计!