Funpack4-1 基于CY8CKIT-149的小型桌面控制台
该项目使用了CY8CKIT-149,实现了桌面控制台的设计,它的主要功能为:可以控制Windows系统音量的加减、歌曲开始/暂停、上一首、下一首以及模拟多个键盘按键。
标签
Funpack活动
CY8CKIT-149
桌面控制台
obrulviser
更新2025-04-03
18

Funpack4-1

——板卡一 自命题:桌面控制台

一、项目介绍

本项目依托于Funpack4-1活动,使用嵌入式板卡-上位机驱动配合的模式,实现了一个桌面控制台。基于CY8CKIT-149板载的滑条和按键等,实现了滑动和按键触摸的识别。上位机驱动实现了滑动去抖,并将按键触摸等行为模拟为一系列按键操作,包括系统音量加减,音乐上一首、下一首,音乐的开始和暂停,纵向滚轮,Windows键,回车键和删除键。


项目内容:

1、识别按键和滑动

2、实现上位机与板卡通信

3、滑条数据处理

4、模拟系统按键


应用场景

本项目是一个多功能桌面控制台。其模拟的按键可以极大程度补充按键,如84键以下的键盘往往缺失较多的功能按键。可以简化按键操作,如实现复制、粘贴等操作。也可以使得操作更舒适,如用非线性滑条代替滚轮,可以同时做到低速精准和高速移动快。

二、总体架构

image.png

系统的总体结构为板卡识别滑条和按键的数据,通过串口连接至上位机。上位机驱动接收串口数据,对数据进行处理,转义为系统操作,并与系统交互。


三、受控端软件

受控端使用ModusToolBox开发,基于案例CAPSENSE_SmartSense_buttons_slider开发。

系统上电后首先进行初始化,包含最基本的bsp(板级支持包)内所含的初始化,中断使能,初始化capsense,以及初始化串口。

	result = cybsp_init();
/* Board initialization failed. Stop program execution */
if (result != CY_RSLT_SUCCESS)
{
CY_ASSERT(CY_ASSERT_FAILED);
}
/* Enable global interrupts */
__enable_irq();
/* Initialize EZI2C */
initialize_capsense_tuner();
/* Initialize CAPSENSE */
initialize_capsense();
Cy_SCB_UART_Init(CYBSP_UART_HW, &CYBSP_UART_config, &CYBSP_UART_context);
Cy_SCB_UART_Enable(CYBSP_UART_HW);

然后,初始化PWM,这部分是呼吸灯。

	if (CY_TCPWM_SUCCESS != Cy_TCPWM_PWM_Init(CYBSP_PWM1_HW, CYBSP_PWM1_NUM, &CYBSP_PWM1_config))
{
CY_ASSERT(CY_ASSERT_FAILED);
}
if (CY_TCPWM_SUCCESS != Cy_TCPWM_PWM_Init(CYBSP_PWM2_HW, CYBSP_PWM2_NUM, &CYBSP_PWM2_config))
{
CY_ASSERT(CY_ASSERT_FAILED);
}
/* Enable the initialized PWM */
Cy_TCPWM_PWM_Enable(CYBSP_PWM1_HW, CYBSP_PWM1_NUM);
Cy_TCPWM_PWM_Enable(CYBSP_PWM2_HW, CYBSP_PWM2_NUM);
/* Then start the PWM */
Cy_TCPWM_TriggerStart(CYBSP_PWM1_HW, CYBSP_PWM1_MASK);
Cy_TCPWM_TriggerStart(CYBSP_PWM2_HW, CYBSP_PWM2_MASK);
smart_io_start();

最后,开始捕获触摸。至此,系统初始化部分完成,进入主循环。

			Cy_CapSense_ScanAllWidgets(&cy_capsense_context);			

主循环中刨除为了控制数据量的延时,就只有触摸的识别和处理。

		Cy_SysLib_Delay(2);
