基于XG24-EK2703A的BLE HID蓝牙键盘+鼠标复合设备功能开发(BLE+HID+FreeRTOS+Gecko SDK)

news2024/11/15 17:41:55

目录

  • 项目介绍
  • 硬件介绍
  • 项目设计
    • 开发环境及工程参考
    • 总体流程图
    • 硬件基本配置
    • 应用初始化
    • 按键中断回调
    • 定时器回调
    • 按键响应任务
    • 蓝牙事件回调
    • BLE HID
      • Report Map及报文
        • 键盘设备
        • 鼠标设备
        • 复合设备
      • 发送字符串
      • 上/下滚动
  • 功能展示
  • 项目总结

👉 【Funpack3-1】基于XG24-EK2703A的BLE HID蓝牙键盘+鼠标复合设备
👉 Github: EmbeddedCamerata/XG24_ble_hid_keymouse

项目介绍

本项目基于Silicon Labs XG24-EK2703A开发板,通过HID协议实现了一个蓝牙键盘+鼠标复合设备,可通过按键实现上下翻页、发送字符功能。使用板载两个按键,当BTN0按下,向上翻页;当BTN1按下,向下翻页;当两按键同时按下2s后,向主机依次发送字符“EETREE.CN”。

👉 Simplicity Studio 5

硬件介绍

XG24-EK2703A是一款基于EFR32MG24片上系统的开发套件,具备超低成本、低功耗和小巧的特点。该套件支持2.4GHz无线通信,兼容蓝牙LE、蓝牙mesh、Zigbee、Thread和Matter协议,为无线物联网产品的开发和原型制作提供了极大的便利。包含:

  1. 一个USB接口
  2. 一个板载SEGGER J-Link 调试器,支持SWD
  3. 两个LED和两个按钮
  4. 虚拟COM端口
  5. 数据包跟踪接口(PTI)
  6. 一个支持外部硬件连接的mikroBus插座和一个Qwiic连接器
  7. 32 位 ARM Cortex-M33,78 MHz最高工作频率
  8. 1536 kB 闪存和 256 kB RAM

XG24板卡资源图

项目设计

开发环境及工程参考

本项目使用Silicon Labs官方的IDE Simplicity Studio 5开发,使用Gecko SDK v4.4.0,GNU ARM Toolchain 12.2。工程目录上,按照Bluetooth - SoC Empty 空白示例的代码组织形式即可。主要的业务代码写在 app.capp.h 内,外设、驱动及蓝牙部分通过 .slcp 文件配置。

👉 本工程参考SiliconLabs蓝牙应用示例:bluetooth_hid_keyboard

总体流程图

所使用的系统外设:两个按键、两个LED及蓝牙栈。

  • 在按键中断回调中,根据不同按键按下,置位或清除各按键按下的事件
  • 使用FreeRTOS操作系统,创建按键响应任务,用以实现两个按键按下的响应服务:循环读取按键按下事件,当按键单独按下时,则用一枚举变量 km_status 记录:
    • 当BTN0按下,置 KM_SCROLL_UP
    • 当BTN1按下,置 KM_SCROLL_DOWN
    • 当同时按下,且无定时器在运行,则开启2s定时器,该定时器绑定一回调函数,在该回调内:置 km_statusKM_SEND_STRING,同时反转两LED状态(便于观察现象)
    • 最后,都向蓝牙栈发送外部事件信号
  • 在蓝牙事件回调中,当接收到外部事件信号后,根据 km_status 值进行相应操作。从而实现上/下翻页、发送字符的功能。

系统工作流程图

硬件基本配置

在基于 “Bluetooth - Soc Empty” 空白示例的基础上,打开 .slcp 文件,在 SOFTWARE COMPONENTS 选项卡下安装如下组件:

  • [Platform] → [Driver] → [Button] → [Simple Button],例化 btn0 与 btn1,对应开发板上两个按键,均设置为中断模式
  • [Platform] → [Driver] → [LED] → [Simple LED],例化 led0 与 led1,对应开发板上两个 LED
  • [Services] → [IO Stream] → [IO Stream: USART],保持默认配置即可
  • [Application] → [Utility] → [Timer for FreeRTOS]
  • [Application] → [Utility] → [Log]

