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

AIR32F103(十一) 在AIR32F103上移植微雪墨水屏驱动

目录

  • AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告
  • AIR32F103(二) Linux环境和LibOpenCM3项目模板
  • AIR32F103(三) Linux环境基于标准外设库的项目模板
  • AIR32F103(四) 27倍频216MHz,CoreMark跑分测试
  • AIR32F103(五) FreeRTOSv202112核心库的集成和示例代码
  • AIR32F103(六) ADC,I2S,DMA和ADPCM实现的录音播放功能
  • AIR32F103(七) AIR32F103CBT6/CCT6启用96K内存
  • AIR32F103(八) 集成Helix MP3解码库播放MP3
  • AIR32F103(九) CAN总线的通信和ID过滤机制及实例
  • AIR32F103(十) 在无系统环境和FreeRTOS环境集成LVGL
  • AIR32F103(十一) 在AIR32F103上移植微雪墨水屏驱动

电子墨水屏 Electronic Paper, Digital Paper

电子墨水屏又称电子纸, 其结构是两片基板, 上面分布着微小透明颗粒, 颗粒是一种带正负电的黑色, 红色和白色粒子密封于内部液态微胶囊. 不同颜色的带电粒子会因施加电场的不同, 朝不同的方向运动,在显示屏表面呈现出黑或白, 红或白的效果, 这样,在电子纸的表面就可以显示出图案和文字, 视觉效果与纸张极为类似, 不发光, 只有画素颜色变化时(例如从黑转到白)才耗电, 掉电后屏上画面仍保留, 这个特性使其特别适合于在路牌, 标签, 价签这样的场合使用. 但是这个特性也会带来一些副作用, 例如长时间展示同一画面, 会导致显示颗粒老化, 画面不易清除, 以及刷新慢等情况. 在长时间不使用时, 建议清屏(白屏)后再断电, 放置时显示面朝上. 如果需要长时间展示一个画面, 最好设置为每隔数小时刷新一次, 减缓老化.

之前在合宙上买了一片1.54寸的墨水屏一直在吃灰, 这次趁点亮的机会把AIR32F103上的驱动示例给做了.

微雪驱动库

微雪可能是因为墨水屏才被大家熟知, 其实这家做了相当多的电路模块, 主要做外销, 国内了解的比较少.

他们维护了一个品类众多(45种)的墨水屏型号列表, 在 GitHub 上有一个专门的代码仓库

https://github.com/waveshare/e-Paper

微雪的这个驱动库代码质量还是不错的. 里面带了针对 RaspberryPi, Arduino 和 STM32 的驱动, STM32的这个驱动, 用的硬件是 STM32F103ZET6, 迁移到AIR32F103很方便.

驱动库当前支持以下的45种墨水屏型号, 从1.54寸到7.5寸, 其命名方式是 1N54 代表 1.54英寸, 如果同一尺寸有多个, 用 B, C, D, V2, V3 等后缀区分.

EPD_1IN54
EPD_1IN54B_V2
EPD_1IN54B
EPD_1IN54C
EPD_1IN64G
EPD_2IN7_V2
EPD_2IN7
EPD_2IN7B_V2
EPD_2IN7B
EPD_2IN9_V2
EPD_2IN9
EPD_2IN9B_V3
EPD_2IN9BC
EPD_2IN9D
EPD_2IN13_V2
EPD_2IN13_V3
EPD_2IN13
EPD_2IN13B_V3
EPD_2IN13B_V4
EPD_2IN13BC
EPD_2IN13D
EPD_2IN36G
EPD_2IN66
EPD_2IN66B
EPD_3IN0G
EPD_3IN7
EPD_3IN52
EPD_4IN01F
EPD_4IN2
EPD_4IN2B_V2
EPD_4IN2BC
EPD_4IN37G
EPD_5IN65F
EPD_5IN83_V2
EPD_5IN83
EPD_5IN83B_V2
EPD_5IN83BC
EPD_7IN3F
EPD_7IN3G
EPD_7IN5_HD
EPD_7IN5_V2
EPD_7IN5
EPD_7IN5B_HD
EPD_7IN5B_V2
EPD_7IN5BC

将微雪驱动库移植到AIR32F103

添加驱动库代码

将微雪仓库导出, 需要的部分都在 STM32/STM32-F103ZET6/User 目录下, 将其中代码部分复制到AIR32F103的库目录下, 形成目录结构为

