当前位置: 首页 > news >正文

【嵌入式开发-按键扫描】

嵌入式开发-按键扫描

  • ■ 1. 按键
    • ■ 按键队列发送后在读取队列处理
    • ■ 定时器30ms扫描一次,并通过MsgAdd(msg); 发送出去。
  • ■ 2. 触摸屏处理

■ 1. 按键

■ 按键队列发送后在读取队列处理

// key queue
#define KEY_QUEUE_MAX 5typedef enum
{KEY_TYPE_IR = 0,KEY_TYPE_ADC,KEY_TYPE_GPIO,
} KEY_TYPE_e;typedef struct
{KEY_MSG_s key_msg[KEY_QUEUE_MAX];int front;int rear;  //队尾指针int size;  //大小
} KEY_QUEUE_s;static KEY_QUEUE_s m_key_queue;static KEY_QUEUE_s m_key_queue;// 初始化队列
void key_queue_init(KEY_QUEUE_s *q)
{q->front = q->rear = 0;q->size = 0;		//队列当前长度为0
}// 判断队列是否为空
bool key_queue_empty(KEY_QUEUE_s *q)
{if (q->size==0)	//队空条件return true;elsereturn false;
}// 入队
bool key_queue_write(KEY_QUEUE_s *q, KEY_MSG_s *x)
{if (q->size == KEY_QUEUE_MAX)return false;		//队列满则报错memcpy(&(q->key_msg[q->rear]), x, sizeof(KEY_MSG_s));	//将x插入(拷贝)队尾q->rear = (q->rear + 1) % KEY_QUEUE_MAX;    //队尾指针后移q->size++;return true;
}// 出队
bool key_queue_read(KEY_QUEUE_s *q, KEY_MSG_s **x)
{if (q->size==0)return false;	//队空则报错*x = &(q->key_msg[q->front]);q->front = (q->front + 1) % KEY_QUEUE_MAX; //队头指针后移q->size--;return true;
}// 获取队头元素
bool key_queue_head_get(KEY_QUEUE_s *q, KEY_MSG_s **x)
{if (q->size==0)return false;	//队空则报错*x = &(q->key_msg[q->front]);return true;
}// 队列中元素的个数
int key_queue_num(KEY_QUEUE_s *q)
{return q->size;
}KEY_MSG_s *api_key_msg_get(void)
{KEY_MSG_s *key_msg = NULL;if (key_queue_read(&m_key_queue, &key_msg))return key_msg;elsereturn NULL;
}void api_key_queue_send(uint32_t act_key, int32_t press)
{KEY_MSG_s key_msg;memset(&key_msg, 0, sizeof(KEY_MSG_s));key_msg.key_type = KEY_TYPE_IR;key_msg.key_event.type = EV_KEY;key_msg.key_event.code = act_key;key_msg.key_event.value = press;  //1: pressed; 0: releasekey_queue_write(&m_key_queue,&key_msg);
}

■ 定时器30ms扫描一次,并通过MsgAdd(msg); 发送出去。

按键h文件定义

#define KEY_DETE_TIME       30
#define KEY_LONG_SENSE      1000
#define KEY_LONG_COUNT      (KEY_LONG_SENSE/KEY_DETE_TIME)typedef enum
{KEY_UP,KEY_DOWN,KEY_LONG_DOWN,
}KeyStatus;typedef enum
{BOL_KEY,  MUTE_KEY, START_KEY,POWER_OFF_KEY,KEY_END=POWER_OFF_KEY,
}KeyType;typedef struct
{uint16_t count;KeyStatus state;
}KeyArgus;typedef struct
{uint32_t value;uint32_t FilterValue;KeyArgus keys[KEY_END];
}KeyInfors;

按键长安短按处理

