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

STM32移植U8G2

STM32 移植 U8G2

u8g2 (Universal 8bit Graphics Library version2 的缩写)是用于嵌入式设备的单色图形库,可以在单色屏幕中绘制 GUI。u8g2 内部附带了例如 SSD13xx,ST7xx 等很多 OLED,LCD 驱动。内置多种不同大小和风格的字体,可以显示中文,其次就是图形程序实现线,框,圆等图形绘制。

1. 建立裸机工程

在移植 u8g2 之前先创建 STM32F103 的 Keil5 工程模板(如何搭建 Keil 模板这里不多介绍),用来编译 STM32 驱动源码和 u8g2 源码。这也是支持 u8g2 开发的一个单片机运行环境,并且调试好屏幕驱动,确保屏幕初始化成功。

屏幕驱动只是为了验证屏幕可行性,移植后方便排除因屏幕不显示的问题,u8g2 附带屏幕驱动程序,受支持的屏幕可以使用里面的驱动程序 。整体移植操作和芯片无关,所以无论什么芯片移植方法都相同。

2. 下载源码

在 Github 官网搜索 u8g2 进行下载,或通过 https://github.com/olikraus/u8g2 链接下载,u8g2 没有发行版,所以直接下载 master 分支源码,下载后可以得到一个 u8g2-master.zip 这样的源码压缩包,如下图。

请添加图片描述

3. u8g2 文件概览

u8g2 源码主要需要使用 cppsrc/csrc/ 这两个文件夹。分别为 u8g2 对 C++ 兼容支持库,u8g2 源码文件夹

请添加图片描述

cppsrc 对 C++ 兼容支持,方便把 u8g2 移植到 C++ 应用。cppsrc 用 C++ 类简单封装了 u8g2 普通操作函数(实际还是依赖 csrc),如下所示,把 u8g2 移植到 C++ 应用才需要这部分代码。

/*u8g2_line.c */
void U8G2::drawLine(u8g2_uint_t x1, u8g2_uint_t y1, u8g2_uint_t x2, u8g2_uint_t y2) 
{u8g2_DrawLine(&u8g2, x1, y1, x2, y2);
}

其他就是一些说明文档,辅助工具程序,版本变更信息,LICENSE 等等,这部分保留 LICENSE(开源许可) 其余可以删除精简工程。

4. 移植 u8g2

在 Keil 项目管理器新建一个 u8g2 文件夹,添加 u8g2 目录 u8g2/csrc/ 下所有的.c 文件。即使 u8g2 移植到 C++ 应用,这部分也是需要的(u8g2 C++ 部分实际还是依赖 csrc 的源码)。

请添加图片描述

添加 u8g2 的头文件目录 u8g2/csrc/,即 u8g2 源码和头文件在同一个目录。

5. 驱动函数选择

csrc 目录下屏幕驱动文件以 u8x8_d_xx_yy_zz.c 格式命名,其中 xx 芯片型号,yy 屏幕分辨率,zz 识别名称,zz 不是一定的,可以为空或 noname。

例如:SSD1312 芯片驱动,128x64 分辨率的 OLED,使用的驱动文件为 u8x8_d_ssd1312_128x64_noname.c

驱动配置函数通常和文件同名,在驱动文件中找到同名函数即可,比如这里就是:

uint8_t u8x8_d_ssd1312_128x64_noname(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)

注意:驱动文件和驱动函数也可能不对应,例如 ssd1312 的驱动函数可能定义在 ssd1306 的驱动文件,这是 u8g2 为了把相近屏幕的驱动函数统一到一个文件。

如果要减小代码量,其它型号屏幕驱动和分辨率对应的 .c 驱动文件可以删除。

6. u8g2_d_setup.c

csrc 目录下找到这个文件,文件包含各种屏幕的配置函数,实上选择的屏幕驱动函数就会被这些配置函数调用。

屏幕配置函数以 u8g2_Setup_xx_yy_zz_gg_[1/2/f].c 命名,具体字段解释如下:

xx 芯片型号,ssd1306,sh1106 等等。

yy 通信方式,识不是一定的,i2c 表示为 i2c 接口,如果没有则表示 spi 通信。

zz 屏幕分辨率,128x64,128x80 等等。

gg 识别名称,gg 不是一定的,可以为 noname 也可以为空。

[1/2/f] 显存 BUF 大小,1:128字节,2:256 字节,f:1024 字节。

例如:SSD1312 芯片驱动,128x64 分辨率 SPI 通信的 OLED,希望使用 1024 字节显存,使用的配置函数为 u8g2_Setup_ssd1312_128x64_noname_f