Libraries
├── AIR32F10xLib
├── CMSIS
├── Debug
├── DeviceSupport
├── EPaper
│    ├── Config            # 配置文件
│    ├── e-Paper           # 对应每一个型号的 .c 和 .h 文件, 驱动的核心
│    ├── Examples          # 对应每一个型号的测试示例, 都实现了 EPD_test(void) 这个方法
│    ├── Fonts             # 字体, 5个英文字体, 2个中文字体(只是少数几个汉字)
│    └── GUI               # 点线面的绘制方法

因为目的是要在 GNU GCC 下使用 Makefile 编译, 所以有些地方需要优化一下

  1. 将目录重命名一下, e-Paper 改为 Lib
  2. 将 Debug.h 删除, 其内容集成到 DEV_Config.h
  3. 将 DEV_Config.c 和 DEV_Config.h 的公用部分(固定部分)提取为 EPD_Common.c 和 EPD_Common.h, 放到 Lib 下
  4. 将 DEV_Config.h 中的配置部分提出来创建 EPD_Config_Template.h, 这个文件在创建项目时, 可以更名为 EPD_Config.h 放到项目目录下.

变成这样的结构

├── EPaper
│    ├── EPD_Config_Template.h
│    ├── Examples
│    ├── Fonts
│    ├── GUI
│    └── Lib

进一步将每一个型号提取为宏, 然后对 Lib 和 Examples 下的每个驱动和测试 c 文件, 增加宏判断

#ifdef EPD_1IN54...#endif

这样可以在 EPD_Config.h 中使用宏配置启用哪一个型号, 例如对于合宙这块1.54的屏, 只需要启用 1N54 这个宏

/*** Uncomment the part number to enable
*/// #define EPD_1IN02
// #define EPD_1IN54_V2
#define EPD_1IN54
// #define EPD_1IN54B_V2
// #define EPD_1IN54B
// #define EPD_1IN54C
// #define EPD_1IN64G
...
...
// #define EPD_7IN5B_V2
// #define EPD_7IN5BC

这样编译时未启用的型号, 其驱动和测试会直接跳过

修改 Makefile

编辑项目模板的 Makefile, 增加配置项, y 代表启用墨水屏驱动

# Build with Waveshare e-paper lib, y:yes, n:no
USE_EPAPER    ?= y

以及对应的编译包含项, 这里使用的是修改过名称后的目录名

ifeq ($(USE_EPAPER),y)
CDIRS   += Libraries/EPaper/Lib \Libraries/EPaper/Examples \Libraries/EPaper/Fonts \Libraries/EPaper/GUIINCLUDES  += Libraries/EPaper/Lib \Libraries/EPaper/Examples \Libraries/EPaper/Fonts \Libraries/EPaper/GUI
endif

驱动墨水屏的示例项目

硬件部分

  • AIR32F103CBT6, 墨水屏驱动编译完只有30多KByte, 所以用哪个型号都可以
  • 合宙的1.54寸墨水屏. 如果使用其它墨水屏, 记得修改启用对应的宏

接线是典型的 SPI 接线方式, 和普通LCD一样, 但是没有背光, 增加了一个 Busy 脚

 * Waveshare 1.54' E-Paper Demo* * AIR32        E-Paper* - PA2        BUSY* - PA3        CS* - PA4        DC(Data/Command)* - PA5        SCK/SCL* - PA6        RES* - PA7        SI/SDA* - GND        GND* - 3.3V       VCC

软件部分

设置 EPD_Config.h

  1. 将 EPD_Config_Template.h 复制到项目目录下, 更名为 EPD_Config.h 并打开编辑
  2. 启用 EPD_1IN54, 将其反注释
  3. EPD_DEBUG设为1, 可以开启串口日志输出
  4. 定义 RESET, DC, CS, BUSY 这几个 GPIO 对应的 PORT和 PIN, 这些 PIN 脚随后需要在程序中初始化
  5. 定义几个关键方法的宏