static KeyInfors key;
static void KeyOperate(void) 
{int8_t i;KeyStatus tmp_state;SysMessage msg = {CONTROL_MODULE, MODEL_MODULE};	//按键的信息传递给model模块,因为没有立即显示需要,不用给view模块if((key.FilterValue ^ key.value) == 0)	//按位运算,异或,两个数据全相同时,返回0for(i=0; i<KEY_END; i++){if(key.FilterValue & (1<<i))	//为1说明有按键按下{tmp_state = KEY_DOWN;if(key.keys[i].count++ >= KEY_LONG_COUNT)	//按下1s钟才算长按{tmp_state = KEY_LONG_DOWN;key.keys[i].count = KEY_LONG_COUNT;}msg.data[0] = i;//按键的值msg.type = (EventType)(KEY_UP_EVENT+tmp_state);//KEY_LONG_DOWN_EVENT或者KEY_DOWN_EVENTMsgAdd(msg);}else{tmp_state = KEY_UP;if(key.keys[i].state != tmp_state)	//按键刚刚释放{msg.data[0] = i;//按键的值msg.type = (EventType)(KEY_UP_EVENT+tmp_state);//KEY_UP_EVENTif(key.keys[i].count < KEY_LONG_COUNT)msg.data[1] = KEY_DOWN;elsemsg.data[1] = KEY_LONG_DOWN;//按键曾经的状态MsgAdd(msg);	//添加按键消息}key.keys[i].count = 0;}key.keys[i].state = tmp_state;}
}//每30ms扫描一次按键
static void KeyScan(int arg)
{key.value = 0;if(M_KEY_Bol_DATA)key.value |= 1<<BOL_KEY;elsekey.value &= ~(1<<BOL_KEY);if(M_KEY_Mute_DATA)key.value |= 1<<MUTE_KEY;elsekey.value &= ~(1<<MUTE_KEY);if(M_KEY_Start_DATA)key.value |= 1<<START_KEY;elsekey.value &= ~(1<<START_KEY);//说明:POWER_OFF_KEY不在这里扫描,其由M0发送的信息来判断KeyOperate();key.FilterValue = key.value;
}//按键初始化
void KeyInit(void)
{key.FilterValue = 0;TimerOnMsRepeatDelay(KeyTimer, KEY_DETE_TIME, KeyScan, 10);
}

获取队列按键处理

void GeneralKeyDeal(SysMessage msg)
{if(msg.type == KEY_UP_EVENT) //松开{switch(msg.data[0]){case MUTE_KEY:if(msg.data[1] == KEY_DOWN){	;}else if(msg.data[1] == KEY_LONG_DOWN){;}break;case START_KEY:break;			case BOL_KEY:break;			}		}else if(msg.type == KEY_LONG_DOWN_EVENT){switch(msg.data[0]){case MUTE_KEY:break;case START_KEY:break;			case BOL_KEY:break;			}}
}

■ 2. 触摸屏处理

触摸中断