/*ssd1312 f*/
void u8g2_Setup_ssd1312_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
{uint8_t tile_buf_height;uint8_t *buf;u8g2_SetupDisplay(u8g2, u8x8_d_ssd1312_128x64_noname, u8x8_cad_001, byte_cb, gpio_and_delay_cb);buf = u8g2_m_16_8_f(&tile_buf_height);u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_vertical_top_lsb, rotation);
}

可以看到上方函数调用了 u8x8_d_ssd1312_128x64_noname(),如果要减小代码量,其它的配置函数可以删除或注释,只留下选择的即可。

7. u8g2_d_memory.c

csrc 目录下找到 u8g2_d_memory.c,文件里面是 u8g2 对显存的定义。在屏幕配置函数中,只调用了 u8g2_m_16_8_f(),所以如果编译 u8g2 时如果提示内存不足,除此之外其它显存函数可以删除或注释。

uint8_t *u8g2_m_16_8_f(uint8_t *page_cnt)
{#ifdef U8G2_USE_DYNAMIC_ALLOC*page_cnt = 8;return 0;#elsestatic uint8_t buf[1024];*page_cnt = 8;return buf;#endif
}

8. 对接屏幕驱动

把屏幕相关的硬件控制对接给 u8g2,需要我们实现 GPIO 控制和数据发送这 2 个统一驱动函数,函数原型如下,函数名称可以自定义:

uint8_t (*u8x8_msg_cb)(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);

最终通过注册的的方式提供给 u8g2。

8.1 对接 GPIO

把屏幕的 GPIO 控制函数按照用途对接到指定位置,比如 SPI 屏幕要对接 CSDCRESET 对应的 GPIO。

uint8_t u8x8_stm32_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{/**STM32 supports HW SPI, Remove unused cases like U8X8_MSG_DELAY_XXX & U8X8_MSG_GPIO_XXX */switch (msg) {case U8X8_MSG_GPIO_AND_DELAY_INIT:/*Insert codes for initialization*/break;case U8X8_MSG_DELAY_MILLI:/* ms Delay */sleep_ms(arg_int);break;#ifdef _USE_SPI/*SPI Interface*/case U8X8_MSG_GPIO_CS:/*Insert codes for SS pin control */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, arg_int);break;case U8X8_MSG_GPIO_DC:/*Insert codes for DC pin control */HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, arg_int);break;case U8X8_MSG_GPIO_RESET:/*Insert codes for RST pin control*/HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, arg_int);break;case U8X8_MSG_GPIO_SPI_CLOCK:/*Insert codes for CLOCK pin control */break;case U8X8_MSG_GPIO_SPI_DATA:/*Insert codes for DATA pin control */break;#endif /*_USE_SPI*/#ifdef _USE_I2Ccase U8X8_MSG_GPIO_I2C_CLOCK:/*Insert codes for CLOCK pin control */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, arg_int);break;case U8X8_MSG_GPIO_I2C_DATA:/*Insert codes for CLOCK pin control */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, arg_int);break;
#endif /*_USE_I2C*/}return 1;
}

如果使用 GPIO 模拟时序通信还要对接模拟通信 GPIO,比如软件模拟 I2C 还要对接 SCLSDA 对应 GPIO,同时还要对接延时函数,u8g2 才能模拟时序。

8.2 对接数据

把屏幕的数据发送函数对接到指定位置,如果屏幕使用 SPI 接口,U8X8_MSG_BYTE_SEND 对应的是 SPI 数据发送函数,可以参考如下写法:

uint8_t u8x8_byte_stm32_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{HAL_StatusTypeDef _res = HAL_ERROR;switch (msg) {case U8X8_MSG_BYTE_SEND:/*Insert codes to transmit data*/_res = HAL_SPI_Transmit(&hspi3, arg_ptr, arg_int, TX_TIMEOUT);if (_res != HAL_OK) return 0;break;case U8X8_MSG_BYTE_INIT:/*Insert codes to begin SPI transmission*/break;case U8X8_MSG_BYTE_SET_DC:/*Control DC pin, U8X8_MSG_GPIO_DC will be called*/u8x8_gpio_SetDC(u8x8, arg_int);break;case U8X8_MSG_BYTE_START_TRANSFER:/* Select slave, U8X8_MSG_GPIO_CS will be called */u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);sleep_ms(2);break;case U8X8_MSG_BYTE_END_TRANSFER:sleep_ms(2);/* Insert codes to end SPI transmission */u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);break;}return 1;
}

如果屏幕使用 I2C 接口,U8X8_MSG_BYTE_SEND 对应的是 I2C 数据发送函数,可以参考如下写法:

uint8_t u8x8_byte_stm32_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{/**u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */static uint8_t buffer[32] = {0};static uint8_t buf_idx = 0;uint8_t * data = NULL;switch (msg) {case U8X8_MSG_BYTE_SEND:data = (uint8_t *) arg_ptr;while (arg_int > 0) {buffer[buf_idx++] = *data;data++;arg_int--;}break;case U8X8_MSG_BYTE_INIT:/*add your custom code to init i2c subsystem*/break;case U8X8_MSG_BYTE_SET_DC:break;case U8X8_MSG_BYTE_START_TRANSFER:buf_idx = 0;break;case U8X8_MSG_BYTE_END_TRANSFER:HAL_I2C_Master_Transmit(_I2C_DEV, (DEV_ADDR << 1), buffer, buf_idx, TX_TIMEOUT);break;}return 1;
}

8.3 初始化外设

如果数据发送是通过单片机外设硬件实现实现的,初始化 u8g2 前先初始化外设和对应的 GPIO,例如这里初始化 SPI 接口,还有相应 GPIO。

void oled_spi3_init(void)
{/* USER CODE BEGIN SPI3_Init 0 *//* USER CODE END SPI3_Init 0 *//* USER CODE BEGIN SPI3_Init 1 *//* USER CODE END SPI3_Init 1 */hspi3.Instance = SPI3;hspi3.Init.Mode = SPI_MODE_MASTER;hspi3.Init.Direction = SPI_DIRECTION_2LINES;hspi3.Init.DataSize = SPI_DATASIZE_8BIT;hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;hspi3.Init.NSS = SPI_NSS_SOFT;hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi3.Init.TIMode = SPI_TIMODE_DISABLE;hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi3.Init.CRCPolynomial = 10;if (HAL_SPI_Init(&hspi3) != HAL_OK){Error_Handler();}/* USER CODE BEGIN SPI3_Init 2 *//* USER CODE END SPI3_Init 2 */
}

8.4 初始化 u8g2

u8g2 没有对象初始化函数,自定义 u8g2 对象初始化函数,函数名称可以自定义,在初始化函数调用显示初始化及对应的屏幕配置函数,如下。

void u8g2_init(u8g2_t *u8g2)
{u8g2_Setup_ssd1312_128x64_noname_f(u8g2, U8G2_R2, u8x8_byte_stm32_hw_spi, u8x8_stm32_gpio_and_delay);u8g2_SetPowerSave(u8g2, 1);u8g2_InitDisplay(u8g2);u8g2_ClearDisplay(u8g2);u8g2_ClearBuffer(u8g2);u8g2_SetPowerSave(u8g2, 0);
}

可以看到这个就是前面讲解屏幕的配置函数,如下。

void u8g2_Setup_ssd1312_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);

该函数的 4 个参数含义:

(1) u8g2,指定待初始化的 u8g2 对象,即 u8g2 结构体。
(2) rotation,配置屏幕旋转方向,支持 U8G2_R0,U8G2_R1,U8G2_R2,U8G2_R3 四种旋转方向。
(3) byte_cb,注册数据通信发送函数。
(4) gpio_and_delay_cb:注册屏幕 GPIO 控制函数。

8.5 总结

把对接屏幕驱动用到的这些自定义函数统一编写到一个文件中,文件可自行命名,例如命名为 u8g2_stm32.c,并添加到 u8g2 之外的用户目录。

9. 测试函数

移植完成后编写应用程序测试 u8g2 是否正常,调用 u8g2 绘图函数在显存绘制内容,在 main 函数调用初始化 SPI 和 u8g2,注意在主循环中调用 u8g2 显存发送函数 u8g2_SendBuffer 将显存内容更新至屏幕,在此附上 u8g2 测试程序。

#include "u8g2.h"static u8g2_t u8g2 = {0};void draw(u8g2_t * u8g2_p)
{u8g2_SetFontMode(u8g2_p, 1);u8g2_SetFontDirection(u8g2_p, 0);u8g2_SetFont(u8g2_p, u8g2_font_inb24_mf);u8g2_DrawStr(u8g2_p, 0, 20, "U");u8g2_SetFontDirection(u8g2_p, 1);u8g2_SetFont(u8g2_p, u8g2_font_inb30_mn);u8g2_DrawStr(u8g2_p, 21, 8, "8");u8g2_SetFontDirection(u8g2_p, 0);u8g2_SetFont(u8g2_p, u8g2_font_inb24_mf);u8g2_DrawStr(u8g2_p, 51, 30, "g");u8g2_DrawStr(u8g2_p, 67, 30,"\xb2");u8g2_DrawHLine(u8g2_p, 2, 35, 47);u8g2_DrawHLine(u8g2_p, 3, 36, 47);u8g2_DrawVLine(u8g2_p, 45, 32, 12);u8g2_DrawVLine(u8g2_p, 46, 33, 12);u8g2_SetFont(u8g2_p, u8g2_font_4x6_tr);u8g2_DrawStr(u8g2_p, 1, 54, "github.com/olikraus/u8g2");
}void main()
{oled_spi_init();u8g2_init(&u8g2);for (;;) {u8g2_ClearBuffer(&u8g2);draw(&u8g2);u8g2_SendBuffer(&u8g2);}
}

