【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【DSP指令加速篇】
【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【DSP指令加速篇】
- 一、前文回顾
- 二、CMSIS-NN简介
- 2.1 为什么介绍CMSIS-NN?
- 2.2 CMSIS-NN是什么?
- 2.3 CMSIS-NN核心特性
- 2.4 CMSIS-NN算子支持
- 三、TFLM+CMSIS-NN集成
- 3.1 包含TFLM的STM32项目
- 3.2 理解TFLM中CMSIS-NN相关构建规则
- 3.3 理解TFLM中CMSIS-NN相关算子实现
- 3.4 集成CMSIS-NN方式1——作为TFLM的一部分
- 3.5 集成CMSIS-NN方式2——作为独立的三方库
- 四、TFLM+CMSIS-NN测试
- 4.1 编译源代码
- 4.2 下载Boot代码
- 4.3 下载Appli代码
- 4.4 运行TFLM基准测试
- 五、问题解决
- 5.1 specialize_files.py 输入不支持CMake列表参数问题
- 5.2 specialize_files.py 输出的路径分隔符不一致问题
- 5.3 specialize_files.py 输出和CMake列表格式不一致问题
- 5.4 specialize_files.py 输出的最后一个文件无法找到
- 六、项目源码
- 七、参考链接
本文介绍了如何通过移植CMSIS-NN库并调整TensorFlow Lite for Microcontrollers (TFLM) 的构建配置,实现在STM32微控制器上利用DSP指令集加速TensorFlow Lite模型的推理过程。通过这一方法,我们能够有效地提升基于ARM Cortex-M系列MCU上运行深度学习模型的性能。文章首先介绍了CMSIS-NN库的基本概念及其在神经网络加速中的作用,随后详细阐述了移植库到STM32平台的步骤。接着,文章深入讲解了如何修改TFLM的构建规则,实现调用CMSIS-NN库实现TensorFlow算子。最后,通过实验验证了该方法在提高模型推理速度方面的显著效果,使用CMSIS-NN实现DSP加速后的人脸检测模型推理速度接近原来的3.5倍。
本系列博文目录:
- 【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【上篇】 (背景介绍、初步体验、框架移植)
- 【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【下篇】 (平台适配、编译集成、基准测试)
- 【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【DSP指令加速篇】 (CMSIS-NN简介、TFLM+CMSIS-NN集成、TFLM+CMSIS-NN测试)
一、前文回顾
此系列前面已经发布了两篇:
-
【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【上篇】
-
【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【下篇】
【上篇】介绍了TensorFlow、TensorFlow Lite、TensorFlow Lite for Microcontrollers(TFLM)是什么,如何下载TFLM源码,如何在个人电脑(PC)上体验运行TFLM基准测试。同时,分析了TFLM的部分Makefile源码分析。最后,介绍了如何移植TFLM的主体代码。
【下篇】介绍了如何准备STM32 CubeMX项目(以便于后续的TFLM可以顺利移植),如何将TFLM源码集成到STM32 CubeMX生成的项目中去,以及如何在STM32项目中运行TFLM基准测试。同时,介绍了过程中遇到的问题,以及解决方法。最后,给出了整个项目的完整可运行源代码。
二、CMSIS-NN简介
2.1 为什么介绍CMSIS-NN?
因为TFLM源码中有针对CMSIS-NN的算子适配层,通过该适配层可以实现将TensorFlow Lite模型的推理计算转化为对CMSIS-NN库的调用。
同时,CMSIS-NN底层支持DSP指令和MVE指令,在Cortex-M4、Cortex-M7、Cortex-M33上可以实现DSP指令加速计算,在Cortex-M55、Cortex-M85上可以实现MVE加速计算。
简言之,TFLM默认的算子实现为纯CPU计算,而CMSIS-NN可以作为TFLM的后端,实现部分处理器上的DSP和MVE加速计算。
2.2 CMSIS-NN是什么?
CMSIS-NN是什么?官方的解释是:
CMSIS NN 软件库是一组高效的神经网络核(函数),旨在最大限度地提高 Arm Cortex-M 处理器上神经网络的性能并最大限度地减少内存占用。
CMSIS-NN是一个计算库,它向上提供了神经网络(NN)计算接口,实现了神经网络计算的硬件加速。它内部实现了纯CPU计算、DSP计算、MVE计算,屏蔽了底层硬件的具体细节,降低了编程难度。
2.3 CMSIS-NN核心特性
总结一下官方的介绍,可以知道CMSIS-NN库的核心特性:
-
专为Cortex-M处理器开发;
-
神经网络计算函数;
-
最大化性能;
-
最小化内存占用;
-
CMSIS-NN的硬件和软件支持
2.4 CMSIS-NN算子支持
在CMSIS-NN源码仓首页,可以看到CMSIS-NN库提供了三种算子实现,分别为:
- 纯C,CMSIS-NN提供了所有算子的纯C实现,用于像Cortex-M0和Cortex-M3这样的处理器;
- DSP扩展,在支持DSP扩展的处理器上,可以使用DSP指令加速计算,例如Cortex-M4或Cortex-M7;
- MVE扩展,在支持ARM Helium技术的处理器上,可以使用MVE指令加速计算,例如 Cortex-M55 或 Cortex-M85;
三、TFLM+CMSIS-NN集成
接下来,我将介绍如何将TFLM和CMSIS-NN集成到STM32项目中。
3.1 包含TFLM的STM32项目
前面的文章中,我们已经知道了如何将TFLM集成到STM32项目中,本文将以上一篇文章的代码为基础,继续进行CMSIS-NN的集成和测试。
基础项目代码仓链接:
https://gitcode.com/xusiwei1236/STM32H7S78-DK-TFLM
这个代码仓就是——已经包含了TFLM的STM32项目。
3.2 理解TFLM中CMSIS-NN相关构建规则
TFLM的构建规则Makefile文件中,和CMSIS-NN相关的主要代码片段为:
这段代码中,比较重要的有两处,分别为:
- 649行,CMSIS-NN对应的
OPTIMIZED_KERNEL_DIR
变量值为cmsis_nn
,此时会包含cmsis_nn.inc
构建规则文件; - 651到653行,调用
specialize_files.py
脚本,用于将算子实现源文件列表MICROLITE_CC_KERNEL_SRCS
中的部分文件替换为CMSIS-NN适配源文件列表;
cmsis_nn.inc
文件内容如下:
这段代码中,可以看到TFLM支持两种方式和CMSIS-NN集成:
- CMSIS-NN作为独立的三方库,链接到一起;
- CMSIS-NN作为TFLM的一部分,编译到一起;
specialize_files.py
文件源码如下:
该文件实现了:
- 遍历
base_files
列表中的条目,检查在specialized_directory
目录下是否存在和它的基础文件名(basename)相同的文件; - 如果存在,则使用
specialized_directory
目录下的替换掉base_files
中的这一条; - 否则,保持原来位于
base_files
中的这一条不变!
3.3 理解TFLM中CMSIS-NN相关算子实现
对于CMSIS-NN,实际运行时的specialized_directory
指定的参数值是tensorflow/lite/micro/kernels/cmsis_nn
子目录。
该目录下包含的文件如下:
实际执行specialize_files.py
脚本时,实际的替换文件的对应关系如下:
默认算子文件 | CMSIS-NN算子文件 |
---|---|
tensorflow/lite/micro/kernels/add.cc | tensorflow/lite/micro/kernels/cmsis_nn/add.cc |
tensorflow/lite/micro/kernels/batch_matmul.cc | tensorflow/lite/micro/kernels/cmsis_nn/batch_matmul.cc |
tensorflow/lite/micro/kernels/conv.cc | tensorflow/lite/micro/kernels/cmsis_nn/conv.cc |
tensorflow/lite/micro/kernels/depthwise_conv.cc | tensorflow/lite/micro/kernels/cmsis_nn/depthwise_conv.cc |
tensorflow/lite/micro/kernels/fully_connected.cc | tensorflow/lite/micro/kernels/cmsis_nn/fully_connected.cc |
tensorflow/lite/micro/kernels/mul.cc | tensorflow/lite/micro/kernels/cmsis_nn/mul.cc |
tensorflow/lite/micro/kernels/pooling.cc | tensorflow/lite/micro/kernels/cmsis_nn/pooling.cc |
tensorflow/lite/micro/kernels/softmax.cc | tensorflow/lite/micro/kernels/cmsis_nn/softmax.cc |
tensorflow/lite/micro/kernels/svdf.cc | tensorflow/lite/micro/kernels/cmsis_nn/svdf.cc |
tensorflow/lite/micro/kernels/transpose_conv.cc | tensorflow/lite/micro/kernels/cmsis_nn/transpose_conv.cc |
tensorflow/lite/micro/kernels/unidirectional_sequence_lstm.cc | tensorflow/lite/micro/kernels/cmsis_nn/unidirectional_sequence_lstm.cc |
这里以第一行add.cc
为例,默认的算子实现主体代码为:
CMSIS-NN版本的add.cc
代码主体代码为:
都提供了Register_ADD()
函数,用于注册ADD
算子。
3.4 集成CMSIS-NN方式1——作为TFLM的一部分
理解了前面的Makefile代码,就可以编写CMake构建规则,从而实现在STM32项目中集成TFLM和CMSIS-NN。
前文提到,STM32项目集成CMSIS-NN有两种方式,分别为:
- CMSIS-NN作为TFLM的一部分,编译到TFLM的静态库(libtflite-micro.a)文件中;
- CMSIS-NN作为独立的三方库,链接到STM32的可执行程序(.elf)文件中;
首先,介绍第一种方式,也就是CMSIS-NN作为TFLM的一部分;这种方式Appli子项目不直接依赖CMSIS-NN库,无需修改,更易于理解。
基于对Makefile源码的理解,修改tflite-micro目录的CMakeLists.txt文件内容:
这段修改中包含了cmsis-nn.cmake
,cmsis-nn.cmake
文件的内容为:
整个修改实现了:
- 调用
specialize_files.py
脚本,将MICROLITE_KERNEL_CC_SRCS
中的部分算子文件路径替换为cmsis_nn
目录内的,实现了CMSIS-NN适配层的编译; - 将
cmsis-nn.cmake
中匹配到的CMSIS-NN源文件,添加到TFLM库的源文件列表中,实现了CMSIS-NN代码的编译,并作为TFLM库的一部分;
这样修改之后,重新编译生成的libtflite-micro.a
中就包含了CMSIS-NN的代码,以及基于CMSIS-NN的TensorFlow算子实现。
3.5 集成CMSIS-NN方式2——作为独立的三方库
另外一种集成CMSIS-NN的方式是,CMSIS-NN作为独立的三方库,最终连接到整个项目的可执行文件(.elf)中。
要实现这种继承方式,需要在刚修改的TFLM的CMakeLists.txt的基础上进行修改:
一共修改两处:
add_library
代码片段,删除CMSIS-NN
相关的代码文件;- 文件末尾添加
add_subdirectory(tensorflow/lite/micro/tools/make/downloads/cmsis_nn)
,让CMSIS-NN的CMakeLists.txt
被包含到整个项目中;
除此之外,还需要修改Appli目录的CMakeLists.txt文件,具体修改内容如下图:
一共修改了三处:
- 新增了
TF_CMSIS_NN_DIR
变量定义,用于记录cmsis_nn
源码所在子目录; target_link_directories
下,增加一行,指定CMSIS-NN库文件生成的目录;target_link_libraries
下,增加一行,指定链接cmsis-nn
库;
以上这种修改方式,也可以实现将TFLM和CMSIS-NN集成到STM32项目中。
四、TFLM+CMSIS-NN测试
4.1 编译源代码
第一种方式集成CMSIS-NN,由于上层代码不依赖CMSIS-NN库,即不新增库依赖;因此,其编译方式和此前的文章方式一样,这里不在介绍。
这里仅介绍第二种方式集成CMSIS-NN的编译方法,分为如下几步:
-
清理输出目录,如下图操作:
-
编译
tflite-micro
库,如下图操作: -
编译
xxx_benchmark
库,如下图操作: -
编译
cmsis-nn
库,如下图操作: -
编译
Appli
目标,如下图操作: -
编译
Boot
代码,如下图所示:
4.2 下载Boot代码
由于Appli代码需要使用Boot
代码进行跳转,因此,下载Appli代码之前,需要先将Boot代码下载到开发板上。
下载之前,先将STM32H7S78-DK开发板和PC通过USB线连接好,板子由三个USB口,注意连接到标有STLK
的。
下载Boot代码,按照如下图所示操作:
执行过程中终端子窗口会输出进度等信息:
4.3 下载Appli代码
下载Appli代码,按照如下图操作:
执行过程中终端子窗口会输出进度等信息:
4.4 运行TFLM基准测试
打开MobaXterm,添加会话,选择STLink的虚拟串口设备,参数如下:
连接设备之后,按下开发板上的NRST
按钮,重启设备,可以看到串口输出如下:
可以看到,开发板上,运行有人图像的人体检测耗时为286毫秒,没有人的耗时为286毫秒;连续运行10次的耗时分别为2863毫秒和2863毫秒,速度有点慢。
和上一篇文章的数据对比如下:
测试项目 | TFLM | TFLM+CMSIS-NN |
---|---|---|
WithPersonDataIterations(1) | 993 | 286 |
NoPersonDataIterations(1) | 994 | 286 |
NoPersonDataIterations(10) | 9938 | 2863 |
NoPersonDataIterations(10) | 9940 | 2863 |
五、问题解决
第三章、第四章实际过程中遇到了一些问题,为了保持前文逻辑连贯,没有在前面记录,本章将记录具体问题及解决方法。
5.1 specialize_files.py 输入不支持CMake列表参数问题
【问题现象】specialize_files.py脚本输出和输入参数base_files
的值完全一样。
【问题原因】specialize_files.py脚本使用Python的string.split
对参数base_files
的值进行分隔,要求值是空白字符(空格、TAB、换行等)分隔的。而CMake的列表字符串是分号分隔的。
【解决方法】将MICROLITE_CC_KERNEL_SRCS
中的分隔符替换为空格,再将其传给specialize_files.py脚本,具体代码为:
5.2 specialize_files.py 输出的路径分隔符不一致问题
【问题现象】specialize_files.py 输出的路径分隔符不一致,有正斜杠也有反斜杠,导致后续报错——文件找不到。
【问题原因】CMake代码使用的路径分隔符是正斜杠,specialize_files.py代码里面使用的是os.path.sep
,在Windows上是反斜杠。
【解决方法】将反斜杠全部替换为正斜杠。
5.3 specialize_files.py 输出和CMake列表格式不一致问题
【问题现象】specialize_files.py 输出的文件列表是空格分隔的,和CMake列表格式不一致。
【问题原因】specialize_files.py 使用空格拼接文件列表为一个字符串之后输出,而CMake列表需要用使用分号分隔。
【解决方法】将字符串中的空格替换为分号。
5.4 specialize_files.py 输出的最后一个文件无法找到
【问题现象】specialize_files.py 输出的文件列表的最后一个文件,后续CMake代码提示该文件找不到。
【问题原因】乍看起来文件路径是对的,能够找到;实际将该文件路径字符串加上双引号输出之后,发现末尾多了一个换行符。
【解决方法】去除末尾的空白字符。
六、项目源码
如需本文修改后项目源码的,请在评论区留言。我将会在留言超过10条,或本文阅读量超过1200之后,将本文修改的最终源码全部开源。
当然,动手能力强的读者,也可以根据文章描述的步骤,一步步修改得到最终版本的源码。
七、参考链接
- TensorFlow Lite for Microcontrollers介绍: TensorFlow Lite for Microcontrollers (google.cn)
- TensorFlow Lite for Microcontrollers入门: 微控制器入门 | TensorFlow (google.cn)
- tflite-micro 源码仓: https://github.com/tensorflow/tflite-micro
- CMake最新文档: CMake Reference Documentation — CMake 3.30.3 Documentation
- CMSIS-NN在线文档: CMSIS-NN: CMSIS NN Software Library (arm-software.github.io)
- CMSIS-NN 源码仓: https://github.com/ARM-software/CMSIS-NN
相关文章:
【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【DSP指令加速篇】
【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【DSP指令加速篇】 一、前文回顾二、CMSIS-NN简介2.1 为什么介绍CMSIS-NN?2.2 CMSIS-NN是什么?2.3 CMSIS-NN核心特性2.4 CMSIS-NN算子支持 三、TFLMCMSIS-NN集成3.1 包含TFLM的STM32项目3.2 理解TFLM…...
Python中如何判断一串文本是不是数字
目录 1. 内置函数2. 尝试类型转换3. 正则表达式 在编程中,我们经常需要确定一段文本是否为数字。 这不仅关系到数据的准确性,还涉及到后续的计算和处理。 1. 内置函数 在Python中,可以使用str.isdigit()、str.isnumeric()和str.isdecimal()…...
基于YOLOv8深度学习的智慧农业山羊行为检测系统研究与实现(PyQt5界面+数据集+训练代码)
随着智慧农业的快速发展,利用先进的技术手段对牲畜的行为进行自动化监测和管理,已经成为现代农业中的重要研究方向之一。在传统的农业管理模式中,牲畜的行为监测通常依赖于人工观测,耗时耗力且难以实现大规模实时监控。然而&#…...
Redis环境部署(主从模式、哨兵模式、集群模式)
一、概述 REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库…...
高阶C语言之六:程序环境和预处理
本文介绍程序的环境,在Linux下对编译链接理解,较为简短,着重在于编译的步骤。 C的环境 在ANSI C(标准C语言)的任何一种实现中,存在两个不同的环境。 翻译环境:在这个环境中,源代码…...
Vue 3 国际化 (i18n) 最佳实践指南
1. 安装依赖 npm install vue-i18n@9 2. 项目结构建议 src/ ├── i18n/ │ ├── index.ts # i18n 配置文件 │ ├── languages/ # 语言文件目录 │ │ ├── zh-CN.ts # 中文 │ │ ├── en-US.ts # 英文 │ │ └─…...
Acme PHP - Let‘s Encrypt
Lets Encrypt是一个于2015年三季度推出的数字证书认证机构,旨在以自动化流程消除手动创建和安装证书的复杂流程,并推广使万维网服务器的加密连接无所不在,为安全网站提供免费的SSL/TLS证书。 使用PHP来更新证书: Acme PHP | Rob…...
获取DOM 节点的四大方式
前言: 在 Vue 中,获取 DOM 节点可以通过多种方式,如自定义属性、ref 引用、类选择器和 ID 选择器等。 一、使用 ref 获取 DOM 实例 ref 是 Vue 中推荐的获取 DOM 节点的方式,它为每个节点分配一个唯一的引用,可以直…...
ROS2 Humble 机器人建模和Gazebo仿真
一.Ubuntu22.04系统虚拟机安装 1.下载镜像并安装 Index of /ubuntu-releases/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 2.安装选英文版,安装类型选清除磁盘。 3.遇到无法复制windows内容到虚拟机里。需安装VMware tools。VMware tools安装不了&a…...
docker容器镜像的制作、使用以及传递
目录 制作容器镜像使用Dockerfile制作镜像准备所需文件构建镜像怎么不使用基础镜像来构建容器镜像 使用容器镜像传递容器镜像 这篇文章讨论一下怎么使用docker制作容器镜像,容器镜像的使用,以及怎么传递容器镜像。 制作容器镜像 docker制作容器镜像推荐…...
一种由于吸入硅酸盐粉尘而引起的肺部疾病:pneumonoultramicroscopicsilicovolcanoconiosis
有人说,pneumonoultramicroscopicsilicovolcanoconiosis是英语中最长的单词,这是一个医学词汇,意思是指:一种由于吸入硅酸盐粉尘而引起的肺部疾病。 pneumonoultramicroscopicsilicovolcanoconiosis [ˈnju:mənəuˌʌltrəˌmai…...
百度AI人脸检测与对比
1.注册账号 打开网站 https://ai.baidu.com/ ,注册百度账号并登录 2.创建应用 3.技术文档 https://ai.baidu.com/ai-doc/FACE/yk37c1u4t 4.Spring Boot简单集成测试 pom.xml 配置: <!--百度AI--> <dependency> <groupId>com.baidu.…...
贴代码框架PasteForm特性介绍之outer,outers,object,objects,outerdisplay
简介 PasteForm是贴代码推出的 “新一代CRUD” ,基于ABPvNext,目的是通过对Dto的特性的标注,从而实现管理端的统一UI,借助于配套的PasteBuilder代码生成器,你可以快速的为自己的项目构建后台管理端!目前管…...
sql数据库-权限控制-DCL
目录 常用权限类别 查询用户权限 举例 授予用户权限 删除权限 常用权限类别 权限说明ALL,ALL PRIVILEGES所有权限SELECT查询数据INSERT插入数据UPDATE修改数据DELETE删除数据ALTER修改表DROP删除数据库/表/视图CREATE创建数据库/表 查询用户权限 show grants for 用户名…...
【计组笔记】目录
【计组笔记】机器数表示及运算https://blog.csdn.net/Resurgence03/article/details/142673325?sharetypeblog&shareId142673325&sharereferAPP&sharesourceresurgence03&sharefromlink 【计组笔记】指令系统https://blog.csdn.net/Resurgence03/article/det…...
深度学习中的Pixel Shuffle和Pixel Unshuffle:图像超分辨率的秘密武器
在深度学习的计算机视觉任务中,提升图像分辨率和压缩特征图是重要需求。Pixel Shuffle和Pixel Unshuffle是在超分辨率、图像生成等任务中常用的操作,能够通过转换空间维度和通道维度来优化图像特征表示。本篇文章将深入介绍这两种操作的原理,…...
AntFlow 0.11.0版发布,增加springboot starter模块,一款设计上借鉴钉钉工作流的免费企业级审批流平台
AntFlow 0.11.0版发布,增加springboot starter模块,一款设计上借鉴钉钉工作流的免费企业级审批流平台 传统老牌工作流引擎比如activiti,flowable或者camunda等虽然功能强大,也被企业广泛采用,然后也存着在诸如学习曲线陡峭,上手难度大&#x…...
golang操作mysql基础驱动github.com/go-sql-driver/mysql使用
golang中类似java操作mysql的jdbc一样,github.com/go-sql-driver/mysql也为go提供了基础接口,在开发中往往需要写更多的代码来满足自己的定制需求,java在驱动基础上有了扩展,orm框架诞生,mybatis、jpa等都是好用的扩展…...
正则表达式完全指南,总结全面通俗易懂
目录 元字符 连接符 限定符 定位符 修饰符(标记) 运算符优先级 普通字符集及其替换 零宽断言 正向先行断言 负向先行断言 正向后发断言 负向后发断言 捕获组 普通捕获组 命名捕获组 PS:非捕获组 正则表达式在线测试: 正则在线测试工具 …...
运维面试题.云计算面试题之三ELK
1.ELK是什么? ELK 其实并不是一款软件,而是一整套解决方案,是三个软件产品的首字母缩写 Elasticsearch:负责日志检索和储存 Logstash:负责日志的收集和分析、处理 Kibana:负责日志的可视化 这三款软件都是开源软件,通常是配合使用,而且又先后归于 Elastic.co 公司名下,…...
C# DataTable使用Linq查询详解
前奏- C# 对DataTable进行查询 C# 可以对 DataTable 进行查询。在 .NET 框架中,DataTable 类提供了几种方法来查询数据,包括 Select 方法和 AsEnumerable 扩展方法(在 System.Data.DataSetExtensions 命名空间中)。 使用 Select…...
【企业级分布式系统】ELK优化
文章目录 Elasticsearch作为日志存储时的优化优化ES索引设置优化线程池配置锁定内存,不让JVM使用Swap减少分片数、副本数 Elasticsearch作为日志存储时的优化 linux内核优化、JVM优化、ES配置优化、架构优化(filebeat/fluentd代替logstash、加入kafka做…...
51单片机基础05 定时器
目录 一、为什么要定时器 二、定时器中断 1、定时器中断参数 2、定时器中断程序 3、定时器计数 一、为什么要定时器 前文提到,比如进行流水灯等操作,都是直接写了delay_ms这类操作。 但是在51单片机中,其一般就是靠双for进行的循环时延&…...
tdengine学习笔记实战-jdbc连接tdengine数据库
先上代码,里面有两种获取连接的方式,一个单例,一个连接池 package com.tdengine.utils;import com.alibaba.druid.pool.DruidDataSource;import java.sql.*; import java.util.Properties;public class TDConnectUtils {// 单例对象private …...
vue3项目执行npm install下载依赖报错问题排查方法
1、检查当前node与npm的版本 nodejs 和 npm 的版本是有适配的,具体可以看官网:nodejs 和 npm 的版本是有适配的 若是版本不兼容,修改node或者npm的版本即可,建议使用nvm版本管理工具,切换方便; 2、清除缓…...
【vue】项目迭代部署后 自动清除浏览器缓存
前言: vue项目打包部署上线后,因浏览器缓存问题,导致用户访问的依旧是上个迭代批次的旧资源,需要用户手动清除缓存才能更新至最新版本,影响用户体验。 解决方法: html根文件添加以下标签 <meta http-eq…...
Leetcode(滑动窗口习题思路总结,持续更新。。。)
讲解题目:长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 target ,找出该数组中满足其和 ≥ target 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。示例: 输入: target 7, nums [2,3,1,2,4,3] 输出: 2 解…...
【UNIAPP】uniapp版图片压缩工具
二次封装的uniapp版本图片压缩、上传工具,支持全端(H5、小程序、APP) 新建文件:file-util.js class FileUtil {/*** [文件上传]* param {[object]} fileObj [图片地址]* param {[object]} formData [参数]* param {[str…...
PaddlePaddle 开源产业级文档印章识别PaddleX-Pipeline “seal_recognition”模型 开箱即用篇(一)
AI时代到来,各行各业都在追求细分领域垂直类深度学习模型,今天给大家介绍一个PaddlePaddle旗下,基于PaddleX Pipeline 来完成印章识别的模型“seal_recognition”。 官方地址:https://github.com/PaddlePaddle/PaddleX/blob/relea…...
Vue3 + Vite 项目引入 Typescript
文章目录 一、TypeScript简介二、TypeScript 开发环境搭建三、编译方式1. 自动编译单个文件2. 自动编译整个项目 四、配置文件1. compilerOptions基本选项严格模式相关选项(启用 strict 后自动包含这些)模块与导入相关选项 2. include 和 excludeinclude…...
自己做网站步骤/游戏推广公司怎么接游戏的
ArcGIS Server 是功能强大的基于服务器的 GIS 产品,用于构建集中管理的、支持多用户的、具备高级GIS功能的企业级GIS应用与服务,如:空间数据管理、二维三维地图可视化、数据编辑、空间分析等即拿即用的应用和类型丰富的服务。ArcGIS Server 是…...
找人一起做素材网站/谷歌推广开户多少费用
这两天老大让我写一个让照片翻转的效果,甚是痛苦,下面是我的一些个人心得 在W3C官方的标准里,通过transform属性使对象旋转的写法如下:transform: rotate(40deg); /* 其中40是旋转的角度 */ 可是由于目前几乎所有的浏览器对这个属…...
seo推广网站有哪/高报师培训机构排名
今天学习了几个命令,是创建、删除文件和文件夹的,在linux里,文件夹是目录,下面说下我学习的命令。 创建文件夹【mkdir】 一、mkdir命令使用权限 所有用户都可以在终端使用 mkdir 命令在拥有权限的文件夹创建文件夹或目录。 二、mkdir命令使用格式 格式:mkdir [选项] DirN…...
win10做的网站其他电脑访问不了/现在有什么推广平台
上下文 上下文:相当于一个容器,保存了 Flask 程序运行过程中的一些信息。 Flask中有两种上下文,请求上下文和应用上下文 请求上下文(request context) 思考:在视图函数中,如何取到当前请求的相关数据?比如&…...
网站logo优化/小程序推广50个方法
JLabel的使用: 类层次结构图: java.lang.Object--java.awt.Component--java.awt.Container--javax.swing.JComponent--javax.swing.JLabel 在以前的许多范例,我们已经使用过JLabel这个组件,相信大家对此组件应该不会感到陌生…...
政府门户网站集约化建设会/百度网盘网页
爱一个人难道有错吗? 我不知道。 本以为自己可以忘记 本以为自己可以勇敢的面对 本以为我可以不在乎对你的感受 本以为我可以战胜自己 但是 渐渐的 我发现 原来我不能! 我真的不能做到!~ 是我太软弱,还是我太脆弱? 不&…...