文章目录
-
- 摘要
- [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 软件安装
- 下载并安装ModusToolbox IDE
- 安装PSoC 6系列支持包
- 安装蓝牙协议栈
- 安装必要的驱动和工具链
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灵敏度问题
问题描述 :触摸检测不灵敏或误触发
解决方案:
- 调整CapSense参数:增加/减少手指阈值
- 添加软件滤波算法
- 优化电极布局和接地
6.2 蓝牙连接不稳定
问题描述 :蓝牙频繁断开或连接失败
解决方案:
- 检查天线匹配电路
- 调整蓝牙发射功率
- 优化电源滤波
6.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设备提供了全面的参考。