并且,参考SiliconLabs蓝牙应用示例:bluetooth_hid_keyboard,使用该示例提供的 GATT 配置,导入到自己的工程中:

  1. 打开项目中 .slcp 文件
  2. 在 CONFIGURATION TOOLS 选项卡下找到 Bluetooth GATT Configurator
  3. 导入 config/btconf/gatt_configuration.btconf 文件
  4. 保存 GATT 配置

后续还会进行一定程度的修改。

应用初始化

app.h 内,定义四种按键按下的枚举类型,分别表示:未按下、发送字符(两按键同时按下)、上翻页(BTN0按下)及下翻页(BTN1按下):

typedef enum
{
  KM_IDLE = 0U,
  KM_SEND_STRING = 1U,
  KM_SCROLL_UP = 2U,
  KM_SCROLL_DOWN = 3U,
} km_status_t;

在初始化阶段,先创建按键按下事件组、按键响应任务。

#define KM_BTN_TASK_NAME        "keymouse_btn"
#define KM_BTN_TASK_STACK_SIZE  1024
#define KM_BTN_TASK_STATIC      0

TaskHandle_t km_btn_task_handle = NULL;
static EventGroupHandle_t xbtn_events = NULL;
static km_status_t km_status = KM_IDLE;

SL_WEAK void app_init(void)
{
  	xbtn_events = xEventGroupCreate();
  	if (xbtn_events == NULL) {
  		app_log_error("BTN events create failed\r\n");
	}
  	xTaskCreate(km_btn_task,
              	KM_BTN_TASK_NAME,
             	configMINIMAL_STACK_SIZE,
              	NULL,
              	tskIDLE_PRIORITY,
              	&km_btn_task_handle);
}

按键中断回调

按键中断回调定义在 void sl_button_on_change(const sl_button_t *handle) 内,可参考示例修改。在此,根据触发中断的句柄判断是哪个按键按下或释放,相应地置位或清除事件位 xbtn_events

#include "sl_simple_button_instances.h"
#define BTN0_PRESSED            (1 << 0)
#define BTN1_PRESSED            (1 << 1)
#define BTN_NONE_PRESSED        0
#define BTN_BOTH_PRESSED        (BTN0_PRESSED | BTN1_PRESSED)
void sl_button_on_change(const sl_button_t *handle)
{
	BaseType_t xHigherPriorityTaskWoken;
  	if (&sl_button_btn0 == handle) {
    	if (sl_button_get_state(handle) == SL_SIMPLE_BUTTON_PRESSED) {
	     	xEventGroupSetBitsFromISR(xbtn_events, BTN0_PRESSED, &xHigherPriorityTaskWoken);
	    }
		else {
      		xEventGroupClearBitsFromISR(xbtn_events, BTN0_PRESSED);
      	}
	}
	if (&sl_button_btn1 == handle) {
    	if (sl_button_get_state(handle) == SL_SIMPLE_BUTTON_PRESSED) {
	     	xEventGroupSetBitsFromISR(xbtn_events, BTN1_PRESSED, &xHigherPriorityTaskWoken);
	    }
		else {
      		xEventGroupClearBitsFromISR(xbtn_events, BTN1_PRESSED);
      	}
	}
}

定时器回调

该回调函数被捆绑在2s不自动重载定时器上,由于定时器是在两按键同时按下并持续2s后才结束,因此在回调内,需清除两个按键按下事件,最后发送给蓝牙栈外部事件信号。

static void btn_press_timer_cb(app_timer_t *timer, void *data)
{
  	(void)data;
  	(void)timer;
  	BaseType_t xResult;
  	xResult = xEventGroupClearBitsFromISR(xbtn_events, BTN_BOTH_PRESSED);
  	if (xResult == pdFAIL) {
    	app_log_error("Clear BTN_BOTH_PRESSED event failed\r\n");
  	}
  	km_status = KM_SEND_STRING;
  	sl_led_toggle(&sl_led_led0);
  	sl_led_toggle(&sl_led_led1);
  	sl_bt_external_signal(1);
}

按键响应任务

主体为一循环。在循环内,通过 xEventGroupGetBits 读取按键事件,并做出不同响应。该事件在应用初始化时创建。用一bool型变量 is_running 记录定时器是否在运行,从而避免在两按键一直按下时反复重启定时器。由于可能出现先两按键按下,再释放一个或两个按键的情况,因此在其他情况下,都关闭定时器。