if(CY_CAPSENSE_NOT_BUSY == Cy_CapSense_IsBusy(&cy_capsense_context))
{
/* Process all widgets */
Cy_CapSense_ProcessAllWidgets(&cy_capsense_context);
capsense_led();
/* Establishes synchronized communication with the CAPSENSE Tuner tool */
Cy_CapSense_RunTuner(&cy_capsense_context);
/* Start the next scan */
Cy_CapSense_ScanAllWidgets(&cy_capsense_context);
}

与上位机的交互以及按键和滑条对应LED的处理都在函数capsense_led()中,代码如下。

static void capsense_led(void)
{

/* LED ON/OFF based on the CAPSENSE linear slider position */
if(0 != Cy_CapSense_IsWidgetActive(CY_CAPSENSE_LINEARSLIDER0_WDGT_ID, &cy_capsense_context))
{
/* CAPSENSE Slider info */
cy_stc_capsense_touch_t *slider_touch_info;
uint8_t slider_touch_status;
uint16_t slider_pos = 0;
char st[20];
/* Get slider status */
slider_touch_info = Cy_CapSense_GetTouchInfo(
CY_CAPSENSE_LINEARSLIDER0_WDGT_ID, &cy_capsense_context);
slider_touch_status = slider_touch_info->numPosition;
if (slider_touch_status != 0)
{
slider_pos = slider_touch_info->ptrPosition->x;

sprintf(st,"nsv%03d",slider_pos,STEP_SIZE);

Cy_SCB_UART_PutString(CYBSP_UART_HW,st);

Cy_SCB_UART_PutString(CYBSP_UART_HW, "\r\n");

f_s=1;
}

if(slider_pos > 0 || slider_pos == 0)
{
Cy_GPIO_Write(CYBSP_LED_SLD0_PORT, CYBSP_LED_SLD0_NUM, LED_ON);
}
if(slider_pos > (1*STEP_SIZE))
{
Cy_GPIO_Write(CYBSP_LED_SLD1_PORT, CYBSP_LED_SLD1_NUM, LED_ON);
}
else
{
Cy_GPIO_Write(CYBSP_LED_SLD1_PORT, CYBSP_LED_SLD1_NUM, LED_OFF);
}
if(slider_pos > (2*STEP_SIZE))
{
Cy_GPIO_Write(CYBSP_LED_SLD2_PORT, CYBSP_LED_SLD2_NUM, LED_ON);
}
else
{
Cy_GPIO_Write(CYBSP_LED_SLD2_PORT, CYBSP_LED_SLD2_NUM, LED_OFF);
}
if(slider_pos > (3*STEP_SIZE))
{
Cy_GPIO_Write(CYBSP_LED_SLD3_PORT, CYBSP_LED_SLD3_NUM, LED_ON);
}
else
{
Cy_GPIO_Write(CYBSP_LED_SLD3_PORT, CYBSP_LED_SLD3_NUM, LED_OFF);
}
if(slider_pos > (4*STEP_SIZE))
{
Cy_GPIO_Write(CYBSP_LED_SLD4_PORT, CYBSP_LED_SLD4_NUM, LED_ON);
}
else
{
Cy_GPIO_Write(CYBSP_LED_SLD4_PORT, CYBSP_LED_SLD4_NUM, LED_OFF);
}
if(slider_pos > (5*STEP_SIZE))
{
Cy_GPIO_Write(CYBSP_LED_SLD5_PORT, CYBSP_LED_SLD5_NUM, LED_ON);
}
else
{
Cy_GPIO_Write(CYBSP_LED_SLD5_PORT, CYBSP_LED_SLD5_NUM, LED_OFF);
}
}
else
{
Cy_GPIO_Write(CYBSP_LED_SLD0_PORT, CYBSP_LED_SLD0_NUM, LED_OFF);
Cy_GPIO_Write(CYBSP_LED_SLD1_PORT, CYBSP_LED_SLD1_NUM, LED_OFF);
Cy_GPIO_Write(CYBSP_LED_SLD2_PORT, CYBSP_LED_SLD2_NUM, LED_OFF);
Cy_GPIO_Write(CYBSP_LED_SLD3_PORT, CYBSP_LED_SLD3_NUM, LED_OFF);
Cy_GPIO_Write(CYBSP_LED_SLD4_PORT, CYBSP_LED_SLD4_NUM, LED_OFF);
Cy_GPIO_Write(CYBSP_LED_SLD5_PORT, CYBSP_LED_SLD5_NUM, LED_OFF);
if(f_s==1)
{
Cy_SCB_UART_PutString(CYBSP_UART_HW, "nse\r\n");
}
}

/* LED ON/OFF based on the CAPSENSE buttons status */
if(0 != Cy_CapSense_IsSensorActive(CY_CAPSENSE_BUTTON0_WDGT_ID, CY_CAPSENSE_BUTTON0_SNS0_ID, &cy_capsense_context))
{
Cy_GPIO_Write(CYBSP_LED_BTN0_PORT, CYBSP_LED_BTN0_NUM, LED_ON);
Cy_SCB_UART_PutString(CYBSP_UART_HW, "np1b\r\n");
f_b1=1;
}
else
{
Cy_GPIO_Write(CYBSP_LED_BTN0_PORT, CYBSP_LED_BTN0_NUM, LED_OFF);
if(f_b1==1)
{
// f_b1=0;
Cy_SCB_UART_PutString(CYBSP_UART_HW, "np1e\r\n");
}
}
if(0 != Cy_CapSense_IsSensorActive(CY_CAPSENSE_BUTTON1_WDGT_ID, CY_CAPSENSE_BUTTON1_SNS0_ID, &cy_capsense_context))
{
Cy_GPIO_Write(CYBSP_LED_BTN1_PORT, CYBSP_LED_BTN1_NUM, LED_ON);
Cy_SCB_UART_PutString(CYBSP_UART_HW, "np2b\r\n");
f_b2=1;
}
else
{
Cy_GPIO_Write(CYBSP_LED_BTN1_PORT, CYBSP_LED_BTN1_NUM, LED_OFF);
if(f_b2==1)
{
// f_b2=0;
Cy_SCB_UART_PutString(CYBSP_UART_HW, "np2e\r\n");
}
}
if(0 != Cy_CapSense_IsSensorActive(CY_CAPSENSE_BUTTON2_WDGT_ID, CY_CAPSENSE_BUTTON2_SNS0_ID, &cy_capsense_context))
{
Cy_GPIO_Write(CYBSP_LED_BTN2_PORT, CYBSP_LED_BTN2_NUM, LED_ON);
Cy_SCB_UART_PutString(CYBSP_UART_HW, "np3b\r\n");
f_b3=1;
}
else
{
Cy_GPIO_Write(CYBSP_LED_BTN2_PORT, CYBSP_LED_BTN2_NUM, LED_OFF);
if(f_b3==1)
{
// f_b3=0;
Cy_SCB_UART_PutString(CYBSP_UART_HW, "np3e\r\n");
}
}
}