void PORTA_IRQHandler(void)  
{if(TsArgu.port->ISFR & (1<<TsArgu.PinNum)){TimerOnMsOnceCallBack(TsTimer, 100, TsWork, 0);//延时去抖动NVIC_DisableIRQ(PORTA_IRQn);}TsArgu.port->ISFR |= PORT_ISFR_ISF_MASK;//每次中断仅可执行一次
}//有触摸屏按下时,每隔5ms执行一次
//#ifdef TSC2007
static void TsWork(int argu)
{int8_t pin_status;if(M_TSC_INT_DATA) pin_status = GPIO_HIGH_LEVEL;else pin_status = GPIO_LOW_LEVEL;if(pin_status== GPIO_LOW_LEVEL)//touch down{TsRead_XYvalues();	//获取坐标值和Z值TsDisADC_EnPENIRQ();//为下一次读取数据做准备TsFilter();			//做滤波处理,其平均值再赋给x_value和y_valueif(TsArgu.point.data.x_value && TsArgu.point.data.y_value){		if(++TsArgu.LongPressCount >= TS_LONG_PRESS_TIMES_COUNT+TS_LONG_PRESS_INTERVAL_COUNT)	//长按为至少1700ms{TsSendMsg(4, TsArgu.point.datas, TOUCH_LONG_DOWN_EVENT);//发送长按消息和坐标TsArgu.LongPressCount = TS_LONG_PRESS_TIMES_COUNT; }else if(TsArgu.LongPressCount < TS_LONG_PRESS_TIMES_COUNT){TsSendMsg(4, TsArgu.point.datas, TOUCH_DOWN_EVENT);		//发送按下消息和坐标}}TimerOnMsOnceCallBack(TsTimer, TOUCH_SCREEN_CHECK_TIME, TsWork, 0);//继续执行TsWork函数}else	//touch up{	if(TsArgu.point.data.x_value && TsArgu.point.data.y_value){		if(TsArgu.LongPressCount >= TS_LONG_PRESS_TIMES_COUNT){TsSendMsg(4, TsArgu.point.datas, TOUCH_LONG_DOWN_UP_EVENT);	//发送从长按释放的消息}else{TsSendMsg(4, TsArgu.point.datas, TOUCH_UP_EVENT);	//发送释放触摸屏的消息}}//清空x和y的坐标记录,清空滤波器TsArgu.point.data.x_value = 0;TsArgu.point.data.y_value = 0;memset(TsArgu.filter, 0 ,sizeof(TsArgu.filter));//打开中断,等待下一次正确处理TsArgu.LongPressCount = 0;NVIC_EnableIRQ(PORTA_IRQn);}
}//把触摸屏的触发事件添加到消息队列中去
static void TsSendMsg(int8_t len, uint8_t *data, EventType type)
{SysMessage msg = {CONTROL_MODULE, VIEW_MODULE};	//由控制模块传递到显示模块的消息msg.type = type;  memcpy((char *)msg.data, (char *)data, 4);MsgAdd(msg);	//添加到消息队列
}//数组内数据左移,刚到来的数据放在最后一个位置
static void filter(int8_t type, uint16_t *value)
{int8_t i;int32_t min, max, average, sum;sum = 0;max = min = *value;for(i=0; i<TOUCH_SCREEN_FILTER_NUM; i++){if(i < TOUCH_SCREEN_FILTER_NUM-1){if(TsArgu.filter[i+1].value[type] == 0)TsArgu.filter[i].value[type] = *value;	//若是数组为空,就填充刚进来的值else				//如果数组已有值,就让数据左移TsArgu.filter[i].value[type] = TsArgu.filter[i+1].value[type];}else {TsArgu.filter[i].value[type] = *value;}sum += TsArgu.filter[i].value[type];if(TsArgu.filter[i].value[type] > max)max = TsArgu.filter[i].value[type];if(TsArgu.filter[i].value[type] < min)min = TsArgu.filter[i].value[type];    }sum -= (max + min);	//去掉最大值和最小值average = sum / (TOUCH_SCREEN_FILTER_NUM-2);*value = average;	//求取平均值
}static void TsFilter(void)
{filter(0, &TsArgu.point.data.x_value);filter(1, &TsArgu.point.data.y_value);    
}

http://www.xdnf.cn/news/454141.html

相关文章:

  • 从构想到交付:专业级软开发流程详解
  • c++中的函数(默认参数,占位参数,重载)
  • Arduino使用红外收发模块
  • MySQL基础之开窗函数
  • 嵌入式(c语言篇)Day9
  • 基于nacos2.5.1的java微服务项目开发环境配置简介
  • Spyglass:跨时钟域同步(同步单元)
  • Gin 框架指南(代码+通俗解析版)
  • 2025前四月新能源汽车出口增长52.6%,外贸ERP数字化助力汽企持续跃升
  • 给 DBGridEh 增加勾选用的检查框 CheckBox
  • 通用软件项目技术报告 - 导读I
  • C++ 并发编程(1)再学习,为什么子线程不调用join方法或者detach方法,程序会崩溃? 仿函数的线程启动问题?为什么线程参数默认传参方式是值拷贝?
  • 阿里的库存秒杀实现与Inventory Hint技术解析
  • Windows系统Anaconda/Miniconda的安装、配置、基础使用、清理缓存空间和Pycharm/VSCode配置指南
  • Linux系统编程——fork函数的使用方法
  • idea插件使用
  • Prometheus 的介绍与部署(入门)
  • Spring 的 异常管理的相关注解@ControllerAdvice 和@ExceptionHandler
  • 2011-2019年各省总抚养比数据
  • 【GESP真题解析】第 5 集 GESP一级 2023 年 3 月编程题 2:长方形面积
  • Python实例题:Python抓取相亲网数据
  • Maplibgre-gl 学习1 初识
  • leetcode刷题日记——旋转链表
  • 深入理解Java HotSpot中的即时编译
  • 规控算法分类
  • 【Vue.js 的核心魅力:深入理解声明式渲染】
  • 学习黑客NFC技术详解
  • 互联网协议的多路复用、Linux系统的I/O模式
  • 【FileZilla】sftp协议的数据传输上传和下载
  • 软考软件设计师中级——软件工程笔记