static void km_btn_task(void *p_arg)
{
	app_timer_t btn_press_timer;
	bool is_running = false;
	EventBits_t btn_events;
	
	while (1) {
    	btn_events = xEventGroupGetBits(xbtn_events);
    	switch (btn_events) {
      		case (BTN_BOTH_PRESSED):
      			if (!is_running) {
				    app_timer_start(&btn_press_timer, 2000, btn_press_timer_cb, NULL, false);
		          	is_running = true;
		        }
      		case (BTN0_PRESSED):
      			app_timer_stop(&btn_press_timer);
      			km_status = KM_SCROLL_UP; // scroll up
        		sl_bt_external_signal(1);
        		break;
			case (BTN1_PRESSED):
		        app_timer_stop(&btn_press_timer);
		        km_status = KM_SCROLL_DOWN; // scroll down
		        sl_bt_external_signal(1);
		        break;
		    default:
		    	app_timer_stop(&btn_press_timer);
		    	is_running = false;
        		break;
		}
		vTaskDelay(pdMS_TO_TICKS(50));
	}
	vTaskDelete(NULL);
}

蓝牙事件回调

参考SiliconLabs蓝牙应用示例: bluetooth_hid_keyboard,修改蓝牙事件回调中当 MSG_ID 为 sl_bt_evt_system_external_signal_id 时的部分代码:根据 km_status 状态分别实现上/下翻页、发送字符,且这几个功能分别用函数封装。最后,置 km_status = KM_IDLE

...
case  sl_bt_evt_system_external_signal_id:
	if (notification_enabled == 1 && km_status != KM_IDLE) {
        if (km_status == KM_SEND_STRING) {
        	send_eetree_string();
        }
        else if (km_status == KM_SCROLL_UP) {
        	scroll_with_distance(0x01);
        }
        else { // KM_SCROLL_DOWN
        	scroll_with_distance(0xFF);
        }
        app_log_info("Key report %d was sent\r\n", km_status);
        km_status = KM_IDLE;
      }
      break;
...

BLE HID

HID(Human Interface Device)人体学接口设备,是生活中常见的输入设备,比如键盘、鼠标等。早期的HID是设备大部分都是通过USB接口来实现,蓝牙技术出现后,通过蓝牙作为传输层,实现了无线HID设备。通过低功耗蓝牙实现的HID功能一般简称为HOGP(HID over Gatt Profile)。BLE HID 规范以 USB HID 规范为基础,因此具体含义仍需参照USB HID文档。

👉 参考:【BLE】HID设备的实现(蓝牙自拍杆、蓝牙键盘、蓝牙鼠标、HID复合设备)

Report Map及报文

键盘设备

👉 参考:DIY蓝牙键盘(1) - 理解键盘报文

Report Map用十六进制数据,描述HID设备的基本信息,例如,按键数量,数据的最大最小值,功能等。为了实现鼠标+键盘复合设备,参考SiliconLabs蓝牙应用示例: bluetooth_hid_keyboard所给出的一个键盘设备的报告映射,并加入Report ID条目:

项目
0x05, 0x01Usage Page (Generic Desktop)
0x09, 0x06Usage (Keyboard)
0xa1, 0x01Collection (Application)
0x85, 0x01Report Id (1)
0x75, 0x01Report Size (1)
0x95, 0x08Report Count (8)
0x05, 0x07Usage Page (Keyboard)
0x19, 0xe0Usage Minimum (Keyboard LeftControl)
0x29, 0xe7Usage Maximum (Keyboard Right GUI)
0x15, 0x00Logical Minimum (0)
0x25, 0x01Logical Maximum (1)
0x75, 0x01Report Size (1)
0x95, 0x08Report Count (8)
0x81, 0x02Input (Data, Variable, Absolute) Modifier byte
0x95, 0x01Report Count (1)
0x75, 0x08Report Size (8)
0x81, 0x01Input (Constant) Reserved byte
0x95, 0x06Report Count (6)
0x75, 0x08Report Size (8)
0x15, 0x00Logical Minimum (0)
0x25, 0x65Logical Maximum (101)
0x05, 0x07Usage Page (Key Codes)
0x05, 0x01Usage Minimum (Reserved (no event indicated))
0x05, 0x01Usage Maximum (Keyboard Application)
0x05, 0x01Input (Data,Array) Key arrays (6 bytes)
0xc0End Collection