这里主要是对按键和滑条状态的判断,然后是控制LED的通断,最后是将状态发送至上位机。


上位机驱动和板卡间的通信协议如下,以n为起始位,p代表按键,后面1、2、3代表按键标号,b代表按下,e代表抬起;s代表滑条,v表示处于触摸中,后接以0填充的3为整数,表示触摸的位置。按键和滑条均以\r\n作为结束。

四、上位机软件

上位机软件基于QT实现,由于需要系统级别操作,本程序程序需要引用系统API,但是作者仅有Windows电脑,因此本项目仅在装有WIndows的电脑上有良好效果。上位机的串口通信与数据处理和按键模拟分开处理。串口通信基于串口数据可读的槽函数,按键模拟基于定时器超时的槽函数。


串口数据可读的槽函数如下。首先读取全部数值,然后循环每一位处理,如果不是\n就将本位存入buffer,如果是,就处理buffer。本段代码中的通信协议解析此处不做赘述。需要注意的是,对于滑条数据,由于手指离开触摸区域的瞬间会有数据突变,因而,要做限幅。同样,为了去抖,加入线性IIR滤波器,后接死区截断。

QObject::connect(serialport,&QSerialPort::readyRead,this,[&](){

QByteArray data = serialport->readAll();

foreach(char b , data)
{
if (b != '\n')
{
buffer.append(b);
}
else
{
QString str(buffer);
buffer.clear();
if(str[0]=="n")
{
if(str[1]=="p")
{
if(str[2]=="1")
{
if(str[3]=="b")
{
p1_s=1;
}
else if(str[3]=="e")
{
if(p1_s==1)
{
p1_ss=1;
p1_s=0;
}
}
}
else if(str[2]=="2")
{
if(str[3]=="b")
{
p2_s=1;
}
else if(str[3]=="e")
{
if(p2_s==1)
{
p2_ss=1;
p2_s=0;
}
}

}
else if(str[2]=="3")
{
if(str[3]=="b")
{
p3_s=1;
}
else if(str[3]=="e")
{
if(p3_s==1)
{
p3_ss=1;
p3_s=0;
}
}

}
}
else if(str[1]=="s")
{

if(str[2]=="v")
{
l_v=(str[3].digitValue())*100+(str[4].digitValue())*10+(str[5].digitValue());
if(l_s>1)
{
l_d=(l_v-l_vv)*0.8+l_d*0.2;
if(abs(l_d)>5)
l_d=0;
if(abs(l_d)<0.5)
l_d=0;
qDebug()<<l_d<<"\n";
}
else if (l_s==0)
l_s=1;
else if (l_s==1)
l_s=2;
l_vv=l_v;
}
else if(str[3]=="e")
{
l_s=0;
l_v=0;
l_vv=0;
l_d=0;
l_b=0;
}

}
}
}
}
});