10. 移植 C++ 版本

移植 C++ 版本基础步骤和前面小节介绍的步骤相同,除此之外现在继续在 Keil 项目管理器再新建一个 u8g2cpp 文件夹,然后添加 u8g2 目录 u8g2/cppsrc/ 下所有的 .cpp 文件。

请添加图片描述

10.1 u8g2 继承类

自定义 u8g2 对象初始化类,继承 U8G2 不是必须的。可以把类定义在 U8g2lib.h 文件中,或其他文件,类名称可以自定义。在类的构造函数调用对应的屏幕配置函数,例如调用 ssd1312 屏幕配置。

void u8g2_Setup_ssd1312_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);

再自定义初始化函数 SSD1312::Init(),调用 u8g2 显示初始化来初始化 u8g2。

extern "C" uint8_t u8x8_stm32_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
extern "C" uint8_t u8x8_byte_stm32_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);class SSD1312 : public U8G2 {
private:public: SSD1312(const u8g2_cb_t *rotation = U8G2_R2) : U8G2() {u8g2_Setup_ssd1312_128x64_noname_f(&u8g2, rotation, u8x8_byte_stm32_hw_spi, u8x8_stm32_gpio_and_delay);}bool Init() {/**note: call to u8x8_utf8_init is not required here, this is done in the setup procedures before*/setPowerSave(1); initDisplay(); clearDisplay(); clearBuffer(); setPowerSave(0);return 1;}
};

10.2 测试程序

调用 SSD1312 类对象方法,编写应用程序测试 u8g2 是否正常,调用 u8g2 绘图函数在显存绘制内容,初始化 u8g2 对象,在主循环中调用 sendBuffer 将显存内容更新至屏幕。

#include "U8g2lib.h"SSD1312 oled;void draw(SSD1312 * oled_p)
{oled_p->setFontMode(1);oled_p->setFontDirection(0);oled_p->setFont(u8g2_font_inb24_mf);oled_p->drawStr(0, 20, "U");oled_p->setFontDirection(1);oled_p->setFont(u8g2_font_inb30_mn);oled_p->drawStr(21, 8, "8");oled_p->setFontDirection(0);oled_p->setFont(u8g2_font_inb24_mf);oled_p->drawStr(51, 30, "g");oled_p->drawStr(67, 30,"\xb2");oled_p->drawHLine(2, 35, 47);oled_p->drawHLine(3, 36, 47);oled_p->drawVLine(45, 32, 12);oled_p->drawVLine(46, 33, 12);oled_p->setFont(u8g2_font_4x6_tr);oled_p->drawStr(1, 54, "github.com/olikraus/u8g2");
}void main()
{oled.Init();for (;;) {oled.clearBuffer();draw(&oled);oled.sendBuffer();}
}

详细查看:

https://blog.csdn.net/qq_51183186/article/details/120348070

相关文章:

STM32移植U8G2

STM32 移植 U8G2 u8g2 &#xff08;Universal 8bit Graphics Library version2 的缩写&#xff09;是用于嵌入式设备的单色图形库&#xff0c;可以在单色屏幕中绘制 GUI。u8g2 内部附带了例如 SSD13xx&#xff0c;ST7xx 等很多 OLED&#xff0c;LCD 驱动。内置多种不同大小和风…...

26.电流信号的强抗干扰能力运用

电流信号强抗干扰能力运用 1. 电流型信号与电压型信号的传输抗干扰能力差异2. 电流型信号电路示例 1. 电流型信号与电压型信号的传输抗干扰能力差异 现场干扰以电场干扰为主&#xff0c;电压较高但是能量&#xff08;电流I&#xff09;较低。如果以能量信号作为传输媒介&#x…...

【 Node.js】 Node.js安装

下载 下载 | Node.js 中文网https://nodejs.cn/download/ 安装 双击安装包 点击Next 勾选使用许可协议&#xff0c;点击Next 选择安装位置 点击Next 点击Next 点击Install 点击Finish 完成安装 添加环境变量 编辑【系统变量】下的变量【Path】添加Node.js的安装路径--如果…...

经典算法 青蛙跳杯子

青蛙跳杯子 题目描述 桌子上有n行m列的杯子&#xff0c;每个杯子与相邻杯子之间的距离为1&#xff0c;已知青蛙的跳跃半径为d&#xff0c;青蛙现在在第一行第一列的杯子上&#xff0c;它跳到最后一行最后一列的杯子上&#xff0c;最少需要跳几次&#xff1f; 输入描述 输入…...

C语言-函数的递归和迭代