这样描述的键盘设备具有通用键盘的基本功能,将按键与释放键信息通过输入报告发送到主机。同时,使用常见的键盘报文结构,其中包含保留字节、修饰符字节与6个键码字节(可以描述最多6个按键同时按下)。键盘报文格式如下所列:

Byte 0Byte 1Byte 2Byte 3Byte 4Byte 5Byte 6Byte 7
Modifier byteReserved byteKey code 1Key code 2Key code 3Key code 4Key code 5Key code 6

其中,第一个字节从LSB开始依次表示:

Bit 0Bit 1Bit 2Bit 3Bit 4Bit 5Bit 6Bit 7
L CtrlL ShiftL AltL GUIR CtrlR ShiftR AltR GUI

第二个字节保留(默认为0)。后面6个字节的每个字节都可以表示一个按键的状态,可以同时有多个按键按下。在手册《HID Usage Tables For Universal Serial Bus (USB)》中,规定了键码与按键的对应关系,例如:

Usage IDUsage Name
0x04Keyboard a & A
0x05Keyboard b & B
0x1DKeyboard z & Z
0x37Keyboard . & >

例如,下述两个报文分别表示a与A(同时按下左Shift + a):

Byte 0Byte 1Byte 2Byte 3Byte 4Byte 5Byte 6Byte 7含义
0x000x000x040x000x000x000x000x00a
Byte 0Byte 1Byte 2Byte 3Byte 4Byte 5Byte 6Byte 7含义
0x040x000x040x000x000x000x000x00A

此外,在发送按下按键的信息后,还需发送释放按键的报文,否则键盘将一直按住。

Byte 1Byte 2Byte 3Byte 4Byte 5Byte 6Byte 7Byte 8含义
0x000x000x000x000x000x000x000x00释放
鼠标设备

鼠标设备的报告映射如下所列:

项目
0x05, 0x01Usage Page (Generic Desktop)
0x09, 0x02Usage (Mouse)
0xa1, 0x01Collection (Application)
0x85, 0x02Report Id (2)
0x75, 0x01Report Size (1)
0x95, 0x08Report Count (8)
0x09, 0x01Usage (Pointer)
0xa1, 0x00Collection (Physical)
0x05, 0x09Usage Page (Buttons)
0x19, 0x01Logical Minimum (1)
0x29, 0x03Logical Maximum (3)
0x15, 0x00Logical Minimum (0)
0x25, 0x01Logical Maximum (1)
0x95, 0x03Report Count (3)
0x75, 0x01Report Count (1)
0x81, 0x02Input(Data, Variable, Absolute); 3 button bits
0x95, 0x01Report Count (1)
0x75, 0x05Report Size (5)
0x81, 0x03Input(Constant); 5 bits padding
0x05, 0x01Usage Page (Generic Desktop)
0x09, 0x30Usage (X)
0x09, 0x31Usage (Y)
0x09, 0x38Usage (Wheel)
0x15, 0x81Logical Minimum (-127)
0x25, 0x7FLogical Maximum (127)
0x75, 0x08Report Size (8)
0x95, 0x03Report Count (3)
0x81, 0x06Input(Data, Variable, Relative); 3 position bytes (X,Y,Wheel)
0xc0End Collection
0xc0End Collection

对于鼠标,上报的数据我们定义了4个字节。其中Byte 0 的bit 0~2分别表示鼠标左键、右键与中键,后4位由设备定义(默认为0)。Byte 1 表示鼠标指针X轴移动,Byte 2 表示鼠标指针Y轴移动(有符号数,具体数值与移动距离的关系可实际测试),Byte 3 表示滚轮移动。鼠标的报文格式如下所列:

Byte 0Byte 1Byte 2Byte 3
bit 0~2 左、右、中键指针X方向移动指针Y方向移动滚轮移动
复合设备

对于两个或以上的HID复合设备来说,需要额外用Report ID描述,在此键盘Report ID为1,鼠标为2。同时,设备的报文前需额外一个字节表示Report ID。将上述两个设备的报告映射写在一起,即可描述键盘+鼠标的复合设备。如图所示,将这个长字节配置至 Bluetooth GATT Configurator 内。

