蓝牙HID设备开发:基于英飞凌CY8CKIT-149实现CapSense触摸控制的PC键盘

文章目录

    • 摘要
    • [1. 项目概述](#1. 项目概述)
      • [1.1 项目背景](#1.1 项目背景)
      • [1.2 技术选型](#1.2 技术选型)
      • [1.3 系统架构](#1.3 系统架构)
    • [2. 开发环境搭建](#2. 开发环境搭建)
      • [2.1 硬件准备](#2.1 硬件准备)
      • [2.2 软件安装](#2.2 软件安装)
      • [2.3 环境配置步骤](#2.3 环境配置步骤)
    • [3. 硬件设计与连接](#3. 硬件设计与连接)
      • [3.1 CapSense传感器设计](#3.1 CapSense传感器设计)
      • [3.2 硬件连接示意图](#3.2 硬件连接示意图)
    • [4. 软件实现](#4. 软件实现)
      • [4.1 创建工程文件](#4.1 创建工程文件)
      • [4.2 主程序代码(main.c)](#4.2 主程序代码(main.c))
      • [4.3 CapSense处理代码(capsense.c)](#4.3 CapSense处理代码(capsense.c))
      • [4.4 蓝牙HID实现(bluetooth_hid.c)](#4.4 蓝牙HID实现(bluetooth_hid.c))
      • [4.5 键盘处理代码(keyboard.c)](#4.5 键盘处理代码(keyboard.c))
    • [5. 系统配置与调试](#5. 系统配置与调试)
      • [5.1 CapSense参数调优](#5.1 CapSense参数调优)
      • [5.2 蓝牙配置](#5.2 蓝牙配置)
    • [6. 常见问题与解决方案](#6. 常见问题与解决方案)
      • [6.1 CapSense灵敏度问题](#6.1 CapSense灵敏度问题)
      • [6.2 蓝牙连接不稳定](#6.2 蓝牙连接不稳定)
      • [6.3 功耗优化](#6.3 功耗优化)
    • [7. 成果展示与测试](#7. 成果展示与测试)
      • [7.1 功能测试](#7.1 功能测试)
      • [7.2 性能指标](#7.2 性能指标)
    • [8. 技术图谱](#8. 技术图谱)
    • [9. 总结与展望](#9. 总结与展望)

摘要

本文详细介绍如何使用英飞凌CY8CKIT-149开发板,通过CapSense电容触摸技术实现蓝牙HID键盘设备的开发,包含完整的硬件连接、软件编程和调试过程。

1. 项目概述

1.1 项目背景

蓝牙HID(Human Interface Device)设备在现代计算机外设中扮演着重要角色。传统的机械键盘存在磨损、噪音大等问题,而电容触摸技术提供了更好的用户体验和更长的使用寿命。

1.2 技术选型

英飞凌CY8CKIT-149开发板集成了PSoC 6 MCU和AIROC CYW20835蓝牙芯片,支持CapSense电容触摸技术,是开发蓝牙HID设备的理想平台。

1.3 系统架构

CY8CKIT-149开发板
CapSense触摸传感器
蓝牙射频电路
PSoC 6 MCU
CYW20835蓝牙芯片
电容触摸检测
数据处理
蓝牙通信
PC/手机等蓝牙主机

2. 开发环境搭建

2.1 硬件准备

  • 英飞凌CY8CKIT-149开发板
  • USB数据线
  • 跳线若干
  • 电容触摸板或自制电极

2.2 软件安装

  1. 下载并安装ModusToolbox IDE
  2. 安装PSoC 6系列支持包
  3. 安装蓝牙协议栈
  4. 安装必要的驱动和工具链

2.3 环境配置步骤

bash 复制代码
# 安装ModusToolbox
wget https://download.cypress.com/modustoolbox/ModusToolbox_3.0.0.alpha4.exe

# 安装后设置环境变量
export MTB_TOOLS_PATH=/opt/ModusToolbox/tools_3.0
export CYSDK=/opt/ModusToolbox

3. 硬件设计与连接

3.1 CapSense传感器设计

电容触摸传感器的设计需要考虑电极形状、大小和布局。我们使用开发板上的现有按钮或外接电极。

3.2 硬件连接示意图

CY8CKIT-149开发板
CapSense电极1

GPIO P0.1
CapSense电极2

GPIO P0.2
CapSense电极3

GPIO P0.3
CapSense电极4

GPIO P0.4
LED指示灯

GPIO P10.0
电源3.3V
地线GND

4. 软件实现

4.1 创建工程文件

创建以下文件结构:

复制代码
bluetooth_hid_keyboard/
├── main.c
├── keyboard.h
├── keyboard.c
├── capsense.h
├── capsense.c
├── bluetooth_hid.h
├── bluetooth_hid.c
└── Makefile

4.2 主程序代码(main.c)

c 复制代码
/**
 * @file main.c
 * @brief 蓝牙HID键盘主程序
 * @version 1.0
 * @date 2023-10-15
 */

#include "cy_pdl.h"
#include "cyhal.h"
#include "cybsp.h"
#include "cycfg.h"
#include "keyboard.h"
#include "capsense.h"
#include "bluetooth_hid.h"

/* 全局变量定义 */
cyhal_gpio_callback_data_t capsense_cb_data;
bool capsense_touched[CAPSENSE_BUTTON_COUNT] = {false};

int main(void)
{
    cy_rslt_t result;
    
    /* 初始化硬件平台 */
    result = cybsp_init();
    if (result != CY_RSLT_SUCCESS)
    {
        CY_ASSERT(0);
    }
    
    /* 使能全局中断 */
    __enable_irq();
    
    /* 初始化CapSense */
    result = capsense_init();
    if (result != CY_RSLT_SUCCESS)
    {
        CY_ASSERT(0);
    }
    
    /* 初始化蓝牙HID */
    result = bluetooth_hid_init();
    if (result != CY_RSLT_SUCCESS)
    {
        CY_ASSERT(0);
    }
    
    /* 主循环 */
    for (;;)
    {
        /* 检测CapSense触摸 */
        capsense_scan();
        
        /* 处理键盘事件 */
        keyboard_process();
        
        /* 短暂延时 */
        cyhal_system_delay_ms(10);
    }
}

4.3 CapSense处理代码(capsense.c)

c 复制代码
/**
 * @file capsense.c
 * @brief CapSense电容触摸处理
 * @version 1.0
 * @date 2023-10-15
 */

#include "capsense.h"

/* CapSense中间件上下文 */
cy_stc_capsense_context_t capsense_context;
cy_stc_capsense_widget_context_t *widgetContext;

cy_rslt_t capsense_init(void)
{
    cy_rslt_t result = CY_RSLT_SUCCESS;
    
    /* 初始化CapSense配置 */
    result = cy_capsense_init(&capsense_context);
    if (CY_RSLT_SUCCESS != result)
    {
        return result;
    }
    
    /* 启用CapSense */
    result = cy_capsense_enable(&capsense_context);
    if (CY_RSLT_SUCCESS != result)
    {
        return result;
    }
    
    /* 初始化所有传感器 */
    result = cy_capsense_init_sensors(&capsense_context);
    if (CY_RSLT_SUCCESS != result)
    {
        return result;
    }
    
    /* 初始化所有Widget */
    result = cy_capsense_init_widgets(&capsense_context);
    if (CY_RSLT_SUCCESS != result)
    {
        return result;
    }
    
    /* 扫描所有传感器 */
    result = cy_capsense_scan_all_widgets(&capsense_context);
    if (CY_RSLT_SUCCESS != result)
    {
        return result;
    }
    
    return result;
}

void capsense_scan(void)
{
    static uint32_t prev_touch_status = 0;
    uint32_t current_touch_status;
    uint32_t touch_diff;
    uint32_t widget_id;
    
    /* 处理CapSense扫描 */
    if (CY_CAPSENSE_NOT_BUSY == cy_capsense_is_busy(&capsense_context))
    {
        /* 处理触摸数据 */
        cy_capsense_process_all_widgets(&capsense_context);
        
        /* 获取触摸状态 */
        current_touch_status = cy_capsense_get_touch_state(&capsense_context, 0);
        
        /* 检测状态变化 */
        touch_diff = prev_touch_status ^ current_touch_status;
        
        for (widget_id = 0; widget_id < CY_CAPSENSE_TOTAL_WIDGET_COUNT; widget_id++)
        {
            if (touch_diff & (1u << widget_id))
            {
                if (current_touch_status & (1u << widget_id))
                {
                    /* 触摸按下事件 */
                    handle_touch_press(widget_id);
                }
                else
                {
                    /* 触摸释放事件 */
                    handle_touch_release(widget_id);
                }
            }
        }
        
        prev_touch_status = current_touch_status;
        
        /* 启动下一次扫描 */
        cy_capsense_scan_all_widgets(&capsense_context);
    }
}

void handle_touch_press(uint32_t widget_id)
{
    /* 根据Widget ID处理不同的触摸按键 */
    switch (widget_id)
    {
        case CAPSENSE_BUTTON0_WIDGET_ID:
            keyboard_set_key(KEY_A, true);
            break;
        case CAPSENSE_BUTTON1_WIDGET_ID:
            keyboard_set_key(KEY_B, true);
            break;
        case CAPSENSE_BUTTON2_WIDGET_ID:
            keyboard_set_key(KEY_C, true);
            break;
        case CAPSENSE_BUTTON3_WIDGET_ID:
            keyboard_set_key(KEY_D, true);
            break;
        default:
            break;
    }
}

void handle_touch_release(uint32_t widget_id)
{
    /* 根据Widget ID处理不同的触摸释放 */
    switch (widget_id)
    {
        case CAPSENSE_BUTTON0_WIDGET_ID:
            keyboard_set_key(KEY_A, false);
            break;
        case CAPSENSE_BUTTON1_WIDGET_ID:
            keyboard_set_key(KEY_B, false);
            break;
        case CAPSENSE_BUTTON2_WIDGET_ID:
            keyboard_set_key(KEY_C, false);
            break;
        case CAPSENSE_BUTTON3_WIDGET_ID:
            keyboard_set_key(KEY_D, false);
            break;
        default:
            break;
    }
}

4.4 蓝牙HID实现(bluetooth_hid.c)

c 复制代码
/**
 * @file bluetooth_hid.c
 * @brief 蓝牙HID功能实现
 * @version 1.0
 * @date 2023-10-15
 */

#include "bluetooth_hid.h"
#include "wiced_bt_dev.h"
#include "wiced_bt_gatt.h"
#include "wiced_bt_hidd.h"

/* HID设备描述符 */
const uint8_t hid_report_descriptor[] =
{
    0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
    0x09, 0x06,        // Usage (Keyboard)
    0xA1, 0x01,        // Collection (Application)
    0x05, 0x07,        //   Usage Page (Key Codes)
    0x19, 0xE0,        //   Usage Minimum (0xE0)
    0x29, 0xE7,        //   Usage Maximum (0xE7)
    0x15, 0x00,        //   Logical Minimum (0)
    0x25, 0x01,        //   Logical Maximum (1)
    0x75, 0x01,        //   Report Size (1)
    0x95, 0x08,        //   Report Count (8)
    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x95, 0x01,        //   Report Count (1)
    0x75, 0x08,        //   Report Size (8)
    0x81, 0x01,        //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x95, 0x05,        //   Report Count (5)
    0x75, 0x01,        //   Report Size (1)
    0x05, 0x08,        //   Usage Page (LEDs)
    0x19, 0x01,        //   Usage Minimum (Num Lock)
    0x29, 0x05,        //   Usage Maximum (Kana)
    0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
    0x95, 0x01,        //   Report Count (1)
    0x75, 0x03,        //   Report Size (3)
    0x91, 0x01,        //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
    0x95, 0x06,        //   Report Count (6)
    0x75, 0x08,        //   Report Size (8)
    0x15, 0x00,        //   Logical Minimum (0)
    0x25, 0x65,        //   Logical Maximum (101)
    0x05, 0x07,        //   Usage Page (Key Codes)
    0x19, 0x00,        //   Usage Minimum (0)
    0x29, 0x65,        //   Usage Maximum (101)
    0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0xC0,              // End Collection
};

/* HID报告映射 */
static uint8_t keyboard_report[8] = {0};

cy_rslt_t bluetooth_hid_init(void)
{
    wiced_bt_hidd_device_initialize();
    
    /* 配置HID设备属性 */
    wiced_bt_hidd_attr_t hid_attr = {
        .dev_info.bd_addr = {0}, // 蓝牙地址
        .dev_info.vendor_id = 0x0001,
        .dev_info.product_id = 0x0001,
        .dev_info.version = 0x0100,
        .dev_info.ctry_code = 0x00,
        .dev_info.flags = 0,
        .dev_info.p_manufacturer_name = "Infineon",
        .dev_info.p_product_name = "CapSense Keyboard",
        .dev_info.p_serial_num = "123456",
        .p_report_desc = hid_report_descriptor,
        .report_desc_len = sizeof(hid_report_descriptor),
        .sup_timeout = 0,
        .norm_conn_min_interval = 6,
        .norm_conn_max_interval = 6,
        .norm_conn_latency = 0,
        .norm_conn_sup_timeout = 100,
        .boot_dev = TRUE
    };
    
    /* 注册HID设备 */
    wiced_bt_hidd_register(&hid_attr);
    
    /* 设置可发现模式 */
    wiced_bt_dev_set_discoverability(BTM_NON_DISCOVERABLE, 0, 0);
    
    /* 设置可连接模式 */
    wiced_bt_dev_set_connectability(BTM_NON_CONNECTABLE, 0, 0);
    
    return CY_RSLT_SUCCESS;
}

void bluetooth_send_key_report(void)
{
    /* 发送键盘报告 */
    wiced_bt_hidd_send_report(
        HID_TRANS_SPORT_TYPE_LE, 
        HID_REPORT_TYPE_INPUT, 
        0, 
        sizeof(keyboard_report), 
        keyboard_report
    );
}

void bluetooth_update_key(uint8_t keycode, bool pressed)
{
    if (pressed)
    {
        /* 查找空闲位置添加按键 */
        for (int i = 2; i < 8; i++)
        {
            if (keyboard_report[i] == 0)
            {
                keyboard_report[i] = keycode;
                break;
            }
        }
    }
    else
    {
        /* 移除按键 */
        for (int i = 2; i < 8; i++)
        {
            if (keyboard_report[i] == keycode)
            {
                keyboard_report[i] = 0;
                break;
            }
        }
    }
    
    /* 发送更新后的报告 */
    bluetooth_send_key_report();
}

4.5 键盘处理代码(keyboard.c)

c 复制代码
/**
 * @file keyboard.c
 * @brief 键盘逻辑处理
 * @version 1.0
 * @date 2023-10-15
 */

#include "keyboard.h"

/* 键盘状态 */
static keyboard_state_t keyboard_state = {
    .keys_pressed = {0},
    .modifiers = 0
};

void keyboard_init(void)
{
    /* 初始化键盘状态 */
    memset(&keyboard_state, 0, sizeof(keyboard_state));
}

void keyboard_set_key(uint8_t keycode, bool pressed)
{
    /* 更新键盘状态 */
    if (pressed)
    {
        /* 检查是否为修饰键 */
        if (keycode >= KEY_LEFT_CTRL && keycode <= KEY_RIGHT_GUI)
        {
            keyboard_state.modifiers |= (1 << (keycode - KEY_LEFT_CTRL));
        }
        else
        {
            /* 添加普通按键 */
            for (int i = 0; i < MAX_KEYS_PRESSED; i++)
            {
                if (keyboard_state.keys_pressed[i] == 0)
                {
                    keyboard_state.keys_pressed[i] = keycode;
                    break;
                }
            }
        }
    }
    else
    {
        /* 检查是否为修饰键 */
        if (keycode >= KEY_LEFT_CTRL && keycode <= KEY_RIGHT_GUI)
        {
            keyboard_state.modifiers &= ~(1 << (keycode - KEY_LEFT_CTRL));
        }
        else
        {
            /* 移除普通按键 */
            for (int i = 0; i < MAX_KEYS_PRESSED; i++)
            {
                if (keyboard_state.keys_pressed[i] == keycode)
                {
                    keyboard_state.keys_pressed[i] = 0;
                    break;
                }
            }
        }
    }
    
    /* 更新蓝牙HID报告 */
    update_hid_report();
}

void update_hid_report(void)
{
    /* 构建HID报告 */
    uint8_t report[8] = {0};
    
    /* 设置修饰键 */
    report[0] = keyboard_state.modifiers;
    
    /* 设置普通按键 */
    int report_index = 2;
    for (int i = 0; i < MAX_KEYS_PRESSED; i++)
    {
        if (keyboard_state.keys_pressed[i] != 0 && report_index < 8)
        {
            report[report_index++] = keyboard_state.keys_pressed[i];
        }
    }
    
    /* 发送报告 */
    bluetooth_update_key_report(report);
}

void keyboard_process(void)
{
    /* 处理去抖动和长按检测 */
    static uint32_t last_process_time = 0;
    uint32_t current_time = cyhal_timer_get_current_time();
    
    if (current_time - last_process_time > KEYBOARD_POLL_INTERVAL)
    {
        /* 更新HID报告 */
        update_hid_report();
        last_process_time = current_time;
    }
}

5. 系统配置与调试

5.1 CapSense参数调优

在ModusToolbox中配置CapSense参数:
CapSense配置
传感器类型选择
灵敏度设置
噪声阈值
去抖动参数
按钮传感器
滑条传感器
接近传感器
Fine调谐
Coarse调谐
自动噪声滤波
手动阈值设置
数字滤波器
软件去抖动

5.2 蓝牙配置

配置蓝牙参数和GATT服务:

c 复制代码
/* GATT服务配置 */
const wiced_bt_gatt_attr_t hid_gatt_attrs[] = 
{
    /* HID服务声明 */
    {.attr_type = BT_GATT_UUID_PRIMARY_SERVICE, .attr_value = {.p_val = hid_service_uuid, .len = 16}},
    
    /* HID信息特性 */
    {.attr_type = BT_GATT_UUID_CHARACTERISTIC, .attr_value = {.p_val = hid_info_char_uuid, .len = 16}},
    
    /* 报告映射特性 */
    {.attr_type = BT_GATT_UUID_CHARACTERISTIC, .attr_value = {.p_val = report_map_char_uuid, .len = 16}},
    
    /* 输入报告特性 */
    {.attr_type = BT_GATT_UUID_CHARACTERISTIC, .attr_value = {.p_val = input_report_char_uuid, .len = 16}},
};

6. 常见问题与解决方案

6.1 CapSense灵敏度问题

问题描述 :触摸检测不灵敏或误触发
解决方案

  1. 调整CapSense参数:增加/减少手指阈值
  2. 添加软件滤波算法
  3. 优化电极布局和接地

6.2 蓝牙连接不稳定

问题描述 :蓝牙频繁断开或连接失败
解决方案

  1. 检查天线匹配电路
  2. 调整蓝牙发射功率
  3. 优化电源滤波

6.3 功耗优化

问题描述 :设备电池续航时间短
解决方案

  1. 使用低功耗模式
  2. 优化扫描间隔
  3. 实现睡眠唤醒机制

7. 成果展示与测试

7.1 功能测试

测试项目包括:

  • 单点触摸响应
  • 多点触摸支持
  • 蓝牙连接稳定性
  • 按键响应时间

7.2 性能指标

  • 触摸响应时间:<10ms
  • 蓝牙连接建立时间:<100ms
  • 待机功耗:<10μA
  • 工作电流:<5mA

8. 技术图谱

蓝牙HID键盘开发
硬件层
软件层
通信协议
PSoC 6 MCU
CapSense技术
CYW20835蓝牙
传感器设计
ModusToolbox
蓝牙协议栈
HID配置文件
驱动程序
蓝牙LE
HID over GATT
GATT服务
ATT协议
ARM Cortex-M4
低功耗设计
电容检测
噪声抑制
GAP层
GATT层
SM层
报告协议
设备描述符

9. 总结与展望

本项目成功实现了基于英飞凌CY8CKIT-149的蓝牙HID键盘,展示了CapSense技术在现代化人机交互设备中的应用潜力。未来可以进一步扩展功能,如添加手势识别、背光控制等特性,提升产品的竞争力。

通过本教程,读者可以掌握从硬件设计到软件开发的完整流程,为开发类似的蓝牙HID设备提供了全面的参考。

相关推荐
YJlio1 天前
文件工具学习笔记(12.8):MoveFile 实战——重启后重命名/删除顽固文件
笔记·学习·计算机外设
YJlio1 天前
文件工具学习笔记(12.7):Sysinternals 文件工具实战总览与排障闭环
笔记·学习·计算机外设
成都证图科技有限公司1 天前
如何启用扩展桌面模式
计算机外设
skywalk81632 天前
Deskflow 是一个开源的跨平台工具,用于在多台计算机之间共享鼠标和键盘。它允许用户通过一套键鼠控制多台电脑,就像操作单台机器一样流畅。
计算机外设·电脑·deskflow
TESmart碲视2 天前
深入解析:DisplayLink 是如何把“视频”变成 USB 数据再还原成显示信号的?
计算机外设·音视频·tesmart
ACP广源盛139246256733 天前
GSV2231G@ACP#2231G产品规格详解及产品应用分享
嵌入式硬件·计算机外设·音视频
ACP广源盛139246256733 天前
GSV6505F@ACP#6505F产品规格详解及产品应用分享
单片机·嵌入式硬件·计算机外设·音视频
我的golang之路果然有问题3 天前
win键盘设置改为类似mac 配置
windows·笔记·macos·计算机外设·键盘
tyatyatya3 天前
MATLAB图形交互教程:鼠标拾取/坐标轴交互/动态绘图实战详解
开发语言·matlab·计算机外设