Funpack4-1——基于CY8CKIT-149开发套件的触摸控制电脑上下翻页
该项目使用了PSCON4.4 IDE,实现了CY8CKIT-149开发套件的设计,它的主要功能为:触摸跟BLE通讯控制电脑上下翻页。
标签
嵌入式系统
Funpack活动
reidentify
更新2025-04-08
21

一、项目简介

本项目使用Funpack第四季第1期活动的板卡,CY8CKIT-149开发套件,PSoC 4100S Plus主控,完成了任务二。

只需要通过触摸主控,发送信号的BLE芯片,连接电脑以实现控制音量等HID功能。


二、硬件资源

开发环境:

赛普拉斯支持两种开发环境

PSOC Creator 4.4

[PSoC Creator下载地址](https://www.infineon.com/cms/en/design-support/tools/sdk/psoc-software/psoc-creator/)

ModusToolbox,在vscode里面的应用市场下载

开发板:CY8CKIT-149-4100S PLUS

M0+芯片:CY8C4147AZI-S475

BLE芯片:CYBLE-022001-00


三、探索过程

刚开始寄过来的开发板默认使用了CE220891_CapSense_with_Breathing_LED的Demo以做展示。

环境问题,导致无法编译。
image.png


四、实现任务流程

1.规划硬件外设:

触摸按键(CSX) * 3
触摸滑条(CSX) * 1
EZI2C从机 * 1
I2C主机 * 1

通讯IO
M0_EZI2C_SCL[P30] -- BLE_I2C_MASTER_SCL[P51]
M0_EZI2C_SDA[P31] -- BLE_I2C_MASTER_SDA[P50]

CSX区别于CSD按键,可以少用一个IO,相对来说,抗干扰性更弱

CSX软件设置如图所示,Mutual-cap则对应CSD
image.png

2.程序架构:

BLE HID服务配置:键盘模式
CapSense触摸检测
I2C通信传输触摸数据
HID报告发送

3.使用介绍

上电后,会亮3个指示灯
开发板上电后,LED指示灯会闪烁表示正在广播
在电脑的蓝牙设置中搜索并连接设备(显示为BLE Keyboard)
连接成功后,LED指示灯常亮
使用触摸按键和滑条控制电脑:
左按键:音量加
右按键:音量减
中间按键:亮度调节
滑条:控制屏幕页面上下滚动

4.参考Demo:

E224820_PSoC4_CapSense_Slider_Gesture

BLE_HID_Keyboard

5.遇到的问题:

HID函数添加延时也无法解决,HID一直会发送指令,不会松开,暂时无法查明原因,希望各位大佬能给点意见。

6.技术细节
通过CapSense_DecodeWidgetGestures函数,获取当前滑条的手势,返回一个状态值,再根据状态值传送对应的EZI2C参数和LED操作事件

 /* Stores the current detected gesture */
            detectedGesture = CapSense_DecodeWidgetGestures(CapSense_LINEARSLIDER0_WDGT_ID);
           
            /* Turns a specific LED on or off depending on the gesture */
            switch(detectedGesture){
            case CapSense_ONE_FINGER_FLICK_RIGHT:
                /* If LED is on turn it off, or if off turn it on */
                Right_LED_Write((Right_LED_Read() == LED_ON) ? LED_OFF: LED_ON);
                i2cBuffer[BUTTON_STATUS_INDEX2] = 0x01;
                break;
            case CapSense_ONE_FINGER_SINGLE_CLICK:
                /* If LED is on turn it off, or if off turn it on */
                PWM_WriteCompare((PWM_ReadCompare() != 0) ? 0: HALF_POWER);
                break;
            case CapSense_ONE_FINGER_FLICK_LEFT:
                /* If LED is on turn it off, or if off turn it on */
                Left_LED_Write((Left_LED_Read() == LED_ON) ? LED_OFF: LED_ON);
                i2cBuffer[BUTTON_STATUS_INDEX2] = 0x02;
                break;
            }


            LED11_Write(CapSense_IsWidgetActive(CapSense_BUTTON0_WDGT_ID) ? LED_ON : LED_OFF );
            // LED_12_Write(CapSense_IsWidgetActive(CapSense_BUTTON1_WDGT_ID) ? LED_ON : LED_OFF );
            LED13_Write(CapSense_IsWidgetActive(CapSense_BUTTON2_WDGT_ID) ? LED_ON : LED_OFF );


            /* Calculate the button status mask and update the I2C buffer
                bit0= BTN0 status, bit1 = BTN1 status, bit2 = BTN2 status */
            for(uint8 widgetID = 0; widgetID < TOTAL_CAPSENSE_BUTTONS; widgetID++)
            {
                if(CapSense_IsWidgetActive(widgetID))
                {
                    SET_BIT(buttonStatus, widgetID);
                }
                else
                {
                    CLEAR_BIT(buttonStatus, widgetID);
                }
            }

使用for循环遍历,获取触摸按键状态,再根据滑条调整LED的PWM占空比,最后EZI2C发送滑环百分比和按键值

            /* Calculate the button status mask and update the I2C buffer
                bit0= BTN0 status, bit1 = BTN1 status, bit2 = BTN2 status */
            for(uint8 widgetID = 0; widgetID < TOTAL_CAPSENSE_BUTTONS; widgetID++)
            {
                if(CapSense_IsWidgetActive(widgetID))
                {
                    SET_BIT(buttonStatus, widgetID);
                }
                else
                {
                    CLEAR_BIT(buttonStatus, widgetID);
                }
            }
/* Checks if the linear slidere was touched and that the slider should be changed */
            if(CapSense_GetCentroidPos(CapSense_LINEARSLIDER0_WDGT_ID) != CapSense_SLIDER_NO_TOUCH && PWM_ReadCompare() != 0)
            {
                /* Changes the compare value based on the slider position */
                PWM_WriteCompare(PWM_SCALAR * CapSense_GetCentroidPos(CapSense_LINEARSLIDER0_WDGT_ID) + 1);
            }
            i2cBuffer[SLIDER_PERCENT_INDEX] = CapSense_GetCentroidPos(CapSense_LINEARSLIDER0_WDGT_ID);
            i2cBuffer[BUTTON_STATUS_INDEX1] = buttonStatus;

BLE这边参考了大佬的代码,放到等待BLE连接成功的大循环里面。实现了IIC轮询只读数据标志位,来获取从机的数据,实现事件传递。做完事件,需要清除标志,避免被重复触发。

static uint8 buffer[BUFFER_SIZE];


void ReceiveData(void)
{
    static uint8 sliderPercentValue = 0;
    static uint8 touchKeyValue = 0;
    static uint8 sliderGestureValue = 0;


    /* Read entire data buffer from the slave device */
    IIC_I2CMasterReadBuf(I2C_SLAVE_ADDRESS, buffer, BUFFER_SIZE,
                    IIC_I2C_MODE_COMPLETE_XFER);    
    while (0u == (IIC_I2CMasterStatus() & IIC_I2C_MSTAT_RD_CMPLT))
    {
        CyBle_ProcessEvents();
    }


    sliderPercentValue = buffer[SLIDER_PERCENT_INDEX];


    sliderGestureValue = buffer[BUTTON_STATUS_INDEX2];


    if(sliderGestureValue == SLIDER_GESTURE_RIGHT)
    {
        SendKeyboard(PAGE_UP);
        send_key_board_flag = 1;
        sliderGestureValue = 0;
    }
    else if(sliderGestureValue == SLIDER_GESTURE_LEFT)
    {
        SendKeyboard(PAGE_DOWN);
        send_key_board_flag = 1;
        sliderGestureValue = 0;
    }


    touchKeyValue = buffer[BUTTON_STATUS_INDEX1];
    if(touchKeyValue)
    {
        if(touchKeyValue & 0x01)
        {
            send_key_board_flag = 1;
            SendKeyboard(VOLUME_UP);
            touchKeyValue = 0;
        }
        if(touchKeyValue & 0x02)
        {
            send_key_board_flag = 1;
            SendKeyboard(VOLUME_DOWN);
            touchKeyValue = 0;
        }
        if(touchKeyValue & 0x04)
        {
            send_key_board_flag = 1;
            SendKeyboard(LIGHT_DOWN);
            touchKeyValue = 0;
        }
    }
}

HID发送,参考了BLEdemo里面的发送asciil函数。使用了全局标志控制,避免事件被重复触发,对常用的区块进行了函数封装。HID和IIC一样使用了判断标志位来轮询HID的状态,以进行数据传输到电脑。



uint8 send_key_board_flag = 0;


void SendKeyboard(uint8 SimKey)
{
    static uint8 keyboard_data[KEYBOARD_DATA_SIZE]={0};
    CYBLE_API_RESULT_T apiResult;
    keyboard_data[2u] = SimKey;


    if(!send_key_board_flag)
    {
        return;
    }
    send_key_board_flag = 0;
    if(CyBle_GattGetBusyStatus() == CYBLE_STACK_STATE_FREE)
    {
        apiResult = CyBle_HidssGetCharacteristicValue(CYBLE_HUMAN_INTERFACE_DEVICE_SERVICE_INDEX, CYBLE_HIDS_PROTOCOL_MODE, sizeof(protocol), &protocol);
        SendHidNotification(keyboard_data);
        if(apiResult == CYBLE_ERROR_OK)
        {
            memset(keyboard_data, 0, KEYBOARD_DATA_SIZE);
            SendHidNotification(keyboard_data);
        }
        if(apiResult != CYBLE_ERROR_OK)
        {
            DBG_PRINTF("HID notification API Error: %x \r\n", apiResult);
            keyboardSimulation = DISABLED;
        }
    }
}


CYBLE_API_RESULT_T SendHidNotification(uint8_t* data)
{
    CYBLE_API_RESULT_T result;


    if(protocol == CYBLE_HIDS_PROTOCOL_MODE_BOOT)
    {
        result = CyBle_HidssSendNotification(cyBle_connHandle,
            CYBLE_HUMAN_INTERFACE_DEVICE_SERVICE_INDEX,
            CYBLE_HIDS_BOOT_KYBRD_IN_REP,
            KEYBOARD_DATA_SIZE,
            data);
    }
    else
    {
        result = CyBle_HidssSendNotification(cyBle_connHandle,
            CYBLE_HUMAN_INTERFACE_DEVICE_SERVICE_INDEX,
            CYBLE_HUMAN_INTERFACE_DEVICE_REPORT_IN,
            KEYBOARD_DATA_SIZE,
            data);
    }
    return result;
}


感谢大家的观看,也欢迎在评论区交流,指出我的不足。感谢电子森林和得捷电子的大力支持本次活动。

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