ESP32学习笔记_FreeRTOS(3)——SoftwareTimer
摘要(From AI):
这篇笔记全面介绍了 FreeRTOS 软件定时器的核心概念和使用方法,包括定时器的创建、管理、常用 API 和辅助函数,并通过示例代码演示了如何启动、重置和更改定时器的周期。它强调了软件定时器的灵活性、平台无关性以及与硬件定时器的对比
前言:本文档是本人在依照B站UP:Michael_ee的视频教程进行学习时所做的学习笔记,可能存在疏漏和错误,如有发现,望指正。
上一篇:ESP32学习笔记_FreeRTOS(2)——Queue
文章目录
- Software Timer
- Creating a Software Timer
- xTimerCreate()
- Managing Software Timers
- xTimerStart()
- xTimerStop()
- pcTimerGetName()
- pvTimerGetTimerID()
- xTimerReset()
- xTimerChangePeriod()
- Example Code:Using Software Timers
参考资料:
[Michael_ee视频教程] https://www.bilibili.com/video/BV1Nb4y1q7xz?spm_id_from=333.788.videopod.sections&vd_source=4d8bd0ed3878ef81b239bf69bf38e741
freeRTOS官网
espressif 在线文档
Software Timer
硬件定时器会有数量等方面的限制,使用较不灵活,而软件定时器使用更为灵活,其与硬件、平台无关,在不同的 MCU 都可以使用 FreeRTOS API 进行调用
特性 | 硬件定时器 | 软件定时器 |
---|---|---|
数量 | 固定,受 MCU 硬件资源限制(通常只有几个) | 灵活,可以根据需要动态创建(受内存和任务管理能力限制) |
依赖性 | 依赖具体硬件平台,配置方式和功能因芯片而异 | 与硬件平台无关,可通过 FreeRTOS API 在不同 MCU 上使用 |
精度 | 高精度,直接由硬件计时,通常用于实时性要求高的场景 | 精度依赖于 RTOS 的调度周期(tick 周期),不适合极高实时性场景 |
性能 | 高性能,独立运行,不占用 CPU 资源 | 运行在 RTOS 守护任务上下文中,占用 CPU 资源 |
适用场景 | 适合时间敏感的应用,如 PWM 信号生成、脉冲捕获、输入输出事件计时等 | 适合通用定时功能,如定时任务执行、软件超时处理等 |
灵活性 | 配置固定,功能和用途受限 | 灵活性高,可动态调整超时时间、回调函数等 |
使用复杂度 | 配置复杂,需根据芯片手册手动设置寄存器 | 使用方便,通过 FreeRTOS API 调用 |
移植性 | 差,代码与硬件平台强耦合 | 好,代码与硬件无关,便于跨平台移植 |
所有软件定时器的回调函数都在同一个RTOS守护任务(也称为“定时器服务任务”)的上下文中执行(该任务最初被称为“定时器服务任务”,因为最初它只用于执行软件定时器回调函数。现在同一任务也用于其他用途,因此被改名为更通用的“RTOS 守护任务”)
守护任务是一个标准的FreeRTOS任务,会在调度器启动时自动创建。其优先级和堆栈大小由编译时配置常量configTIMER_TASK_PRIORITY
和configTIMER_TASK_STACK_DEPTH
分别设置,这两个常量在FreeRTOSConfig.h
中定义
需要注意,软件定时器的回调函数是在 RTOS 守护任务的上下文中执行的,而不是在独立的任务中运行。因此,回调函数中不能调用可能使任务进入阻塞状态的 FreeRTOS API 函数,因为这会阻塞整个守护任务,导致系统运行异常
Creating a Software Timer
xTimerCreate()
xTimerCreate()
用于创建一个新的软件定时器,并返回一个句柄以引用创建的定时器
#include “FreeRTOS.h”
#include “timers.h”TimerHandle_t xTimerCreate( const char *pcTimerName,const TickType_t xTimerPeriod,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction );
参数
pcTimerName
定时器的名称,仅用于调试xTimerPeriod定时器周期,单位为系统 tick,不能为 0。可以使用
pdMS_TO_TICKS()` 宏将毫秒转换为 tick。例如:- 100 tick直接设置为 100
- 500ms可使用
pdMS_TO_TICKS(500)
,前提是configTICK_RATE_HZ <= 1000
uxAutoReload
设置定时器类型:pdTRUE
自动重载定时器(周期性触发)pdFALSE
一次性定时器(仅触发一次,可手动重新启动)
pvTimerID
定时器标识符,用于在回调函数中区分不同的定时器,或在回调调用之间存储值pxCallbackFunction
:定时器到期时执行的回调函数,需符合TimerCallbackFunction_t
原型:
void vCallbackFunctionExample(TimerHandle_t xTimer);
configTICK_RATE_HZ
是 FreeRTOS 配置文件FreeRTOSConfig.h
中定义的一个宏,它表示 每秒系统 Tick 的次数,即 FreeRTOS 的调度器每秒中断的频率(单位为 Hz)
例如:
如果configTICK_RATE_HZ = 1000
,表示系统每 1 毫秒触发一次 Tick 中断
如果configTICK_RATE_HZ = 100
,表示系统每 10 毫秒触发一次 Tick 中断
返回值:
NULL
定时器创建失败,原因可能是 FreeRTOS 堆内存不足其他值
定时器创建成功,返回的句柄可用于引用该定时器
配置要求(一般不用动)
- 在
FreeRTOSConfig.h
文件中,configUSE_TIMERS
和configSUPPORT_DYNAMIC_ALLOCATION
必须都设置为1
- 如果
configSUPPORT_DYNAMIC_ALLOCATION
未定义,其默认值为1
创建定时器并不会立即启动。可以使用以下函数来启动或管理定时器
// 启动定时器。如果定时器已经在运行,则从当前时间重新开始。
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );// 重置(重新启动)定时器。确保定时器启动或重新计算到期时间。
BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );// 从中断上下文启动定时器。等效于 xTimerStart(),用于中断中调用。
BaseType_t xTimerStartFromISR( TimerHandle_t xTimer,BaseType_t *pxHigherPriorityTaskWoken );// 从中断上下文重置(重新启动)定时器。等效于 xTimerReset(),用于中断中调用。
BaseType_t xTimerResetFromISR( TimerHandle_t xTimer,BaseType_t *pxHigherPriorityTaskWoken );// 更改定时器的周期。如果定时器未运行,则会启动定时器。
BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,TickType_t xNewPeriod,TickType_t xTicksToWait );// 从中断上下文更改定时器的周期。等效于 xTimerChangePeriod(),用于中断中调用。
BaseType_t xTimerChangePeriodFromISR( TimerHandle_t xTimer,TickType_t xNewPeriod,BaseType_t *pxHigherPriorityTaskWoken );
Managing Software Timers
xTimerStart()
xTimerStart() 用于启动一个软件定时器的运行
- 如果定时器尚未运行,
xTimerStart()
会计算一个到期时间,该时间相对于调用xTimerStart()
的时刻 - 如果定时器已经在运行,则
xTimerStart()
相当于调用了xTimerReset()
,即重置定时器 - 定时器会在定义的周期后(即
xTimerStart()
调用后n
个 tick)触发回调函数,除非定时器在此期间被停止、删除或重置
#include “FreeRTOS.h”
#include “timers.h”BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );
参数
xTimer
:要启动、重置或重新启动的定时器句柄xTicksToWait
指定调用任务在timer command queue
队列已满的情况下,等待空间可用的最大时间(单位为 tick)。这是任务在进入 Blocked 状态时的阻塞时间。如果队列已满,任务会被阻塞,直到有足够的空间来发送命令- 设置
xTicksToWait
为portMAX_DELAY
将导致任务无限期等待,直到队列中有空间 - 如果在调度器启动之前调用
xTimerStart()
,则xTicksToWait
会被忽略
- 设置
当任务调用
xTimerStart()
或其他定时器相关 API 时,这些命令并不会立即由任务执行,而是通过一个队列传递给定时器服务任务
如果队列已满,新的命令会被阻塞,直到队列有空间可用。这时,调用xTimerStart()
等 API 的任务会根据指定的阻塞时间(xTicksToWait
)进入阻塞状态,等待队列空间变得可用
timer command queue
的大小由 FreeRTOS 的配置项决定。队列的大小设置影响系统可以同时处理多少个定时器命令。如果队列大小太小,可能会导致命令丢失或任务阻塞:
configTIMER_QUEUE_LENGTH
:定义了timer command queue
队列的最大长度(即可以存放多少个定时器命令)
configUSE_TIMERS
:必须设置为 1,才能启用定时器功能和相关队列
返回值
pdPASS
启动命令成功发送到定时器命令队列。如果指定了阻塞时间(即xTicksToWait
不为零),则可能会因为队列已满,任务进入阻塞状态等待空间释放,直到数据成功写入队列- 定时器命令的处理时间会根据定时器服务任务的优先级而有所不同,但定时器的到期时间是相对于实际调用
xTimerStart()
时刻(从队列中取出命令并实际启动定时器)的 - 定时器命令的处理时间受定时器服务任务优先级的影响,定时器服务任务的优先级由
configTIMER_TASK_PRIORITY
配置常量设置
- 定时器命令的处理时间会根据定时器服务任务的优先级而有所不同,但定时器的到期时间是相对于实际调用
pdFAIL
启动命令未成功发送到定时器命令队列,原因是队列已满。如果指定了阻塞时间,任务会被阻塞等待队列有空间,直到指定的阻塞时间过期,但仍未成功写入数据到队列
注意事项(一般不用动)
在 FreeRTOSConfig.h
中,configUSE_TIMERS
必须设置为 1,才能使用 xTimerStart()
函数
xTimerStop()
xTimerStop()
用于停止一个运行中的软件定时器
- 调用
xTimerStop()
可以停止一个正在运行的定时器。如果定时器已经停止或已过期,则调用xTimerStop()
不会产生影响。 xTimerStop()
向定时器命令队列发送停止命令,定时器服务任务会在稍后处理该命令。
#include “FreeRTOS.h”
#include “timers.h”BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xTicksToWait );
参数
xTimer
要停止的定时器句柄。xTicksToWait
指定任务在定时器命令队列已满的情况下,最大等待时间(单位为 ticks)
返回值
pdPASS
pdFAIL
pcTimerGetName()
pcTimerGetName()
用于返回在创建定时器时分配的可读文本名称
#include “FreeRTOS.h”
#include “timers.h”const char * pcTimerGetName( TimerHandle_t xTimer );
返回值
- 返回值为一个指向定时器名称的指针。
- 定时器名称是一个标准的以
NULL
结尾的 C 字符串。
pvTimerGetTimerID()
pvTimerGetTimerID()
用于返回与定时器关联的标识符(ID)
- 返回在创建定时器时分配的标识符,该标识符可以通过
vTimerSetTimerID()
API 更新 - 在回调函数中可以使用该标识符区分哪个定时器到期,特别是在多个定时器共享相同的回调函数时
#include “FreeRTOS.h”
#include “timers.h”void *pvTimerGetTimerID( TimerHandle_t xTimer );
返回值
- 返回与指定定时器关联的标识符(指针类型)
xTimerReset()
xTimerReset()
用于重置、启动或重新启动一个软件定时器,能够起到 Watch Dog 的作用
- 如果定时器正在运行,
xTimerReset()
会将定时器的到期时间重新计算为相对于调用时间的周期 - 如果定时器未运行,
xTimerReset()
会启动定时器,并将到期时间计算为相对于调用时间的周期。此时等效于xTimerStart()
- 无论定时器当前是否运行,调用
xTimerReset()
后,定时器都将开始运行
#include “FreeRTOS.h”
#include “timers.h”BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );
返回值
pdPASS
pdFAIL
xTimerChangePeriod()
xTimerChangePeriod()
用于更改软件定时器的周期
- 更改运行中定时器的周期
- 如果定时器正在运行,则新周期将用于重新计算到期时间。
- 新的到期时间相对于调用
xTimerChangePeriod()
的时刻,而不是定时器最初启动的时刻。
- 启动未运行的定时器
- 如果定时器未运行,则定时器将使用新的周期值计算到期时间,并开始运行。
#include “FreeRTOS.h”
#include “timers.h”BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,TickType_t xNewPeriod,TickType_t xTicksToWait );
参数
xTimer
需要更改周期的定时器句柄xNewPeriod
定时器的新周期(单位为 tick)。可使用pdMS_TO_TICKS()
将毫秒转换为 tickxTicksToWait
阻塞任务的最大时间(单位为 tick),如果定时器命令队列已满,则等待空间可用
返回值
pdPASS
pdFAIL
Example Code:Using Software Timers
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h" #include "freertos/timers.h" // 定时器头文件 void TimerCallback(TimerHandle_t xTimer)
{ const char *pcTimerName = pcTimerGetName(xTimer);// 获取定时器名称 uint32_t *uiTimerID = (uint32_t *)pvTimerGetTimerID(xTimer);// 获取定时器ID printf("%s expired, ID: %lu.\n", pcTimerName, *uiTimerID);// 打印定时器名称和ID
} int id1 = 0;
int id2 = 1; void app_main(void)
{ TimerHandle_t TimerHandle1 = NULL; TimerHandle1 = xTimerCreate("Timer1", pdMS_TO_TICKS(1000), pdTRUE, (void *)&id1, TimerCallback);// 创建一个周期为1000ms的定时器 xTimerStart(TimerHandle1, 0);// 启动定时器 TimerHandle_t TimerHandle2 = NULL; TimerHandle2 = xTimerCreate("Timer2", pdMS_TO_TICKS(2000), pdTRUE, (void *)&id2, TimerCallback);// 与Timer1公用同一个回调函数,观察pcTimerGetName的输出 xTimerStart(TimerHandle2, 0);// 启动定时器 // for(int i = 0; i < 10; i++) // { // vTaskDelay(pdMS_TO_TICKS(1000)); // xTimerReset(TimerHandle2, 0);// 重置定时器,观察pcTimerGetName的输出,此时Timer2不会被打印 // } vTaskDelay(pdMS_TO_TICKS(5000)); xTimerChangePeriod(TimerHandle2, pdMS_TO_TICKS(1000), 0);// 修改Timer2的周期为1000ms vTaskDelay(pdMS_TO_TICKS(5000)); xTimerStop(TimerHandle1, 0);// 停止定时器 xTimerStop(TimerHandle2, 0);// 停止定时器
}
相关文章:
ESP32学习笔记_FreeRTOS(3)——SoftwareTimer
摘要(From AI): 这篇笔记全面介绍了 FreeRTOS 软件定时器的核心概念和使用方法,包括定时器的创建、管理、常用 API 和辅助函数,并通过示例代码演示了如何启动、重置和更改定时器的周期。它强调了软件定时器的灵活性、平台无关性以及与硬件定时器的对比 …...

文心一言与千帆大模型平台的区别:探索百度AI生态的双子星
随着人工智能技术的迅猛发展,越来越多的公司开始投入资源开发自己的AI解决方案。在中国,百度作为互联网巨头之一,不仅在搜索引擎领域占据重要位置,还在AI领域取得了显著成就。其中,“文心一言”和“千帆大模型平台”便…...

【c语言】文件操作详解 - 从打开到关闭
文章目录 1. 为什么使用文件?2. 什么是文件?3. 如何标识文件?4. 二进制文件和文本文件?5. 文件的打开和关闭5.1 流和标准流5.1.1 流5.1.2 标准流 5.2 文件指针5.3 文件的打开和关闭 6. 文件的读写顺序6.1 顺序读写函数6.2 对比一组…...

Flink Sink的使用
经过一系列Transformation转换操作后,最后一定要调用Sink操作,才会形成一个完整的DataFlow拓扑。只有调用了Sink操作,才会产生最终的计算结果,这些数据可以写入到的文件、输出到指定的网络端口、消息中间件、外部的文件系统或者是…...
pcl::PointCloud<PointType>::Ptr extractedCloud; 尖括号里的值表示什么含义?
在C中,pcl::PointCloud<PointType>::Ptr是一种智能指针,它是Point Cloud Library (PCL)中用于管理pcl::PointCloud对象的智能指针类型。这里的<pcl::PointCloud<PointType>::Ptr>尖括号里的值表示智能指针所指向的对象类型。 让我们分…...

《基于FPGA的便携式PWM方波信号发生器》论文分析(三)——数码管稳定显示与系统调试
一、论文概述 基于FPGA的便携式PWM方波信号发生器是一篇由任青颖、庹忠曜、黄洵桢、李智禺和张贤宇 等人发表的一篇期刊论文。该论文主要研究了一种新型的信号发生器,旨在解决传统PWM信号发生器在移动设备信号调控中存在的精准度低和便携性差的问题 。其基于现场可编…...

VsCode 插件推荐(个人常用)
VsCode 插件推荐(个人常用)...

路由策略与路由控制实验
AR1、AR2、AR3在互联接口、Loopback0接口上激活OSPF。AR3、AR4属于IS-IS Area 49.0001,这两者都是Level-1路由器,AR3、AR4的系统ID采用0000.0000.000x格式,其中x为设备编号 AR1上存在三个业务网段A、B、C(分别用Loopback1、2、3接…...
训练的decoder模型文本长度不一致,一般设置为多大合适,需要覆盖最长的文本长度么
在训练解码器模型时,文本长度不一致是常见的情况,需要根据任务的特性和数据集的长度分布来设置合理的最大长度 (max_length)。以下是一些指导原则,帮助你设置合适的最大长度: 1. 是否需要覆盖最长文本长度 覆盖最长文本长度: 如果任务对完整性要求很高(例如生成数学公式、…...

过滤条件包含 OR 谓词,如何进行查询优化——OceanBase SQL 优化实践
这篇博客涉及两个点,一个是 “OR Expansion 改写”,另一个是 “基于代价的改写”。 背景 在写SQL查询时,难以避免在过滤条件中使用 OR 谓词,但其往往会导致索引利用效率下降的问题 。本文将分享如何通过查询改写的2种方式进行优化…...

通过异步使用消息队列优化秒杀
通过异步使用消息队列优化秒杀 同步秒杀流程异步优化秒杀异步秒杀流程基于lua脚本保证Redis操作原子性代码实现阻塞队列的缺点 同步秒杀流程 public Result seckillVoucher(Long voucherId) throws InterruptedException {SeckillVoucher seckillVoucher iSeckillVoucherServi…...

AI产业告别“独奏”时代,“天翼云息壤杯”高校AI大赛奏响产学研“交响乐”
文 | 智能相对论 作者 | 陈泊丞 人工智能产业正在从“独奏”时代进入“大合奏”时代。 在早期的AI发展阶段,AI应用主要集中在少数几个领域,如语音识别、图像处理等。这些领域的研究和开发工作往往由少数几家公司或研究机构即可独立完成,犹…...

Hot100 - 字母异位词分组
Hot100 - 字母异位词分组 最佳思路:排序 时间复杂度: O(nmlogm),其中 n 为 strs 数组的长度,m 为每个字符串的长度。 代码: class Solution {public List<List<String>> groupAnagrams(String[] strs) …...

力扣hot100-->排序
排序 1. 56. 合并区间 中等 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。 示例 1: 输…...

【VRChat 全身动捕】VIVE 手柄改 tracker 定位器教程,低成本光学动捕解决方案(持续更新中2024.11.26)
更新 0.0.1(2024/11/26): 1.解决了内建蓝牙无法识别、“steamVR 蓝牙不可用” 的解决方案 2.解决了 tracker 虽然建立了连接但是在 steamVR 界面上看不到的问题 3.解决了 VIVE 基站1.0 无法被蓝牙识别 && 无法被 steamVR 搜索到 &…...

【Nginx】核心概念与安装配置解释
文章目录 1. 概述2. 核心概念2.1.Http服务器2.2.反向代理2.3. 负载均衡 3. 安装与配置3.1.安装3.2.配置文件解释3.2.1.全局配置块3.2.2.HTTP 配置块3.2.3.Server 块3.2.4.Location 块3.2.5.upstream3.2.6. mine.type文件 3.3.多虚拟主机配置 4. 总结 1. 概述 Nginx是我们常用的…...

Qt界面篇:QMessageBox高级用法
1、演示效果 2、用法注意 2.1 设置图标 用于显示实际图标的pixmap取决于当前的GUI样式。也可以通过设置icon pixmap属性为图标设置自定义pixmap。 QMessageBox::Icon icon(...
【二叉树】【2.1遍历二叉树】【刷题笔记】【灵神题单】
关注二叉树的三个问题: 什么情况适合自顶向下?什么时候适合用自底向上?一般来说,DFS的递归边界是空节点,什么情况下要额外把叶子节点作为递归边界?在什么情况下,DFS需要有返回值?什…...
Mongo数据库 --- Mongo Pipeline
Mongo数据库 --- Mongo Pipeline 什么是Mongo PipelineMongo Pipeline常用的几个StageExplanation with example:MongoDB $matchMongoDB $projectMongoDB $groupMongoDB $unwindMongoDB $countMongoDB $addFields Some Query Examples在C#中使用Aggreagtion Pipeline**方法一: …...

Adobe Illustrator 2024 安装教程与下载分享
介绍一下 下载直接看文章末尾 Adobe Illustrator 是一款由Adobe Systems开发的矢量图形编辑软件。它广泛应用于创建和编辑矢量图形、插图、徽标、图标、排版和广告等领域。以下是Adobe Illustrator的一些主要特点和功能: 矢量绘图:Illustrator使用矢量…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...

前端开发者常用网站
Can I use网站:一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use:Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站:MDN JavaScript权威网站:JavaScript | MDN...
Angular中Webpack与ngx-build-plus 浅学
Webpack 在 Angular 中的概念 Webpack 是一个模块打包工具,用于将多个模块和资源打包成一个或多个文件。在 Angular 项目中,Webpack 负责将 TypeScript、HTML、CSS 等文件打包成浏览器可以理解的 JavaScript 文件。Angular CLI 默认使用 Webpack 进行项目…...
Python网页自动化测试,DrissonPage库入门说明文档
🛰️ 基本逻辑 操作浏览器的基本逻辑如下: 创建浏览器对象,用于启动或接管浏览器获取一个 Tab 对象使用 Tab 对象访问网址使用 Tab 对象获取标签页内需要的元素对象使用元素对象进行交互 除此以外,还能执行更为复杂的操作&am…...