定时器超时的槽函数如下,根据不同状态向系统输入不同的按键即可。

QObject::connect(tim1,&QTimer::timeout,this,[&](){
if(p1_ss)
{
switch(state)
{
case 1:
simulateKeyPressWin(VK_LWIN);
break;
case 0:
simulateKeyPressWin(VK_MEDIA_PLAY_PAUSE);
break;
}
p1_ss=0;

}

if(p2_ss)

{

switch(state)
{

case 1:
simulateKeyPressWin(VK_RETURN);
break;

case 0:
simulateKeyPressWin(VK_MEDIA_NEXT_TRACK);
break;
}
p2_ss=0;

}

if(p3_ss)

{

switch(state)
{
case 1:
simulateKeyPressWin(VK_DELETE);
break;

case 0:
simulateKeyPressWin(VK_MEDIA_PREV_TRACK);
break;
}
p3_ss=0;
}
if((l_s)&&(l_d!=0))
{
switch(state)
{
case 0:
if(l_d>0)
{
simulateKeyPressWin(VK_VOLUME_DOWN);
if(high)
simulateKeyPressWin(VK_VOLUME_DOWN);
}
else if(l_d<0){
simulateKeyPressWin(VK_VOLUME_UP);
if(high)
simulateKeyPressWin(VK_VOLUME_UP);
}
break;
case 1:
sroll(l_d);

break;
}

l_d=0;

}

});



五、最终效果

具体效果请参考视频,实物如图。


2abb1f7cdcbc3f960625cb2c4c0a9f4.jpg

六、展望

本项目实现了一个多功能的桌面控制台,其可以控制系统音量加减,音乐上一首、下一首,音乐的开始和暂停,并能模拟纵向滚轮,Windows键,回车键和删除键等输入。但是,由于滑条存在的段落式定位问题,会使纵向滚轮存在段式响应的问题,降低操作手感。可以通过精确校准,来降低这一问题。同时,上位机函待完善以支持自定义按键,而非更改源码。



附件下载
CAPSENSE_SmartSense_buttons_slider.7z
untitled.7z
团队介绍
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号