以下是我初学C语言的笔记记录&#xff0c;欢迎在评论区补充留言 一&#xff0c;函数的递归 大致有这么几个问题【我看完这堂课后&#xff0c;自己总结的几个问题】 * 问题 1&#xff0c;什么是函数的递归, 2&#xff0c;它是干什么用的&#xff0c;3&#xff0c;有什么条件吗…...

Linux安装部署Postgresql数据库

联网安装方案 Linux能在线安装依赖组件的前提下&#xff0c;可以快速安装部署PG数据库&#xff0c;安装过程使用root管理员帐号&#xff1a; 首先&#xff0c;使用如下命令自动下载Postgresql组件&#xff1a; # 在openEuler、Fedora或CentOS 8上&#xff0c;你可能会使用&a…...

学习与规划的融合Dyna-Q:python从零实现

&#x1f9e0; 向所有学习者致敬&#xff01; “学习不是装满一桶水&#xff0c;而是点燃一把火。” —— 叶芝 我的博客主页&#xff1a; https://lizheng.blog.csdn.net &#x1f310; 欢迎点击加入AI人工智能社区&#xff01; &#x1f680; 让我们一起努力&#xff0c;共创…...

电子病历高质量语料库构建方法与架构项目(环境聆听与自动化文档生成篇)

电子病历高质量语料库的构建是一个复杂而系统的工程,涉及数据收集、清洗、标注、验证等多个环节。在项目实施过程中,"环境聆听"和"自动化文档生成"是两个关键支撑要素,前者确保项目能够适应不断变化的技术和业务环境,后者则保障项目过程的可追溯性和知…...

LegalOne:本土与国际视野融合的法律评级,大湾区律师及律师事务所榜单申报启动

在广东这片法律服务发展的热土上&#xff0c;从1979年全国首家法律服务机构诞生&#xff0c;到如今培育出4700家律所与8.7万律师&#xff0c;法律行业始终蓬勃向前。随着粤港澳大湾区建设推进&#xff0c;法律服务市场迈向双向融合的国际化新阶段&#xff0c;众多优秀律所和律师…...

突破传统!TTRL如何开启大模型无监督强化学习新篇章?

在大语言模型&#xff08;LLMs&#xff09;蓬勃发展的时代&#xff0c;如何让模型在无明确标签数据下有效学习成为关键难题。本文提出的Test-Time Reinforcement Learning&#xff08;TTRL&#xff09;给出了创新解法。它利用多数投票估计奖励&#xff0c;实现LLMs自我进化&…...

什么是:云边端一体化架构

什么是云边端一体化架构 文章目录 什么是云边端一体化架构云、边、端云计算边缘计算终端设备 云边端一体化协同云边端一体化架构协同的流程云边端一体化架构协同的应用云边端一体化架构协同的价值云边端一体化架构协同未来发展趋势 云、边、端 云&#xff08;Cloud&#xff09…...

【2025域适应科研日报】

本笔记主要为了记录自己的科研日报&#xff0c;前段时间刚开始想写的初衷也是为了自己的思考不跑偏&#xff0c;但是有几天又没有坚持下来&#xff0c;看到一位学长的文章&#xff0c;发现这种形式还是很有必要的&#xff0c;所以自己也打算坚持记录下来&#xff0c;由于还正在…...

Linux从入门到精通:全面掌握基础命令与高效操作实战指南

引言 Linux 作为开发者、运维工程师及技术爱好者的核心工具&#xff0c;其命令行的高效性与灵活性无可替代。但对于新手而言&#xff0c;复杂的命令与文件结构往往令人困惑。本文基于官方文档与实践经验&#xff0c;系统梳理 Linux 基础命令、文件管理、目录操作、高级技巧 四大…...

如何提升个人的稳定性?

提升自我的稳定性是一个系统性工程&#xff0c;需要从内在认知、情绪管理、行为习惯到外在环境等多个维度进行优化。 以下是一些具体建议&#xff0c;帮助你逐步增强内心的稳定感&#xff1a; 一、内在认知调整 1. 建立清晰的自我认知 通过反思&#xff08;如写日记、冥想…...

电机常用易混淆概念说明(伺服、舵机、多轮)

1. 概述 基础动力需求 &#xff1a;普通电机&#xff08;如水泵、风扇&#xff09;。 高精度控制 &#xff1a;优先伺服系统或伺服电机&#xff08;如数控机床&#xff09;。 微型化场景 &#xff1a;舵机&#xff08;如遥控模型&#xff09;。 移动底盘 &#xff1a;单舵轮成…...

短视频矩阵系统:源码搭建与定制化开发的深度剖析

