当前位置: 首页 > article >正文

RT-Thread+STM32L475VET6——USB鼠标模拟


文章目录

  • 前言
  • 一、板载资源
  • 二、具体步骤
    • 1.配置icm20608传感器
    • 2.打开CubeMX进行USB配置
    • 3. 配置USB
      • 3.1 打开USB驱动
      • 3.2 声明USB
      • 3.3 剪切stm32xxxx_hal_msp.c中的void HAL_PCD_MspInit(PCD_HandleTypeDef* hpcd)和void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd)函数至board.c
      • 3.4 使能USB
    • 4. 编译,烧录


前言

本文采用开发板为STM32L475VET6(潘多拉开发板),使用RT_Thread Studio基于芯片开发模式,系统版本为4.0.3,完成模拟鼠标实验,实现鼠标功能,左键为KEY0,右键为KEY2


一、板载资源

icm20608传感器采用I2C协议,本文采用软件模拟I2C
查阅数据手册:开发板使用的是 PC0 模拟时钟线SCL、PC1 模拟数据线 SDA,
示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

二、具体步骤

1.配置icm20608传感器

RT-Thread+STM32L475VET6——icm20608传感器

2.打开CubeMX进行USB配置

在这里插入图片描述
生成工程

3. 配置USB

按照官方步骤配置
在这里插入图片描述

3.1 打开USB驱动

在这里插入图片描述

3.2 声明USB

在这里插入图片描述

3.3 剪切stm32xxxx_hal_msp.c中的void HAL_PCD_MspInit(PCD_HandleTypeDef* hpcd)和void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd)函数至board.c

在这里插入图片描述

3.4 使能USB

一般默认开启
在这里插入图片描述

4. 编译,烧录