配置Report Map

发送字符串

通过键盘设备发送字符串“EETREE.CN”,各字符码表为:0x08(e)、0x17(t)、0x15®、0x37(.)、0x06©、0x11(n)。要实现大写,还需要修饰键按下左Shift。例如,发送“E”,并结合键盘的Report ID(0x01):

Byte 0Byte 1Byte 2Byte 3Byte 4Byte 5Byte 6Byte 7Byte 8含义
0x010x040x000x080x000x000x000x000x00E
Byte 0Byte 1Byte 2Byte 3Byte 4Byte 5Byte 6Byte 7Byte 8含义
0x010x000x000x000x000x000x000x000x00释放

发送一个字符后,再发送一次全0报文,表示按键释放。两各按键前后最好间隔几十毫秒。由于所发送字符串“EETREE.CN”有连续的字符,因此不方便在一次报文中发送(如此两个“EE”将仅表达一次“E”按下),且“.”无需修饰符,因此索性每个字符都单次发送。

#define REPORT_ID_INDEX         0
#define KB_REPORT_ID            0x01
#define MODIFIER_INDEX          1
#define DATA_INDEX              3
#define LSHIFT_KEY_OFF        	0x00
#define LSHIFT_KEY_ON         	0x02
static uint8_t kb_report_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };

void send_keyboard(uint8_t caps_key, uint8_t c)
{
  sl_status_t sc;
  memset(kb_report_data, 0, sizeof(kb_report_data));
  kb_report_data[REPORT_ID_INDEX] = KB_REPORT_ID;
  kb_report_data[MODIFIER_INDEX] = caps_key;
  kb_report_data[DATA_INDEX] = c;
  sc = sl_bt_gatt_server_notify_all(gattdb_report,
                                    sizeof(kb_report_data),
                                    kb_report_data);
  app_assert_status(sc);
  memset(kb_report_data, 0, sizeof(kb_report_data));
  kb_report_data[REPORT_ID_INDEX] = KB_REPORT_ID;
  sc = sl_bt_gatt_server_notify_all(gattdb_report,
                                    sizeof(kb_report_data),
                                    kb_report_data);
  app_assert_status(sc);
  sl_sleeptimer_delay_millisecond(20);
}

void send_eetree_string()
{
  send_keyboard(LSHIFT_KEY_ON, 0x08); // E
  send_keyboard(LSHIFT_KEY_ON, 0x08); // E
  send_keyboard(LSHIFT_KEY_ON, 0x17); // T
  send_keyboard(LSHIFT_KEY_ON, 0x15); // R
  send_keyboard(LSHIFT_KEY_ON, 0x08); // E
  send_keyboard(LSHIFT_KEY_ON, 0x08); // E
  send_keyboard(LSHIFT_KEY_OFF,0x37); // .
  send_keyboard(LSHIFT_KEY_ON, 0x06); // C
  send_keyboard(LSHIFT_KEY_ON, 0x11); // N
}

上/下滚动

通过鼠标设备实现上下滚动,并结合鼠标的Report ID(0x02):

Byte 0Byte 1Byte 2Byte 3Byte 4含义
0x020x000x000x000x01上滚
Byte 0Byte 1Byte 2Byte 3Byte 4含义
0x020x000x000x000xFF下滚
#define MOUSE_REPORT_ID         0x02
#define WHEEL_INDEX             4
static uint8_t mouse_report_data[] = { 0, 0, 0, 0, 0 };

void scroll_with_distance(uint8_t distance)
{
  sl_status_t sc;
  memset(mouse_report_data, 0, sizeof(mouse_report_data));
  mouse_report_data[REPORT_ID_INDEX] = MOUSE_REPORT_ID;
  mouse_report_data[WHEEL_INDEX] = distance;
  sc = sl_bt_gatt_server_notify_all(gattdb_report,
                                    sizeof(mouse_report_data),
                                    mouse_report_data);
  app_assert_status(sc);
}

功能展示

开发板连接PC并配对蓝牙后,可以看到XG24 KeyMouse设备已连接,且电量为100%。功能演示参见视频。
板卡实物图
蓝牙配对效果
👉 详细展示参见:B站:基于XG24-EK2703A的BLE HID蓝牙键盘+鼠标复合设备功能开发