在短视频行业蓬勃发展的当下&#xff0c;越来越多的企业和个人希望构建自己的短视频矩阵系统。而在搭建过程中&#xff0c;源码搭建和定制化开发是两种常见的选择&#xff0c;它们各有优劣&#xff0c;适用于不同的需求场景。本文将从多个维度深入探讨两者的区别&#xff0c;为…...

8.进程概念(四)

一、环境变量 1.基本概念 环境变量(environment variables)⼀般是指在操作系统中用来指定操作系统运行环境的⼀些参数。 如&#xff1a;我们在编写C/C代码的时候&#xff0c;在链接的时候&#xff0c;从来不知道我们的所链接的动态静态库在哪里&#xff0c;但是照样可以链接成…...

Windows服务器提权实战:常见方法、场景与防御指南

在渗透测试中&#xff0c;​​权限提升&#xff08;提权&#xff09;​​是从低权限账户&#xff08;如IIS、Apache运行账户&#xff09;获取系统管理员&#xff08;如SYSTEM&#xff09;权限的关键步骤。本文将从实战角度解析Windows服务器提权的常见技术&#xff0c;并结合真…...

OpenGL-ES 学习(14) ----顶点指定和基本图元的绘制

目录 本节概述顶点的指定常量顶点属性和顶点数组顶点数组顶点属性的定义Shader 中声明顶点属性变量顶点属性的绑定 基本图元绘制基本图元三角形直线绘制图元的API 本节概述 绘制图形的第一步就是指定顶点坐标&#xff0c;可以每个顶点指定&#xff0c;也可以是用于所有顶点的常…...

spring-cloud-alibaba最新版本聚合项目创建

1. 创建聚合项目 修改 pom.xml spring-boot 当前最新版本是 3.4.5 但是 spring-cloud-alibaba 的最新版本是 2023.0.3.2&#xff0c;只适配到 spring-boot 3.2.4 还没有适配到 spring-boot 的 3.4.5 版本。 pom.xml 文件内容如下(可以直接复制)&#xff1a; <?xml vers…...

网络分析/

三、网络分析&#xff08;Network Analysis&#xff09; 网络分析用于解决路径规划、资源分配等问题&#xff0c;广泛应用于交通规划、物流配送、紧急救援等领域。ArcPy 提供了强大的网络分析工具&#xff0c;如 MakeNetworkDataset、Solve 等。 &#xff08;一&#xff09;使用…...

Flutter PIP 插件 ---- 新增PipActivity,Android 11以下支持自动进入PIP Mode

接上文 Flutter PIP 插件 ---- Android 项目地址 PIP&#xff0c; pub.dev也已经同步发布 pip 0.0.3&#xff0c;你的加星和点赞&#xff0c;将是我继续改进最大的动力 开发文档 Add videos using picture-in-picture (PiP)介绍PIP功能从 Android 8.0 (API level 26) 引入&…...

权限提升—Linux提权内核溢出漏洞辅助项目

前言 今天开启Linux提权的篇章&#xff0c;主要是讲一下Linux的内核漏洞提权&#xff0c;利用方式和Windows系统漏洞提权差不多&#xff0c;也是网上的项目扫一下&#xff0c;然后根据漏洞编号去找exp即可。 信息收集 首先要说一下Linux用户的权限划分。 系统用户&#xff…...

超稳定性理论

为了更好的理解后面如何利用超稳定性理论来设计MRACS&#xff0c;本篇先对超稳定性理论做一个介绍。 1、理论介绍 在超稳定性理论中&#xff0c;核心的系统结构如下&#xff1a; 其包含一个线性的前向回路 G ( s ) G(s) G(s)和一个非线性的反馈回路 φ ( v ) \varphi (v) φ…...

治理和管理的区别

治理&#xff08;Governance&#xff09;与管理&#xff08;Management&#xff09;是两个在组织和社会运行中经常被提及的概念&#xff0c;它们虽然在某些方面有相似之处&#xff0c;但在内涵、范围、主体和目标等方面存在显著的区别。以下是它们的主要区别&#xff1a; 一、…...

业务流程BPM能力框架体系及华为中兴流程变革案例P83(83页PPT)(文末有下载方式)

资料解读&#xff1a;《业务流程 BPM 能力框架体系及华为中兴流程变革案例》 详细资料请看本解读文章的最后内容。 该文档围绕业务流程管理&#xff08;BPM&#xff09;能力框架体系展开&#xff0c;先阐述其定义、驱动因素与能力框架&#xff0c;再详细介绍战略规划、流程治理…...

如何通过日志在本地调试LangChain编写的程序?

LangSmith可以记录LangChain程序对LLM的调用&#xff0c;但它需要登陆LangSmith网站才能看到。有什么办法在本地就能看到详细的信息&#xff0c;以方便调试LangChain编写的程序吗&#xff1f; 使用LangChain提供的set_debug(True) 在Python代码中只需要导入set_debug这个方法…...