/*** Uncomment to enable the part
*/
// #define EPD_1IN02
// #define EPD_1IN54_V2
#define EPD_1IN54
// #define EPD_1IN54B_V2
// ...
// #define EPD_7IN5BC#define EPD_DEBUG 1/*** e-Paper GPIO*/
#define EPD_RST_PIN     GPIOA, GPIO_Pin_6
#define EPD_DC_PIN      GPIOA, GPIO_Pin_4
#define EPD_CS_PIN      GPIOA, GPIO_Pin_3
#define EPD_BUSY_PIN    GPIOA, GPIO_Pin_2/*** GPIO read and write*/
#define EPD_Digital_Write(_pin, _value) GPIO_WriteBit(_pin, _value == 0? Bit_RESET:Bit_SET)
#define EPD_Digital_Read(_pin)          GPIO_ReadInputDataBit(_pin)
#define EPD_SPI_WriteByte(_value)       SPI_TxRx(_value)
#define EPD_Delay_ms(__xms)             Delay_Ms(__xms)#endif

初始化外设

因为是示例项目, 就不单独分文件了, 都添加到 main.c.

初始化普通 GPIO, PA2是输入, PA3, PA4, PA6 都是输出

void APP_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA, GPIO_Pin_2);
}

初始化SPI1, 这里用 PA5作为SCL, PA7作为SDA

void APP_SPI_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef  SPI_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_5 | GPIO_Pin_7);SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 0;SPI_Init(SPI1, &SPI_InitStructure);SPI_Cmd(SPI1, ENABLE);
}

对应 EPD_Config.h 中的 EPD_SPI_WriteByte() 宏定义, 创建 SPI 的字节读写方法

uint8_t SPI_TxRx(uint8_t data)
{uint8_t retry = 0;while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET && ++retry);SPI_I2S_SendData(SPI1, data);while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET && ++retry);return SPI_I2S_ReceiveData(SPI1);
}

运行驱动测试

在 main() 中初始化后直接调用微雪自带的测试函数. 这个测试会写入图, 然后写入文字, 局部刷新, 最后清屏, 进入睡眠.

int main(void)
{//...APP_GPIO_Config();APP_SPI_Config();EPD_test();while (1);
}

遇到的问题

字体编译错误

原驱动库中文使用的是 GB2312 的编码, 而我在 Ubuntu 下肯定是不用 GBK 的, 所以会乱码, 我把这部分都改成 UTF-8 了, 因此对应的汉字的字节数也从2变成了3, 需要做对应的修改

fonts.h

typedef struct
{unsigned char index[3];                                  //<-- 从 2 改成 3const char matrix[MAX_HEIGHT_FONT*MAX_WIDTH_FONT/8];
} CH_CN;

GUI_Paint.c