项目总结

本次项目通过BLE HID协议,实现了键盘+鼠标复合设备,使用两个按键实现上/下翻页、发送字符串的功能。Silicon Labs的IDE总体感觉还不错,直接在IDE内把GSDK、编译工具链都给安装好。对于配置开发板的外设、IO口、驱动、蓝牙GATT配置等有图形化界面,上手较为容易。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1404245.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Django后台列表显示图片

在列表中显示ImageField的图片预览 编辑应用的models.py&#xff0c;添加下面代码&#xff1a; class Product(models.Model):# ...image models.ImageField(upload_toproducts/%Y/%m/%d, blankTrue)def image_data(self):if self.image:return format_html(<img src"…

2017年认证杯SPSSPRO杯数学建模B题(第二阶段)岁月的印记全过程文档及程序

2017年认证杯SPSSPRO杯数学建模 B题 岁月的印记 原题再现&#xff1a; 对同一个人来说&#xff0c;如果没有过改变面容的疾病、面部外伤或外科手术等经历&#xff0c;年轻和年老时的面容总有很大的相似性。人们在生活中也往往能够分辨出来两张不同年龄段的照片是不是同一个人…

Elasticsearch:介绍 kNN query,这是进行 kNN 搜索的专家方法

作者&#xff1a;来自 Elastic Mayya Sharipova, Benjamin Trent 当前状况&#xff1a;kNN 搜索作为顶层部分 Elasticsearch 中的 kNN 搜索被组织为搜索请求的顶层&#xff08;top level&#xff09;部分。 我们这样设计是为了&#xff1a; 无论分片数量多少&#xff0c;它总…

【人工智能大脑】仿生学与人工智能交汇:基于MP神经网络的精准农业实践

MP神经网络&#xff0c;即McCulloch-Pitts模型&#xff08;MCP Model&#xff09;&#xff0c;是神经网络的早期形式之一&#xff0c;由Warren McCulloch和Walter Pitts在1943年提出。这个模型为现代人工神经网络的发展奠定了理论基础&#xff0c;并首次尝试模拟了生物神经元的…

Kotlin程序设计 扩展篇(一)

Kotlin程序设计&#xff08;扩展一&#xff09; **注意&#xff1a;**开启本视频学习前&#xff0c;需要先完成以下内容的学习&#xff1a; 请先完成《Kotlin程序设计》视频教程。请先完成《JavaSE》视频教程。 Kotlin在设计时考虑到了与Java的互操作性&#xff0c;现有的Ja…

RK3568 移植Ubuntu

使用ubuntu-base构建根文件系统 1、到ubuntu官网获取 ubuntu-base-18.04.5-base-arm64.tar.gz Ubuntu Base 18.04.5 LTS (Bionic Beaver) 2、将获取的文件拷贝到ubuntu虚拟机,新建目录,并解压 mkdir ubuntu_rootfs sudo tar -xpf u

Ubuntu之离线安装Gitlab,搭建私有代码仓库

Ubuntu之离线安装Gitlab,搭建私有代码仓库 文章目录 Ubuntu之离线安装Gitlab,搭建私有代码仓库1. 官网下载&#xff1a;2. 安装Gitlab3. 使用 1. 官网下载&#xff1a; https://packages.gitlab.com/gitlab/gitlab-ce wget下载地址&#xff1a; wget https://packages.gitla…

Linux命令_vim的详细用法

简介 vim是一款针对Linux和其他类Unix操作系统的文本编辑器。它是Vi编辑器的升级版本&#xff0c;具有丰富的功能和强大的扩展性。vim有三种基本模式&#xff1a;命令模式、插入模式和可视模式。 命令模式&#xff1a;用户可以使用各种命令移动光标和进行编辑操作&#xff0c;如…

安裝火狐和穀歌流覽器插件FoxyProxy管理海外動態IP代理

代理生態系統擁有大量有用的實用程式&#xff0c;使海外代理IP代理設置的使用變得簡單起來。其中一種類型叫做代理管理工具&#xff0c;像FoxyProxy就是該工具集比較受歡迎的。 本文將全面解析FoxyProxy擴展的功能和特性、Foxyproxy怎麼下載、以及如何在穀歌流覽器和火狐流覽器…

数据分析的理念、流程、方法、工具(上)