示例代码

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>#include "icm20608.h"
#include <math.h>#define DBG_SECTION_NAME "3D_mouse"
#define DBG_LEVEL DBG_LOG
#include <rtdbg.h>#define PIN_KEY0 GET_PIN(D,10)
#define PIN_KEY2 GET_PIN(D,8)static rt_sem_t mouse_sem = RT_NULL;static struct rt_thread usb_thread;
ALIGN(RT_ALIGN_SIZE)
static char usb_thread_stack[0x1000];static struct rt_thread icm_thread;
ALIGN(RT_ALIGN_SIZE)
static char icm_thread_stack[0x1000];static struct rt_thread key_thread;
ALIGN(RT_ALIGN_SIZE)
static char key_thread_stack[0x1000];/* 变动识别值 */
const static float mouse_rang_scope = 6.0f;
/* 读取角度有效角度 */
const static float mouse_angle_range = 80.0f;
/* 移动值的最大值 */
const static float mouse_move_range = 127.0f;
/* 角度移动比 */
#define mouse_ratio (mouse_move_range / mouse_angle_range)
/* 移动步长 */
const static rt_uint8_t mouse_pixel_len = 5;
/* 鼠标响应时间 */
const static rt_uint32_t mouse_sample_times = 0;static float mouse_cmp_last_x, mouse_cmp_last_y;#define Gyro_Gr 0.0010653f
#define pi 3.141593f
#define Kp 10.0f
#define Ki 0.008f
#define halfT 0.01fstatic float q0 = 1, q1 = 0, q2 = 0, q3 = 0;
static float exInt = 0, eyInt = 0, ezInt = 0;struct icm_position
{icm20608_device_t icm20608_device;rt_mutex_t lock;float x;           // 传感器 x 位置float y;           // 传感器 y 位置float z;           // 传感器 z 位置rt_int8_t buff[4]; // 发送鼠标的值
};
typedef struct icm_position *icm_position_t;icm_position_t icm_device = RT_NULL;static void mouse_meas_check(float *temp)
{if (*temp > mouse_angle_range){*temp = mouse_angle_range;}else if (*temp < -mouse_angle_range){*temp = -mouse_angle_range;}
}#ifdef __GNUC__const float __atan2f_lut[4] = {-0.0443265554792128, //p7-0.3258083974640975, //p3+0.1555786518463281, //p5+0.9997878412794807  //p1
};
const float __atan2f_pi_2 = 1.5707963;/* 求平方根 */
static float _sqrt(float x)
{float xhalf = 0.5f * x;int i = *(int *)&x;i = 0x5f375a86 - (i >> 1);x = *(float *)&i;x = x * (1.5f - xhalf * x * x);return 1.0 / x;
}/* 求绝对值 */
static float _fabs(float x)
{return (x >= 0 ? x : (-x));
}/* 求x / y的反正切值 */
static float _atan2f(float y, float x)
{float a, b, c, r, xx;int m;union {float f;int i;} xinv;xx = _fabs(x);xinv.f = xx;m = 0x3F800000 - (xinv.i & 0x7F800000);xinv.i = xinv.i + m;xinv.f = 1.41176471f - 0.47058824f * xinv.f;xinv.i = xinv.i + m;b = 2.0 - xinv.f * xx;xinv.f = xinv.f * b;b = 2.0 - xinv.f * xx;xinv.f = xinv.f * b;c = _fabs(y * xinv.f);xinv.f = c;m = 0x3F800000 - (xinv.i & 0x7F800000);xinv.i = xinv.i + m;xinv.f = 1.41176471f - 0.47058824f * xinv.f;xinv.i = xinv.i + m;b = 2.0 - xinv.f * c;xinv.f = xinv.f * b;b = 2.0 - xinv.f * c;xinv.f = xinv.f * b;xinv.f = xinv.f + c;a = (c > 1.0f);c = c - a * xinv.f;r = a * __atan2f_pi_2;xx = c * c;a = (__atan2f_lut[0] * c) * xx + (__atan2f_lut[2] * c);b = (__atan2f_lut[1] * c) * xx + (__atan2f_lut[3] * c);xx = xx * xx;r = r + a * xx;r = r + b;b = M_PI;b = b - 2.0f * r;r = r + (x < 0.0f) * b;b = (_fabs(x) < 0.000001f);c = !b;r = c * r;r = r + __atan2f_pi_2 * b;b = r + r;r = r - (y < 0.0f) * b;return r;
}static double _asin(double x)
{return _atan2f(x, _sqrt(1.0 - x * x));
}
#endif /* __GNUC__ *//* 获取俯仰角、偏航角、翻滚角 */
static void get_angle(icm_position_t dev, float ax, float ay, float az, float gx, float gy, float gz)
{float pitch = 0, roll = 0, yaw = 0;float norm;float vx, vy, vz;float ex, ey, ez;float q0q0 = q0 * q0;float q0q1 = q0 * q1;float q0q2 = q0 * q2;float q1q1 = q1 * q1;float q1q3 = q1 * q3;float q2q2 = q2 * q2;float q2q3 = q2 * q3;float q3q3 = q3 * q3;gx *= Gyro_Gr;gy *= Gyro_Gr;gz *= Gyro_Gr;if (az == 0)return;#ifdef __GNUC__norm = _sqrt(ax * ax + ay * ay + az * az);
#elsenorm = sqrt(ax * ax + ay * ay + az * az);
#endif /* __GNUC__ */ax = ax / norm;ay = ay / norm;az = az / norm;vx = 2 * (q1q3 - q0q2);vy = 2 * (q0q1 + q2q3);vz = q0q0 - q1q1 - q2q2 + q3q3;ex = (ay * vz - az * vy);ey = (az * vx - ax * vz);ez = (ax * vy - ay * vx);exInt = exInt + ex * Ki;eyInt = eyInt + ey * Ki;ezInt = ezInt + ez * Ki;gx = gx + Kp * ex + exInt;gy = gy + Kp * ey + eyInt;gz = gz + Kp * ez + ezInt;q0 = q0 + (-q1 * gx - q2 * gy - q3 * gz) * halfT;q1 = q1 + (q0 * gx + q2 * gz - q3 * gy) * halfT;q2 = q2 + (q0 * gy - q1 * gz + q3 * gx) * halfT;q3 = q3 + (q0 * gz + q1 * gy - q2 * gx) * halfT;#ifdef __GNUC__norm = _sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
#elsenorm = sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
#endif /* __GNUC__ */q0 = q0 / norm;q1 = q1 / norm;q2 = q2 / norm;q3 = q3 / norm;#ifdef __GNUC__pitch = -_asin(2 * (q0 * q2 - q1 * q3)) * 57.2957795f;roll = _asin(2 * (q0 * q1 + q2 * q3)) * 57.2957795f;yaw = -_atan2f(2 * (q1 * q2 + q0 * q3), (q0q0 + q1q1 - q2q2 - q3q3)) * 57.29578f;
#elsepitch = -asin(2 * (q0 * q2 - q1 * q3)) * 57.2957795f;roll = asin(2 * (q0 * q1 + q2 * q3)) * 57.2957795f;yaw = -atan2f(2 * (q1 * q2 + q0 * q3), (q0q0 + q1q1 - q2q2 - q3q3)) * 57.29578f;
#endif /* __GNUC__ */mouse_meas_check(&pitch);dev->x = pitch * mouse_ratio;mouse_meas_check(&roll);dev->y = roll * mouse_ratio;mouse_meas_check(&yaw);dev->z = yaw * mouse_ratio;
}static void mouse_get_pos(icm_position_t dev)
{rt_err_t result;rt_int16_t accel_x, accel_y, accel_z;rt_int16_t gyros_x, gyros_y, gyros_z;RT_ASSERT(dev);result = rt_mutex_take(dev->lock, RT_WAITING_FOREVER);if (result != RT_EOK){goto __exit;}result = icm20608_get_accel(dev->icm20608_device, &accel_x, &accel_y, &accel_z);if (result != RT_EOK){rt_mutex_release(dev->lock);goto __exit;}result = icm20608_get_gyro(dev->icm20608_device, &gyros_x, &gyros_y, &gyros_z);if (result != RT_EOK){rt_mutex_release(dev->lock);goto __exit;}get_angle(dev, (float)accel_x, (float)accel_y, (float)accel_z, (float)gyros_x, (float)gyros_y, (float)gyros_z);rt_mutex_release(dev->lock);__exit:if (result != RT_EOK){LOG_E("The sensor does not work");return;}
}static icm_position_t mouse_init_icm(void)
{rt_err_t result;rt_thread_mdelay(1000);icm_device = rt_calloc(1, sizeof(struct icm_position));if (icm_device == RT_NULL){LOG_E("Can't allocate memory for three-dimensional mouse ");return RT_NULL;}/* 初始化传感器 icm20608 */icm_device->icm20608_device = icm20608_init("i2c3");if (icm_device->icm20608_device == RT_NULL){LOG_E("The sensor initializes failure");rt_free(icm_device);return RT_NULL;}else{LOG_D("The 3D mouse initializes success");}icm_device->lock = rt_mutex_create("mutex_mouse", RT_IPC_FLAG_FIFO);if (icm_device->lock == RT_NULL){LOG_E("Can't create mutex for three-dimensional mouse");rt_free(icm_device);return RT_NULL;}mouse_sem = rt_sem_create("mouse_sem", 0, RT_IPC_FLAG_FIFO);if (mouse_sem == RT_NULL){LOG_E("Can't create sem for mouse device");rt_mutex_delete(icm_device->lock);rt_free(icm_device);return 0;}/* 传感器零值校准 */result = icm20608_calib_level(icm_device->icm20608_device, 10);if (result != RT_EOK){LOG_E("The sensor calibrates failure");rt_mutex_delete(icm_device->lock);rt_sem_delete(mouse_sem);rt_free(icm_device);return RT_NULL;}return icm_device;
}static void mouse_go_release_status(void)
{/* 初始状态值 */rt_int8_t buff[4] = {0x08, 0, 0, 0};icm_device->buff[0] = buff[0];icm_device->buff[1] = buff[1];icm_device->buff[2] = buff[2];icm_device->buff[3] = buff[3];
}static void mouse_send_data(rt_device_t device)
{RT_ASSERT(device != RT_NULL);rt_device_write(device, HID_REPORT_ID_MOUSE, icm_device->buff, 4);mouse_go_release_status();
}/* 负值表示向左移动,正值表示向右移动 */
static void mouse_move_x(rt_device_t device, float ratio_x)
{RT_ASSERT(device != RT_NULL);if (icm_device->x < 0){icm_device->buff[1] = (rt_int8_t)(-mouse_pixel_len * ratio_x);}else{icm_device->buff[1] = (rt_int8_t)(mouse_pixel_len * ratio_x);}mouse_send_data(device);
}/* 正值表示向下移动,负值表示向上移动 */
static void mouse_move_y(rt_device_t device, float ratio_y)
{RT_ASSERT(device != RT_NULL);if (icm_device->y < 0){icm_device->buff[2] = (rt_int8_t)(-mouse_pixel_len * ratio_y);}else{icm_device->buff[2] = (rt_int8_t)(mouse_pixel_len * ratio_y);}mouse_send_data(device);
}static void mouse_move_xy(rt_device_t device, float ratio_x, float ratio_y)
{RT_ASSERT(device != RT_NULL);if (icm_device->x < 0){icm_device->buff[1] = (rt_int8_t)(-mouse_pixel_len * ratio_x);}else{icm_device->buff[1] = (rt_int8_t)(mouse_pixel_len * ratio_x);}if (icm_device->y < 0){icm_device->buff[2] = (rt_int8_t)(-mouse_pixel_len * ratio_y);}else{icm_device->buff[2] = (rt_int8_t)(mouse_pixel_len * ratio_y);}mouse_send_data(device);
}static void usb_thread_entry(void *parameter)
{rt_device_t device = (rt_device_t)parameter;rt_uint8_t i = 0;while (1){if (rt_sem_take(mouse_sem, RT_WAITING_FOREVER) == RT_EOK){rt_uint8_t temp_x = 0, temp_y = 0, move_max = 0;float move_distance = 0.0f;rt_mutex_take(icm_device->lock, RT_WAITING_FOREVER);#ifdef __GNUC__temp_x = (rt_uint8_t)_fabs(icm_device->x);temp_y = (rt_uint8_t)_fabs(icm_device->y);move_distance = _sqrt(temp_x * temp_x + temp_y * temp_y);
#elsetemp_x = (rt_uint8_t)fabs(icm_device->x);temp_y = (rt_uint8_t)fabs(icm_device->y);move_distance = sqrt(temp_x * temp_x + temp_y * temp_y);
#endifmove_max = temp_x > temp_y ? temp_x : temp_y;/* 根据倾斜程度获取移动值 */for (i = 0; i < move_max / mouse_pixel_len; i++){LOG_D("move_max :%4d, x: %4d, y :%4d ", move_max, temp_x, temp_y);if (i < temp_x && i < temp_y){mouse_move_xy(device, temp_x / move_distance, temp_y / move_distance);}else if (i < temp_x && i >= temp_y){mouse_move_x(device, temp_x / move_distance);}else if (i >= temp_x && i < temp_y){mouse_move_y(device, temp_y / move_distance);}else{break;}}rt_mutex_release(icm_device->lock);}rt_thread_mdelay(mouse_sample_times);}
}static void icm_thread_entry(void *parameter)
{while (1){float temp_x = 0.0, temp_y = 0.0;rt_mutex_take(icm_device->lock, RT_WAITING_FOREVER);/* 获取鼠标移动范围 */mouse_get_pos(icm_device);/* 获取差值 */temp_x = icm_device->x - mouse_cmp_last_x;temp_y = icm_device->y - mouse_cmp_last_y;/* 避免抖动 */if (temp_x > mouse_rang_scope || temp_x < -mouse_rang_scope || temp_y > mouse_rang_scope || temp_y < -mouse_rang_scope){/* 存储这次鼠标位移值 */mouse_cmp_last_x = icm_device->x;mouse_cmp_last_y = icm_device->y;rt_sem_release(mouse_sem);}rt_mutex_release(icm_device->lock);rt_thread_mdelay(mouse_sample_times);}
}static void key_thread_entry(void *parameter)
{int mouse_key_2, mouse_key_0;rt_device_t device = (rt_device_t)parameter;rt_err_t result = -RT_ERROR;while (1){if (rt_pin_read(PIN_KEY0) == PIN_LOW){mouse_key_0 = 1;}else if (rt_pin_read(PIN_KEY2) == PIN_LOW){mouse_key_2 = 1;}else{mouse_key_2 = 0;mouse_key_0 = 0;}if (mouse_key_2 | mouse_key_0){result = rt_mutex_take(icm_device->lock, RT_WAITING_FOREVER);if (result == RT_EOK){/* 获取鼠标键值,默认为 0 */icm_device->buff[0] = 0x08 | mouse_key_2 | mouse_key_0 << 1;if (mouse_key_2 & mouse_key_0){LOG_D("left & right down");}else if (mouse_key_2){LOG_D("left down");}else if (mouse_key_0){LOG_D("right down");}mouse_send_data(device);rt_mutex_release(icm_device->lock);rt_thread_mdelay(50);}}rt_thread_mdelay(mouse_sample_times / 5);}
}static void mouse_init_key(void)
{/* 鼠标左键 */rt_pin_mode(PIN_KEY0, PIN_MODE_INPUT);/* 鼠标右键 */rt_pin_mode(PIN_KEY2, PIN_MODE_INPUT);
}int main(void)
{return 0;
}static int application_usb_init(void)
{/* 查找名称为 hidd 的设备 */rt_device_t device = rt_device_find("hidd");/* 初始化六轴传感器设备 */icm_device = mouse_init_icm();/* 初始化按键 */mouse_init_key();RT_ASSERT(device != RT_NULL);RT_ASSERT(icm_device != RT_NULL);/*打开查找到的 hid 设备 */rt_device_open(device, RT_DEVICE_FLAG_WRONLY);/* 初始化 USB 线程*/rt_thread_init(&usb_thread,"hidd",usb_thread_entry, device,usb_thread_stack, sizeof(usb_thread_stack),10, 20);rt_thread_startup(&usb_thread);/* 初始化六轴传感器线程 */rt_thread_init(&icm_thread,"icm20608",icm_thread_entry, RT_NULL,icm_thread_stack, sizeof(icm_thread_stack),10, 20);rt_thread_startup(&icm_thread);/* 初始化按键线程 */rt_thread_init(&key_thread,"key",key_thread_entry, device,key_thread_stack, sizeof(key_thread_stack),10, 20);rt_thread_startup(&key_thread);return 0;
}
INIT_APP_EXPORT(application_usb_init);

烧录完成后,将开发板上的USB OTG 连接PC端的USB接口,即可实现鼠标功能。


相关文章:

RT-Thread+STM32L475VET6——USB鼠标模拟

文章目录 前言一、板载资源二、具体步骤1.配置icm20608传感器2.打开CubeMX进行USB配置3. 配置USB3.1 打开USB驱动3.2 声明USB3.3 剪切stm32xxxx_hal_msp.c中的void HAL_PCD_MspInit(PCD_HandleTypeDef* hpcd)和void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd)函数至board.c3.…...

计算机毕业设计SpringBoot+Vue.js母婴商城(源码+LW文档+PPT+讲解+开题报告)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

Teigha(ODA<Open Design Alliance>_开放设计联盟)——cad c# 二次开发

需将dll库文件与exe文件放同一路径下&#xff0c;运行exe即可执行。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Thread…...

Java 中 HTTP 协议版本使用情况剖析

Java 中 HTTP 协议版本使用情况剖析 一、HTTP/1.1 与 HTTP/2 概述 (一)HTTP/1.1 HTTP/1.1 是广泛应用且成熟的 HTTP 协议版本,它在互联网发展历程中扮演了重要角色。其特点主要包括: 连接方式:默认采用短连接,即每次请求都要建立新的 TCP 连接,请求完成后断开。不过也…...

Zama fhEVM应用:摩根大通旗下 Kinexys 发布概念验证

1. 引言 Zama 全同态加密 (FHE) 技术在摩根大通的 Kinexys&#xff08;以前称为 Onyx&#xff09;中成功进行了概念验证。该概念验证是“EPIC 项目&#xff1a;通过链上企业隐私、身份和可组合性推动代币化金融”的一部分&#xff0c;在 Kinexys 数字资产沙盒&#xff08;以前…...

idea 部署 AJ-Report 启动的注意事项

AJ-Report 入门参考&#xff1a; AJ-Report 初学(入门教程) gitee 下载&#xff1a;https://gitee.com/anji-plus/report/releases 根据上面提供的 gitee 下载链接&#xff0c;点击直接下载 最上面的就是最新版本的&#xff0c;旧版本往下拉就可以找到&#xff0c;有三个下载…...

智能化客户行为轨迹分析:AI视频监控在大型商场的技术方案

项目背景&#xff1a;为了提升顾客体验并支持精准营销&#xff0c;卖场或商场需要通过智能化手段分析客户在商场内的行为路线。 一、具体需求 1、行为路径分析&#xff1a;跟踪顾客在商场内的移动轨迹&#xff0c;了解顾客的购物习惯和偏好。 2、高频活动区域识别&#xff1a…...

解决升级flutter 3.29.0 Gradle8.7后报错 Exception has occurred. MissingPluginException

Flutter 升级后 MissingPluginException 及 Proguard 混淆问题解决方案 问题描述 在将 Flutter 从 3.24.5 升级到 3.29&#xff0c;以及 Gradle 升级到 8.7.0 之后&#xff0c;原生自己写的Flutter 插件在运行时出现以下错误&#xff1a; Exception has occurred. MissingPl…...

安全见闻4

今天学了Windows操作系统和驱动程序的相关知识 Windows注册表 注册表是windows系统中具有层次结构的核心数据库 储存的数据对windows 和Windows上运行的应用程序和服务至关重要。注册表时帮助windows控制硬件、软件、用户环境和windows界面的一套数据文件。 打开注册表编辑器…...

Denoising Diffusion Restoration Models论文解读

论文要点 恢复的线性逆问题可以使用预训练的DDPM完成&#xff1a;1. 将降质矩阵使用SVD&#xff0c;得到分解矩阵&#xff1b;2. 使用分解矩阵将图像投影到降质类型间共享的谱空间&#xff1b;3. 谱空间中执行DDPM。 评价 同Track的方法同样很多&#xff0c;比如后续的DDNM、…...

基于SpringBoot的校园消费点评管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…...

vue 修改el-tree高亮样式

vue 修改el-tree高亮样式 ::v-deep .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content, ::v-deep .el-tree-node > .el-tree-node__content:hover {background-color: #eff8ee !important;color: #009764; }...

【NLP 38、激活函数 ④ GELU激活函数】

别盲目&#xff0c;别着急&#xff0c;慢慢走&#xff0c;没事的 —— 25.2.24 一、定义与数学表达式 GELU&#xff08;Gaussian Error Linear Unit&#xff0c;高斯误差线性单元&#xff09;是一种结合概率分布的非线性激活函数&#xff0c;其核心思想是通过输入值服从标准正…...

QT:paintEvent、QPainter、QPaintDevice

paintEvent 介绍 在 Qt 编程中&#xff0c;paintEvent 是 QWidget 类中的一个非常重要的虚函数&#xff0c;用于处理绘图事件。当一个 QWidget 或其派生类的实例需要进行重绘操作时&#xff0c;Qt 会自动调用该控件的 paintEvent 函数。 触发时机 窗口首次显示&#xff1a;当…...

OpenHarmony-4.基于dayu800 GPIO 实践(2)

基于dayu800 GPIO 进行开发 1.DAYU800开发板硬件接口 LicheePi 4A 板载 2x10pin 插针&#xff0c;其中有 16 个原生 IO&#xff0c;包括 6 个普通 IO&#xff0c;3 对串口&#xff0c;一个 SPI。TH1520 SOC 具有4个GPIO bank&#xff0c;每个bank最大有32个IO&#xff1a;  …...

HTML项目一键打包工具:HTML2EXE 最新版

HTML2EXE 工具可以一键打包生成EXE可执行文件。可以打包任意HTML项目或者是一个网址为单个EXE文件&#xff0c;直接打开即可运行。支持KRPano全景VR项目、WebGL游戏项目、视频播放、,课件打包、网址打包等。 下载地址&#xff1a; 最新版HTML2EXE首次发布下载地址 一、功能特点…...

BGP配置华为——路径优选验证

实验拓扑 实验要求 实现通过修改AS-Path属性来影响路径选择实现通过修改Local_Preference属性来影响路径选择实现通过修改MED属性来影响路径选择实现通过修改preferred-value属性来影响路径选择 实验配置与效果 1.改名与IP配置 2.as300配置OSPF R3已经学到R2和R4的路由 3.…...

深度学习基础--ResNet网络的讲解,ResNet50的复现(pytorch)以及用复现的ResNet50做鸟类图像分类

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 如果说最经典的神经网络&#xff0c;ResNet肯定是一个&#xff0c;这篇文章是本人学习ResNet的学习笔记&#xff0c;并且用pytorch复现了ResNet50&…...

TMDS视频编解码算法

因为使用的是DDR进行传输&#xff0c;即双倍频率采样&#xff0c;故时钟只用是并行数据数据的5倍&#xff0c;而不是10倍。 TMDS算法流程&#xff1a; 视频编码TMDS算法流程实现&#xff1a; timescale 1 ps / 1ps //DVI编码通常用于视频传输&#xff0c;将并行数据转换为适合…...

深度解析SmartGBD助力Android音视频数据接入GB28181平台

在当今数字化时代&#xff0c;视频监控与音视频通信技术在各行各业的应用愈发广泛。GB28181协议作为中国国家标准&#xff0c;为视频监控设备的互联互通提供了规范&#xff0c;但在实际应用中&#xff0c;许多Android终端设备并不具备国标音视频能力&#xff0c;这限制了其在相…...

前端兼容处理接口返回的文件流或json数据

参考文档&#xff1a;JavaScript | MDN 参考链接&#xff1a;Blob格式转json格式&#xff0c;拿到后端返回的json数据_blob转json-CSDN博客 参考链接&#xff1a;https://juejin.cn/post/7117939029567340557 场景&#xff1a;导入上传文件&#xff0c;导入成功&#xff0c;…...

Eclipse 透视图 (Perspective)

Eclipse 透视图 (Perspective) Eclipse 是一款强大的集成开发环境(IDE),广泛应用于 Java 开发领域。其中,透视图(Perspective)是 Eclipse 中的一个核心概念,它将不同的工具和视图组合在一起,以便开发者能够更高效地完成特定的开发任务。本文将详细介绍 Eclipse 透视图…...

嵌入式硬件篇---滤波器

文章目录 前言一、模拟电子技术中的滤波器1. 基本概念功能实现方式 2. 分类按频率响应低通滤波器高通滤波器带通滤波器带阻滤波器 按实现方式无源滤波器有源滤波器 3. 设计方法巴特沃斯滤波器&#xff08;Butterworth&#xff09;切比雪夫滤波器&#xff08;Chebyshev&#xff…...

从零到一学习c++(基础篇--筑基期十一-类)

从零到一学习C&#xff08;基础篇&#xff09; 作者&#xff1a;羡鱼肘子 温馨提示1&#xff1a;本篇是记录我的学习经历&#xff0c;会有不少片面的认知&#xff0c;万分期待您的指正。 温馨提示2&#xff1a;本篇会尽量用更加通俗的语言介绍c的基础&#xff0c;用通俗的语言去…...

Java基础常见的面试题(易错!!)

面试题一&#xff1a;为什么 Java 不支持多继承 Java 不支持多继承主要是为避免 “菱形继承问题”&#xff08;又称 “钻石问题”&#xff09;&#xff0c;即一个子类从多个父类继承到同名方法或属性时&#xff0c;编译器无法确定该调用哪个父类的成员。同时&#xff0c;多继承…...

DPVS-2:单臂负载均衡测试

上一篇编译安装了DPVS&#xff0c;这一篇开启DPVS的负载均衡测试 &#xff1a; 单臂 FULL NAT模式 拓扑-单臂 单臂模式 DPVS 单独物理机 CLINET&#xff0c;和两个RS都是另一个物理机的虚拟机&#xff0c;它们网卡都绑定在一个桥上br0 &#xff0c; 二层互通。 启动DPVS …...

C#中提供的多种集合类以及适用场景

在 C# 中&#xff0c;有多种集合类可供使用&#xff0c;它们分别适用于不同的场景,部分代码示例提供了LeetCode相关的代码应用。 1. 数组&#xff08;Array&#xff09; 特点 固定大小&#xff1a;在创建数组时需要指定其长度&#xff0c;之后无法动态改变。连续存储&#xf…...

【蓝桥杯集训·每日一题2025】 AcWing 6135. 奶牛体检 python

6135. 奶牛体检 Week 1 2月21日 农夫约翰的 N N N 头奶牛站成一行&#xff0c;奶牛 1 1 1 在队伍的最前面&#xff0c;奶牛 N N N 在队伍的最后面。 农夫约翰的奶牛也有许多不同的品种。 他用从 1 1 1 到 N N N 的整数来表示每一品种。 队伍从前到后第 i i i 头奶牛的…...

【为什么用pg数据库用 != null 过滤不出null值】

为什么用pg数据库用 ! null 过滤不出null值 1. NULL 的特殊性质2. 为什么 ! null 无效3. 正确的过滤 NULL 的方式示例 4. 为什么 IS NULL 和 IS NOT NULL 有效5. 示例对比6. 总结 在 PostgreSQL 中&#xff0c;使用 ! null 过滤不出 NULL 值的原因与 SQL 标准中 NULL 的特殊性质…...

Classic Control Theory | 12 Real Poles or Zeros (第12课笔记-中文版)

笔记链接&#xff1a;https://m.tb.cn/h.Tt876SW?tkQaITejKxnFLhttps://m.tb.cn/h.Tt876SW?tkQaITejKxnFL...