UE实用地编插件Physical Layout Tool

免费插件 https://www.fab.com/zh-cn/listings/a7fb6fcf-596f-48e9-83cc-f584aea316b1 可以通过物理模拟批量放置物体 不用再一个个摆放了 装饰环境从未如此简单&#xff0c;您不必再考虑对齐物体。 物理地放置物体&#xff0c;移动它们&#xff0c;在移动或在地图上放置物体…...

传感器的精度,灵敏度等概念介绍

文章目录 &#x1f3d4;️ 海拔高度传感器的四个核心指标1. &#x1f3af; **精度&#xff08;Accuracy&#xff09;——“测得的高度准不准”**2. ⚡ **灵敏度&#xff08;Sensitivity&#xff09;——“高度微小变化有没有反应”**3. &#x1f50d; **分辨率&#xff08;Reso…...

前端八股 CSS 1

盒子模型 进行布局时将所有元素表示为一个个盒子box padding margin border content content&#xff1a;盒子内容 待显示的文本和图像 padding&#xff1a;内边距&#xff0c;内容和border之间的空间&#xff0c;不能为负数&#xff0c;受bkc影响 border:边框&#xff0c…...

Transformer架构的解耦重组现象

技术演进图谱与技术成熟度曲线 &#xff08;一&#xff09;架构创新范式迭代 1.1 Transformer架构的解耦重组现象 以2025年Opt模型为例&#xff0c;其通过引入强化学习微调模块实现了传统单层堆叠架构向"感知-推理分离"模式的转型。实验数据显示&#xff0c;该架构…...

【Android】四大组件

目录 1. Activity 2. Service 3. BroadcastReceiver 4. ContentProvider 四大组件各自承担着不同的职责&#xff0c;彼此之间协同工作&#xff0c;共同为用户提供一个流畅的APP体验。 1. Activity 负责展示用户界面&#xff0c;就像App的一个个“页面”&#xff0c;用户通…...

贪心算法精解(Java实现):从理论到实战

一、贪心算法概述 贪心算法&#xff08;Greedy Algorithm&#xff09;是一种在每一步选择中都采取当前状态下最优决策的算法策略。它通过局部最优选择来达到全局最优解&#xff0c;具有高效、简洁的特点。 核心特点&#xff1a; 局部最优选择&#xff1a;每一步都做出当前看…...

基于BERT类的MRPC语义相似度检测(从0到-1系列)

基于BERT类的MRPC语义相似度检测&#xff08;从0到-1系列&#xff09; 介绍 BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;是由Google开发的一种预训练模型&#xff0c;它是一种基于Transformer机制的深度双向模型&#xff0c;可以对…...

mysql-窗口函数一

目录 一、感受一下分组与窗口函数的区别 二、滑动窗口&#xff08;子窗口&#xff09;大小的确认 2.1 分组函数下order by使用 2.2 窗口子句 2.3 执行流程 三、函数使用 窗口函数需要mysql的版本大于等于8才行&#xff0c;可以先检查一下自己的mysql版本是多少 select ve…...

HashMap,高效 哈希

java HashMap 有独特的设计。 哈希表数组的每个位置是一个哈希桶&#xff0c;里面由链表或红黑树实现。&#xff08;> 8 或 < 6 的变化时&#xff0c;避免频繁切换&#xff09; 容量&#xff08;capacity&#xff09;&#xff1a; 哈希表中桶&#xff08;bucket&#xf…...

PyTorch入门------训练图像分类器

前言 1. 操作步骤 2. 数据集 一、公共部分 1.加载并归一化 CIFAR10 2.定义卷积神经网络 二、训练、保存模型参数部分 train_and_save.py 3.定义损失函数和优化器 4.训练网络(使用 CPU 或者 GPU) 5.保存训练好的模型参数 三、加载模型参数、模型推理部分 load_and_infer.py 6…...

DeepSeek V3 架构创新:大规模MoE与辅助损失移除

DeepSeek 团队推出的全新 DeepSeek V3 模型版本,相比之前的 V2 版本,V3 的参数量从两千多亿一跃攀升到 6710 亿,近乎实现了参数规模的三倍增长。如此宏大的模型规模并不只是简单地堆砌参数,而是建立在稀疏混合专家(Mixture-of-Experts,MoE)结构之上。得益于 MoE 的稀疏激…...

MCP 多工具协作链路设计:打造真正的智能工作流

目录 [TOC] &#x1f680; MCP 多工具协作链路设计&#xff1a;打造真正的智能工作流 &#x1f31f; 多工具协作链核心思想 &#x1f6e0;️ 设计示例&#xff1a;智能文档分析系统 &#x1f4d1; 1. MCP Server 定义多工具 list_txt_files.py read_file_content.py su…...