void Paint_DrawString_CN(UWORD Xstart, UWORD Ystart, const char * pString, cFONT* font,UWORD Color_Foreground, UWORD Color_Background)
{
//.../* Point on the next character */p_text += 3;                                  //<-- 从 2 改成 3
//...

原先的字体定义方式为

/*--  文字:  好  --*/
/*--  微软雅黑12;  此字体下对应的点阵为:宽x高=16x21   --*/
{"好",
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x73,0xFF,0x70,0x0F,0xFE,0x1E,
0x7E,0x3C,0x6E,0x38,0xEE,0x30,0xEF,0xFF,0xFC,0x30,0x7C,0x30,0x38,0x30,0x3E,0x30,
0x7E,0x30,0xE0,0x30,0xC1,0xF0,0x00,0x00,0x00,0x00},

这种初始化赋值应该是 ARM GCC 支持, 但是 GUN GCC 不支持, 编译会报错, 两个struct成员变量不能用同一个花括号, 需要改为

  /*--  文字:  好  --*/
/*--  微软雅黑12;  此字体下对应的点阵为:宽x高=16x21   --*/
{index:"好",matrix: {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x73,0xFF,0x70,0x0F,0xFE,0x1E,0x7E,0x3C,0x6E,0x38,0xEE,0x30,0xEF,0xFF,0xFC,0x30,0x7C,0x30,0x38,0x30,0x3E,0x30,0x7E,0x30,0xE0,0x30,0xC1,0xF0,0x00,0x00,0x00,0x00}
},

或者下面这种形式

  /*--  文字:  好  --*/
/*--  微软雅黑12;  此字体下对应的点阵为:宽x高=16x21   --*/
{"好",{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x73,0xFF,0x70,0x0F,0xFE,0x1E,0x7E,0x3C,0x6E,0x38,0xEE,0x30,0xEF,0xFF,0xFC,0x30,0x7C,0x30,0x38,0x30,0x3E,0x30,0x7E,0x30,0xE0,0x30,0xC1,0xF0,0x00,0x00,0x00,0x00}
},

经过以上的修改, 就可以正常编译了.

示例项目源代码

代码已经提交到 GitHub 仓库

https://github.com/IOsetting/air32f103-template/tree/master/Examples/NonFreeRTOS/SPI/Waveshare_1N54_E-Paper

将目录下的文件复制替换掉 User 目录下的文件, 再编辑 Makefile, 开启 EPaper 库就能编译.

如果需要驱动其它型号的墨水屏, 编辑 EPD_Config.h 将#define EPD_1IN54注释掉, 再将需要启用的型号取消注释即可.

相关文章:

AIR32F103(十一) 在AIR32F103上移植微雪墨水屏驱动

目录 AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告AIR32F103(二) Linux环境和LibOpenCM3项目模板AIR32F103(三) Linux环境基于标准外设库的项目模板AIR32F103(四) 27倍频216MHz,CoreMark跑分测试AIR32F103(五) FreeRTOSv202112核心库的集成和示例代码AIR32F103(六) ADC,I2S…...

Uipath Excel 自动化基础系列文章

Uipath Excel 自动化基础系列文章已发布到CSDN,网址&#xff1a;https://blog.csdn.net/Marshaljun?typeblog (3月份会在CSDN博客发布Uipath Excel 实战课程及经验分享) Uipath Studio流程设计器介绍 https://blog.csdn.net/Marshaljun/article/details/128699022 Uipath St…...

神经网络优化器之随机梯度下降法的理解

随机梯度下降法&#xff08;SGD&#xff09;随机梯度下降方法&#xff0c;在每次更新时用1个样本&#xff0c;随机也就是说我们用样本中的一个例子来近似我所有的样本&#xff0c;由于计算得到的并不是准确的一个梯度&#xff0c;因而不是全局最优的。但是相比于批量梯度&#…...

记录一次WIN11开机在登录页面循环的问题

记录一次由于未进行win密码设置&#xff0c;导致开机后卡在登录界面无法登录进去的问题。最后完美解决了。 1. 背景 开机后&#xff0c;显示用户登录界面&#xff0c;但是和以往不同&#xff0c;没有了密码输入框&#xff0c;只有一个“登录”按钮孤零零地显示在屏幕中间&…...

始终从最不易改变的方面开始

在你刚开始新工作、转换职业或者是加入新项目时&#xff0c;始终从最不易改变的方面开始。 在工作中&#xff0c;这可能意味着与团队成员建立关系&#xff0c;了解公司的流程和文化&#xff0c;或者熟悉公司的产品或服务。 在一项新项目中&#xff0c;这可能意味着了解项目范…...

4、Httpclient源码解析之HTTP协议

初始化CloseableHttpClient过程中涉及ExecChainHandler & DefaultHttpProcessor&#xff0c;即典型客户端责任链中的请求执行处理器。 责任链中各节点涉及请求处理器【ExecChainHandler】顺序如下&#xff1a;RedirectExec、ContentCompressionExec、HttpRequestRetryExec…...

浏览器并发行为记录

使用nodejs koa起一个服务&#xff0c;使请求延时返回。 服务端代码 /** 延时 */ exports.timeoutTestData async function (ctx) {console.log(get query:, ctx.request.query);const query ctx.request.query;let timeout query.timeout || 2000;await new Promise(res…...

工厂模式与抽象工厂

原理&#xff1a;逻辑和业务全部封装 不需要细节 只要结果 示例&#xff1a; # 简单工厂 class SimpleFactory:# 产品staticmethoddef product(name):return nameif __name__ "__main__":product SimpleFactory.product("Gitee")print(product) 装饰器…...

什么?你不知道 ConcurrentHashMap 的 kv 不能为 null?

一、背景 最近设计某个类库时使用了 ConcurrentHashMap 最后遇到了 value 为 null 时报了空指针异常的坑。 本文想探讨下以下几个问题&#xff1a; &#xff08;1&#xff09; Map接口的常见子类的 kv 对 null 的支持情况。 &#xff08;2&#xff09;为什么 ConcurrentHashM…...

SQL复习04 | 复杂查询

1. 视图 视图和表的区别&#xff1a; 表保存的是实际的数据视图保存的是SELECT语句 视图的优点&#xff1a; 视图无需保存数据&#xff0c;可节省存储设备的容量可以将频繁使用的SELECT语句保存成视图&#xff0c;可大大提高效率 1.1 创建视图 CREATE VIEW 视图名称&…...

【面试题】Java面试题汇总(无解答)

此内容会持续补充。。。 基础 short s1 1; s1 s1 1;有错吗? short s1 1; s1 1; 有错吗&#xff1f;String str”aaa”,与 String strnew String(“aaa”)一样吗&#xff1f;String 和 StringBuilder、StringBuffer 的区别&#xff1f;Sring最大能存多大内容&#xff1f…...

C++---背包模型---收服精灵(每日一道算法2023.3.11)

注意事项&#xff1a; 本题是"动态规划—01背包"的扩展题&#xff0c;优化的思路不多赘述&#xff0c;dp思路会稍有不同&#xff0c;下面详细讲解。 本题偏向阅读理解&#xff0c;给每种变量归类起名字很有帮助哦。 切记先看思路&#xff0c;再看代码。&#xff08;大…...

day30_JS

今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、作业 二、BOM 三、定时器 四、正则表达式 零、 复习昨日 事件 事件绑定方式鼠标事件 onmouseoveronmouseoutonmousemove 键盘事件 onkeydownonkeyupon…...

【Java学习笔记】19.Java 正则表达式(2)

前言 本章继续介绍Java的正则表达式。 Matcher 类的方法 索引方法 索引方法提供了有用的索引值&#xff0c;精确表明输入字符串中在哪能找到匹配&#xff1a; 序号方法及说明1public int start()返回以前匹配的初始索引。2public int start(int group)返回在以前的匹配操作…...

华为云arm架构轻松安装kubeedge

先安装k8s 华为云arm架构安装k8s(kubernetes) 下载kubeedge需要的软件 官方github下载kubeedge地址 cloudcore.service文件下载地址 注意:下载对应的版本和arm架构 keadm-v1.6.1-linux-arm64.tar.gz 下面的2个文件可以不用下载,安装kubeedge时也会自动去下载到/etc/kubee…...

33--Vue-前端开发-使用Vue脚手架快速搭建项目

一、vue脚手架搭建项目 node的安装: 官方下载,一路下一步 node命令类似于python npm命令类似于pip 使用npm安装第三方模块,速度慢一些,需换成淘宝镜像 以后用cmpm代替npm的使用 npm install -g cnpm --registry=https://registry.npm.taobao.org安装脚手架: cnpm inst…...

TMS WEB Core开发Web应用优势说明

一、Delphi开发Web应用的三大框架如下: IntraWEB适合于WEB前、后端的开发,其自带的网络服务器非常强大、稳定,笔者使用Cesium框架开发的WEB GIS地理信息系统前端不需要Apache Tomcat或Nginx即可稳定运行; uniGUI是对JavaScript库Sencha ExtJS的封装,它带有两套VCL组件包,…...

人工智能简单应用1-OCR分栏识别:两栏识别三栏识别都可以,本地部署完美拼接

大家好&#xff0c;我是微学AI&#xff0c;今天给大家带来OCR的分栏识别。 一、文本分栏的问题 在OCR识别过程中&#xff0c;遇到文字是两个分栏的情况确实是一个比较常见的问题。通常情况下&#xff0c;OCR引擎会将文本按照从左到右&#xff0c;从上到下的顺序一行一行地识别…...

Gin框架路由拆分与注册详解析

Gin框架路由拆分与注册详解析1.基本的路由注册2.路由拆分成单独文件或包3.路由拆分成多个文件4.路由拆分到不同的APP1.基本的路由注册 下面最基础的gin路由注册方式&#xff0c;适用于路由条目比较少的简单项目或者项目demo // StatCost 是一个统计耗时请求耗时的中间件 func…...

2020蓝桥杯真题凯撒加密 C语言/C++

题目描述 给定一个单词&#xff0c;请使用凯撒密码将这个单词加密。 凯撒密码是一种替换加密的技术&#xff0c;单词中的所有字母都在字母表上向后偏移 3 位后被替换成密文。即 a 变为 d&#xff0c;b 变为 e&#xff0c;⋯&#xff0c;w 变为z&#xff0c;x 变为 a&#xff0…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

R 语言科研绘图第 55 期 --- 网络图-聚类

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...