一、数据的价值 1、数据驱动企业运营 从电商平台的「猜你喜欢」到音乐平台的「心动模式」&#xff0c;大数据已经渗透到了我们生活的每一个场景。不论是互联网行业&#xff0c;还是零售业、制造业等&#xff0c;各行各业都在依托互联网大数据&#xff08;数据采集、数据存储、…

AutoDL——终端训练神经网络模型(忽略本地问题)

前言&#xff1a; 本人之前分享过一篇文章&#xff1a;使用pycharm连接远程GPU训练神经网络模型&#xff08;超详细&#xff01;&#xff09;&#xff0c;其中详细介绍了如何利用pycharm连接AutoDL算力云平台租用的GPU服务器训练网络模型。但有些小伙伴可能会因为一些原因而导…

清越 peropure·AI 国内版ChatGP新功能介绍

当OpenAI发布ChatGPT的时候,没有人会意识到,新一代人工智能浪潮将给人类社会带来一场眩晕式变革。其中以ChatGPT为代表的AIGC技术加速成为AI领域的热门发展方向,推动着AI时代的前行发展。面对技术浪潮,清越科技(PeroPure)立足多样化生活场景、精准把握用户实际需求,持续精确Fin…

【爬虫、数据可视化实战】以“人口”话题为例爬取实时微博数据并进行舆情分析

前言&#xff1a; 近期在weibo上讨论的比较热的话题无非就是“人口”了。TaoTao也看了一些大家发的内容。但是感觉单纯的看文字内容不能很直观的反应出来大家的关切。索性就使用爬虫对数据进行爬取&#xff0c;同时结合着数据可视化的方式让数据自己开口说话。那么接下来就让我…

浮点数详解

目录 1.概述 2.浮点数的编码方式 2.1.float类型的IEEE编码 2.2.double类型的IEEE编码 2.3.现场问题 2.4.总结 1.概述 计算机也需要运算和存储数学中的实数。在计算机的发展过程中&#xff0c;曾产生过多种存储实数的方式&#xff0c;有的现在已经很少使用了。不管如何存储…

OpenCV书签 #差值哈希算法的原理与相似图片搜索实验

1. 介绍 差值哈希算法&#xff08;Difference Hash Algorithm&#xff0c;简称dHash&#xff09; 是哈希算法的一种&#xff0c;主要可以用来做以图搜索/相似图片的搜索工作。 2. 原理 差值哈希算法通过计算相邻像素的差异来生成哈希&#xff0c;即通过缩小图像的每个像素与平…

macbookpro怎么恢复出厂设置2024最新恢复方法汇总

可能你的MacBook曾经是高性能的代表&#xff0c;但是现在它正慢慢地逝去了自己的光芒&#xff1f;随着逐年的使用以及文件的添加和程序的安装&#xff0c;你的MacBook可能会开始变得迟缓卡顿&#xff0c;或者失却了以往的光彩。如果你发现你的Mac开始出现这些严重问题&#xff…

c#中使用UTF-8编码处理多语言文本的有效策略

使用UTF-8编码处理多语言文本的有效策略 在当今的全球化时代&#xff0c;软件开发者常常需要处理包含多种语言的文本。这不仅涉及英文和其他西方语言&#xff0c;还包括中文、日文、韩文等多字节字符系统。在这篇博客中&#xff0c;我将探讨如何有效地使用UTF-8编码来处理混合语…

基于SpringBoot Vue二手闲置物品交易系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

unity shaderGraph实例-武器特效(纹理遮罩,纹理动画,纹理变形)

文章目录 效果展示所需素材整体结构各区域内容区域1区域2区域3区域4区域4-1区域4-2区域4-3区域4-4 区域5区域6 后处理工程下载 效果展示 所需素材 除了剑的模型外&#xff0c;主要是这五张贴图&#xff0c;其中swordmask和swordmask1中白色的区域是剑身的位置&#xff0c;sword…

Visual Studio2022实用使用技巧集

前言 对于.NET开发者而言Visual Studio是我们日常工作中比较常用的开发工具&#xff0c;掌握一些Visual Studio实用的搜索、查找、替换技巧可以帮助我们大大提高工作效率从而避免996。 Visual Studio更多实用技巧 https://github.com/YSGStudyHards/DotNetGuide 代码和功能搜…