某修改版软件,已突破限制!

聊一聊 现在很多输入法都带有广告。 用着用着&#xff0c;不是提示升级就是弹出资讯。 特别是忙的时候&#xff0c;很影响心情。 今天给大家分享一款干净的输入法软件。 希望能你喜欢。 软件介绍 Q拼音输入法 工具我们下载后&#xff0c;进行安装。 双击打开&#xff0c…...

透视Linux内核:深度剖析Socket机制的本质

在Linux操作系统构建的网络世界里&#xff0c;Socket 宛如纵横交错的交通枢纽&#xff0c;承担着不同应用程序间数据往来的重任。无论是日常浏览网页时&#xff0c;浏览器与 Web 服务器间信息的快速交互&#xff1b;还是畅玩网络游戏过程中&#xff0c;玩家操作指令与游戏服务器…...

PostgreSQL数据表操作SQL

数据表操作 创建表 CREATE TABLE t_test(id SERIAL PRIMARY KEY,name varchar(30),birthday date);修改表名 ALTER TABLE t_test RENAME TO t_test1;添加列 ALTER TABLE t_test1 ADD COLUMN score numeric(5,2);删除列 ALTER TABLE t_test1 DROP COLUMN score;修改数据类型 AL…...

OpenAI最新发布的GPT-4.1系列模型,性能体验如何?

简单来说,这次GPT-4.1的核心思路就是:更实用、更懂开发者、更便宜!OpenAI这次没搞太多花里胡哨的概念,而是实实在在地提升了大家最关心的几个点:写代码、听指令、处理超长文本,而且知识库也更新到了2024年6月。 写代码。要说这次GPT-4.1最亮眼的地方,可能就是写代码这块…...

2025五一数学建模C题完整分析论文(共36页)(含模型、可运行代码、数据)

2025年五一数学建模C题完整分析论文 摘要 一、问题分析 二、问题重述 三、模型假设 四、符号定义 五、 模型建立与求解 5.1问题1 5.1.1问题1思路分析 5.1.2问题1模型建立 5.1.3问题1代码 5.1.4问题1求解结果 5.2问题2 5.2.1问题2思路分析 5.2.2问题…...

Vue2基础速成

一、准备工作 首先下载vue2的JavaScript库&#xff0c;并且命名为vue.min.js 下载链接&#xff1a;https://cdn.jsdelivr.net/npm/vue2&#xff08;若链接失效可去vue官网寻找&#xff09; CTRLS即可下载保存 文件目录结构 二、使用操作原生DOM与使用VUE操作DOM的便捷性比较…...

Java大厂硬核面试:Flink流处理容错、Pomelo JVM调优、MyBatis二级缓存穿透防护与Kubernetes服务网格实战解析

第二幕&#xff1a;系统架构设计 面试官&#xff1a;设计一个处理10万QPS的秒杀系统需要的技术方案和技术选型 xbhog&#xff1a;采用基础架构&#xff1a; 存储层&#xff1a;Redis限流分布式锁服务层&#xff1a;Sentinel流量控制消息层&#xff1a;RocketMQ事务消息保证最…...

Python实现简易博客系统

下面我将介绍如何使用Python实现一个简易的博客系统,包含前后端完整功能。这个系统将使用Flask作为Web框架,SQLite作为数据库,并包含用户认证、文章发布、评论等基本功能。 1. 系统架构设计 技术栈选择 ​​后端​​:Flask (Python Web框架)​​数据库​​:SQLite (轻量…...

【T型三电平仿真】SPWM调制

自然采样法和规则采样法的特点和计算 https://blog.csdn.net/u010632165/article/details/110889621 单极性和双极性的单双体现在什么地方 单极性和双极性的单双是指载波三角波的极性 为什么simulink进行电路仿真时&#xff0c;都需要放置一个powergui模块 任何使用SimPow…...

Astral Ascent 星界战士(星座上升) [DLC 解锁] [Steam] [Windows SteamOS macOS]

Astral Ascent 星界战士&#xff08;星座上升&#xff09; [DLC 解锁] [Steam] [Windows & SteamOS & macOS] 需要有游戏正版基础本体&#xff0c;安装路径不能带有中文&#xff0c;或其它非常规拉丁字符&#xff1b; DLC 版本 至最新全部 DLC 后续可能无法及时更新文章…...

Ubuntu20.04如何优雅的安装ROS 1(胎教级教程)

1、USTC的源&#xff1a; sudo sh -c . /etc/lsb-release && echo "deb http://mirrors.ustc.edu.cn/ros/ubuntu/ lsb_release -cs main" > /etc/apt/sources.list.d/ros-latest.list2、设置的ROS源添加密钥&#xff1a; sudo apt-key adv --keyserver …...