STM32F1+HAL库+FreeTOTS学习17——事件标志组
STM32F1+HAL库+FreeTOTS学习17——事件标志组
- 1. 事件标志组
- 1.1 事件标志组的的引入
- 1.2 事件标志组简介
- 1.3 事件标志组与队列、信号量的区别
- 2. 事件标志组下相关API函数
- 2. 1 xEventGroupCreate()
- 2. 2 xEventGroupCreateStatic()
- 2. 3 vEventGroupDelete()
- 2. 4 xEventGroupWaitBits()
- 2. 5 xEventGroupSetBits()
- 2. 7 xEventGroupSetBitsFromISR()
- 2. 8 xEventGroupClearBits()
- 2. 9 xEventGroupClearBitsFromISR()
- 2. 10 xEventGroupGetBits()
- 2. 11 xEventGroupGetBitsFromISR()
- 2. 12 xEventGroupSync()
- 3. 事件标志组操作实验
- 3.1. 实验内容
- 3.2 代码实现
- 3.2 实验结果
上期我们介绍了队列集,这一期我们来开始学习事件标志组
1. 事件标志组
1.1 事件标志组的的引入
前面我们在介绍信号量的时候有提到过,信号量是为了解决任务与任务之间的同步问题而引入的,但是对于任务之间的多个事件同步,使用信号量也会比较麻烦,为了实现任务之间多个事件的同步,方便统一管理,我们引入事件标志组。
1.2 事件标志组简介
- 在事件标志组中,每一个位都可以用来表征一个事件的标志,这样的一个位叫做事件标志位,而事件标志组就是事件标志位的集合。
- 当有个标志位被置1了,表示某个事件已经发送,反正则未发生。
- 事件标志组包含了一个 EventBits_t 类型的变量,实际上就是一个整数,EventBits_t 类型变量的具体定义如下:
typedef TickType_t EventBits_t;#if ( configUSE_16_BIT_TICKS == 1 )typedef uint16_t TickType_t;#define portMAX_DELAY ( TickType_t ) 0xffff#elsetypedef uint32_t TickType_t;#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
-
可以见的,EventBits_t 的变量在我们这里是32位变量,但实际上,我们能够使用的只有0~23位,高八位不可用,即一个事件组最大可以存储24个事件标志

-
在实际使用中,事件标志组支持同时等待、设置(置位)多个标志位
-
事件标志组的置位、等待、清除标志位、获取标志位信息等操作支持在任务和中断中使用。
1.3 事件标志组与队列、信号量的区别
- 队列和信号量:在事件发生时,只会唤醒一个任务,是消耗型的资源,队列中的数据被读走就没有了,信号量被获取之后就减少,需要再次写入队列或者释放消息给信号量。
事件标志组:事件发生时,会唤醒所有符合条件的任务,被唤醒的任务有两个选择,可以让事件标志位保持不变,也可以清除事件标志。
2. 事件标志组下相关API函数
FreeRTOS 提供了事件标志组的一些相关操作函数,如下表所示:
| 函数 | 描述 |
|---|---|
| xEventGroupCreate() | 使用动态方式创建事件标志组 |
| xEventGroupCreateStstic() | 使用静态方式创建事件标志组 |
| vEventGroupDelete() | 删除事件标志组 |
| xEventGroupWaitBits() | 等待事件标志位 |
| xEventGroupSetBits() | 设置事件标志位列 |
| xEventGroupSetBitsFromISR() | 在中断中设置事件标志位 |
| xEventGroupClearBits() | 清零事件标志位 |
| xEventGroupClearBitsFromISR() | 在中断中清零事件标志位 |
| xEventGroupGetBits() | 获取事件组中各事件标志位的值 |
| xEventGroupGetBitsFromISR() | 在中断中获取事件组中各事件标志位的值 |
| xEventGroupSync() | 设置事件标志位,并等待事件标志位 |
2. 1 xEventGroupCreate()
此函数用于动态方式创建事件标志组,该函数在 event_groups.c 文件中有定义,函数的原型如下所示:
/*** @brief xEventGroupCreate:动态方式创建事件标志组* @param void* @retval 返回值为NULL,表示创建失败,其他值表示为创建事件标志组的句柄*/
EventGroupHandle_t xEventGroupCreate(void);
2. 2 xEventGroupCreateStatic()
此函数用于动态方式创建事件标志组,该函数在 event_groups.c 文件中有定义,函数的原型如下所示:
/*** @brief xEventGroupCreateStatic:静态方式创建事件标志组* @param pxEventGroupBuffer: 指向StaticEventGroup_t 变量类型的指针,用来存放创建完成的事件标志组* @retval 返回值为NULL,表示创建失败,其他值表示为创建事件标志组的句柄*/
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer );
2. 3 vEventGroupDelete()
此函数用于删除事件标志组,该函数在 event_groups.c 文件中有定义,函数的原型如下所示:
/*** @brief vEventGroupDelete:删除事件标志组* @param xEventGroup:待删除的事件标志组句柄* @retval void*/
void vEventGroupDelete(EventGroupHandle_t xEventGroup);
2. 4 xEventGroupWaitBits()
此函数用于等待事件标志组中的某一个或多个标志位,该函数在 event_groups.c 文件中有定义,函数的原型如下所示:
/*** @brief xEventGroupWaitBits:等待事件标志组中的某一个或多个标志位* @param xEventGroup:等待的事件标志组句柄* @param uxBitsToWaitFor:等待的事件标志位,可以使用逻辑或等待多个事件标志位* @param xClearOnExit:等待成功后是否清除对应标志位,pdTRUE清除,pdFALSE不清除* @param xWaitForAllBits:等待事件标志位中的一个还是所有,pdTRUE等待所有,pdFLASE等待一个* @param xTicksToWait:等待阻塞时间* @retval void*/
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToWaitFor,const BaseType_t xClearOnExit,const BaseType_t xWaitForAllBits,TickType_t xTicksToWait)
2. 5 xEventGroupSetBits()
此函数用于设置(置位)事件标志位,该函数在 event_groups.c 文件中有定义,函数的原型如下所示:
/*** @brief xEventGroupSetBits:设置(置位)事件标志位* @param xEventGroup:待设置的事件标志组句柄* @param uxBitsToSet :需要设置的事件标志位,可以通过逻辑或的方式,同时设置多个事件标志位* @retval 事件标志组值,可以表征事件标志组中的事件标志位的设置(置位)情况。*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet );
2. 7 xEventGroupSetBitsFromISR()
此函数用于在中断中设置(置位)事件标志位,该函数在 event_groups.c 文件中有定义,函数的原型如下所示:
/*** @brief xEventGroupSetBitsFromISR:在中断中设置(置位)事件标志位* @param xEventGroup:待设置的事件标志组句柄* @param uxBitsToSet :需要设置的事件标志位,可以通过逻辑或的方式,同时设置多个事件标志位* @param pxHigherPriorityTaskWoken :是否需要进行任务切换,如果为pdTRUE,表示需要进行任务切换,为pdFALSE则不需要* @retval 如果消息已发送到 RTOS 守护进程任务,则返回 pdPASS,否则返回 pdFAIL。 如果定时器服务队列已满,则返回 pdFAIL。*/
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet,BaseType_t *pxHigherPriorityTaskWoken );
【注】:在事件组中设置位将自动解除 所有等待位的任务的阻塞状态。这个操作是不确定的,因为有可能同时存在多个任务解除阻塞,FreeRTOS不允许在中断中出现这种操作,因此xEventGroupSetBitsFromISR()会向RTOS 守护进程任务发送一条消息, 从而在守护进程任务(也叫做定时器服务任务)的上下文中执行设置操作,其中使用的是调度器锁 而非临界区。
总结一句话:就是xEventGroupSetBitsFromISR()函数中的标志位置位操作会被推迟到 RTOS 守护进程任务中进行。
2. 8 xEventGroupClearBits()
此函数用于在任务中清零事件标志位,该函数在 event_groups.c 文件中有定义,函数的原型如下所示:
/*** @brief xEventGroupClearBits:在任务中清除事件标志位* @param xEventGroup:需要清除标志位的事件标志组句柄* @param uxBitsToClear :需要清除的事件标志位,可以通过逻辑或的方式,同时清除多个事件标志位* @retval 清除指定位之前的事件组的值。*/
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToClear );
2. 9 xEventGroupClearBitsFromISR()
此函数用于在中断中清零事件标志位,该函数在 event_groups.c 文件中有定义,函数的原型如下所示:
/*** @brief xEventGroupClearBitsFromISR:在中断中清除事件标志位* @param xEventGroup:需要清除标志位的事件标志组句柄* @param uxBitsToClear :需要清除的事件标志位,可以通过逻辑或的方式,同时清除多个事件标志位* @retval 如果返回pdPASS表示操作成功延迟到RTOS守护进程任务,否则表示定时器命令队列已满,事件标志位清零失败。*/
BaseType_t xEventGroupClearBitsFromISR(EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToClear );
2. 10 xEventGroupGetBits()
此函数用于获取事件标志组的值,可以表征事件标志组内成员的置位情况,该函数在 event_groups.c 文件中有定义,函数的原型如下所示:
/*** @brief xEventGroupGetBits:获取事件标志组的值* @param xEventGroup:需要查询的事件标志组句柄* @retval 事件标志组的值*/
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup );
2. 11 xEventGroupGetBitsFromISR()
此函数用于中断中获取事件标志组的值,可以表征事件标志组内成员的置位情况,该函数在 event_groups.c 文件中有定义,函数的原型如下所示:
/*** @brief xEventGroupGetBitsFromISR:获取事件标志组的值* @param xEventGroup:需要查询的事件标志组句柄* @retval 事件标志组的值*/
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup );
2. 12 xEventGroupSync()
此函数用于设置事件标志组中的位,并且等待同一事件标志组的标志位,常用于同步多个任务(通常称为任务集合),其中每个任务必须等待其他任务到达同步点后才能继续,且不能在中断中使用此函数。
举个栗子来说:我们在打王者荣耀进入游戏之前,需要先匹配队友,如何等待所有队友点击“确认”才可以进入游戏,如果中途有玩家未点击确认,则无法进入游戏。
在这个例子里面,自己点击“确认”,是自己将标志位置位,但此时需要等待其他队友点击“确认”,是等待同一事件标志组的其他标志位。这个就是多个任务之间的消息同步。同时每个队友(任务),都需要等待其他队友(任务)点击确认(所有人都到达同步点)才能继续。
上述是我自己对于此函数的理解,下面我们来看一下函数原型:
/*** @brief xEventGroupSync:设置事件标志组中的位,并且等待同一事件标志组的标志位,常用于同步多个任务* @param xEventGroup:待设置和等待位的事件标志组句柄* @param uxBitsToSet:在确定uxBitsToWait参数指定的所有位是否都已设置(可能还要等待)之前,要在事件组中设置的一个或多个位。* @param uxBitsToWaitFor:指定要在事件组中等待的一个或多个位的按位值。* @param xTicksToWait: 等待 uxBitsToWaitFor 参数值指定的所有位被设置的最长时间(以滴答为单位) 。* @retval 如果等待事件标志位成功,返回等待到的事件标志位;如果等待事件标志位失败,返回事件组中的事件标志位*/
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet,const EventBits_t uxBitsToWaitFor,TickType_t xTicksToWait );
3. 事件标志组操作实验
3.1. 实验内容
在STM32F103RCT6上运行FreeRTOS,通过按键控制,完成对应的事件标志位操作,具体要求如下:
- 定义一个事件标志位
- 定义任务1:按下按键0,按键0对应的事件标志位置1,LED指示灯亮起;按下按键1,按键1对应的事件标志位置1,LED指示灯亮起。
- 定义任务2:等待事件标志组中按键0和按键1对于的标志位,当两者都被置1时,串口打印相关信息,并且关闭LED指示灯。
3.2 代码实现
- 由于本期内容涉及到按键扫描,会用到: STM32框架之按键扫描新思路 ,这里不做过多介绍。我们直接来看代码:
- freertos_demo.c
#include "freertos_demo.h"
#include "gpio.h"
#include "queue.h" //需要包含队列和任务相关的头文件
#include "key.h" //包含按键相关头文件/*FreeRTOS*********************************************************************************************//******************************************************************************************************/
/*FreeRTOS配置*//* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 */
#define TASK1_PRIO 1 /* 任务优先级 */
#define TASK1_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task1Task_Handler; /* 任务句柄 */
void task1(void *pvParameters); /*任务函数*//* TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 */
#define TASK2_PRIO 2 /* 任务优先级 */
#define TASK2_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task2Task_Handler; /* 任务句柄 */
void task2(void *pvParameters); /*任务函数*//** 事件标志组配置*/
EventGroupHandle_t EventGroup_Handler; /* 事件标志组句柄 *//******************************************************************************************************//*** @brief FreeRTOS例程入口函数* @param 无* @retval 无*/
void freertos_demo(void)
{taskENTER_CRITICAL(); /* 进入临界区,关闭中断,此时停止任务调度*//* 创建事件标志组 */EventGroup_Handler = xEventGroupCreate();if(EventGroup_Handler == NULL){printf("事件标志组创建失败!!!\r\n");}else{printf("事件标志组创建成功!!!\r\n");}/* 创建任务1 */xTaskCreate((TaskFunction_t )task1,(const char* )"task1",(uint16_t )TASK1_STK_SIZE,(void* )NULL,(UBaseType_t )TASK1_PRIO,(TaskHandle_t* )&Task1Task_Handler);/* 创建任务2 */xTaskCreate((TaskFunction_t )task2,(const char* )"task2",(uint16_t )TASK2_STK_SIZE,(void* )NULL,(UBaseType_t )TASK2_PRIO,(TaskHandle_t* )&Task2Task_Handler);taskEXIT_CRITICAL(); /* 退出临界区,重新开启中断,开启任务调度 */vTaskStartScheduler(); //开启任务调度
}/**
* @brief task1:用于按键扫描,按键0或1按下,自动置位事件标志组,并开启相应的LED指示* @param pvParameters : 传入参数(未用到)* @retval 无*/
void task1(void *pvParameters)
{while(1){Key_One_Scan(Key_Name_Key0,Key0_Up_Task,Key0_Down_Task);Key_One_Scan(Key_Name_Key1,Key1_Up_Task,Key1_Down_Task);vTaskDelay(10);}
}
/**
* @brief task2:当按键1和0的事件标志组位都被置1,打印相关信息,并关闭相应的LED指示* @param pvParameters : 传入参数(未用到)* @retval 无*/
void task2(void *pvParameters)
{ EventBits_t eventBits;while(1){ /* 等待按键0和1的事件标志位 */eventBits = xEventGroupWaitBits(EventGroup_Handler,Key0_EventBit|Key1_EventBit,pdTRUE,pdTRUE,portMAX_DELAY);/* 打印相关信息 */printf("等待到的事件标志为:%#x\r\n",eventBits);/* 关闭LED指示 */HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,LED_OFF);HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,LED_OFF);vTaskDelay(50);}}
- key.c
/* USER CODE BEGIN 2 */#include "key.h"
#include "freertos_demo.h"
#include "usart.h"
#include "event_groups.h" //包含事件标志组头文件
#include "gpio.h"void Key0_Down_Task(void)
{/* 设置事件标志位 */HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,LED_ON);/* 开启LED指示 */xEventGroupSetBits(EventGroup_Handler,Key0_EventBit);}
void Key0_Up_Task(void)
{}
void Key1_Down_Task(void)
{/* 设置事件标志位 */HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,LED_ON);/* 开启LED指示 */xEventGroupSetBits(EventGroup_Handler,Key1_EventBit);}
void Key1_Up_Task(void)
{}
void Key2_Down_Task(void)
{}
void Key2_Up_Task(void)
{}
void WKUP_Down_Task(void)
{}
void WWKUP_Up_Task(void)
{}void Key_One_Scan(uint8_t KeyName ,void(*OnKeyOneUp)(void), void(*OnKeyOneDown)(void))
{static uint8_t Key_Val[Key_Name_Max]; //按键值的存放位置static uint8_t Key_Flag[Key_Name_Max]; //KEY0~2为0时表示按下,为1表示松开,WKUP反之Key_Val[KeyName] = Key_Val[KeyName] <<1; //每次扫描完,将上一次扫描的结果左移保存switch(KeyName){case Key_Name_Key0: Key_Val[KeyName] = Key_Val[KeyName] | (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)); //读取Key0按键值break;case Key_Name_Key1: Key_Val[KeyName] = Key_Val[KeyName] | (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin)); //读取Key1按键值break;case Key_Name_Key2: Key_Val[KeyName] = Key_Val[KeyName] | (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin)); //读取Key2按键值break;
// case Key_Name_WKUP: Key_Val[KeyName] = Key_Val[KeyName] | (HAL_GPIO_ReadPin(WKUP_GPIO_Port, WKUP_Pin)); //读取WKUP按键值
// break; default:break;}
// if(KeyName == Key_Name_WKUP) //WKUP的电路图与其他按键不同,所以需要特殊处理
// {
// //WKUP特殊情况
// //当按键标志为1(松开)是,判断是否按下,WKUP按下时为0xff
// if(Key_Val[KeyName] == 0xff && Key_Flag[KeyName] == 1)
// {
// (*OnKeyOneDown)();
// Key_Flag[KeyName] = 0;
// }
// //当按键标志位为0(按下),判断按键是否松开,WKUP松开时为0x00
// if(Key_Val[KeyName] == 0x00 && Key_Flag[KeyName] == 0)
// {
// (*OnKeyOneUp)();
// Key_Flag[KeyName] = 1;
// }
// }
// else //Key0~2按键逻辑判断
// {//Key0~2常规判断//当按键标志为1(松开)是,判断是否按下if(Key_Val[KeyName] == 0x00 && Key_Flag[KeyName] == 1){(*OnKeyOneDown)();Key_Flag[KeyName] = 0;}//当按键标志位为0(按下)if(Key_Val[KeyName] == 0xff && Key_Flag[KeyName] == 0){(*OnKeyOneUp)();Key_Flag[KeyName] = 1;} }//}
/* USER CODE END 2 */
3.2 实验结果

以上就是本期的所有内容,创造不易,点个关注再走呗。

相关文章:
STM32F1+HAL库+FreeTOTS学习17——事件标志组
STM32F1HAL库FreeTOTS学习17——事件标志组 1. 事件标志组1.1 事件标志组的的引入1.2 事件标志组简介1.3 事件标志组与队列、信号量的区别 2. 事件标志组下相关API函数2. 1 xEventGroupCreate()2. 2 xEventGroupCreateStatic()2. 3 vEventGroupDelete()2. 4 xEventGroupWaitBit…...
ElasticSearch基本概念
本文内容参考了田雪松老师编著的《Elastic Stack应用宝典》 对比关系型数据库 索引(Index)相当于库映射类型(Mapping Type)相当于表文档(Document)相当于行文档字段(Field)相当于列…...
fluent-ffmpeg操作MP3文件深入解析
软考鸭微信小程序 学软考,来软考鸭! 提供软考免费软考讲解视频、题库、软考试题、软考模考、软考查分、软考咨询等服务 引言 fluent-ffmpeg是一个功能强大的Node.js库,它为FFmpeg提供了一个流畅的接口。FFmpeg是一个著名的多媒体框架,以处理音频、视频和…...
做信创项目需要什么资质、信创产品认证标准?
信创项目需要企业具备一些特定的资质和认证,以证明其合规性和专业性。以下是做信创项目可能用到的一些资质: 1. 信息安全管理体系认证(ISO27001):该认证可以证明企业已经建立了完善的信息安全管理体系,能够…...
Spring i18n国际化
从源码MessageSource的三个实现出发实战springi18n国际化 - 简熵 - 博客园 import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.MessageSource; import org.spri…...
基于stm32的楼宇照明控制系统设计
基于stm32的楼宇照明控制系统设计 项目说明一、绪论1.1 研究背景1.2 研究意义1.4 研究内容 二、系统方案设计2.1 微控制器方案选择2.2 信息检测模块方案选择2.3 WiFi模块选择2.4 终端显示2.5 WiFi无线通信实现方法 三、系统硬件电路图设计3.1 整体电路图设计3.2 主控制器设计3.…...
ESP32移植Openharmony外设篇(3)OLED屏
模块简介 产品介绍 OLED (Organic Light-Emitting Diode):有机发光二极管又称为有机电激光显示,OLED显示技术具有自发光的特性,采用薄的有机材料涂层和玻璃基板,当有电流通过时,这些有机材料就会发光,而且…...
人工智能:未来生活与工作的变革力量
人工智能(AI)作为21世纪最具变革性的技术之一,正以前所未有的速度改变着我们的生活和工作方式。从医疗行业的突破性进展到企业运营的智能化,以及日常生活中各种智能产品的普及,人工智能正在成为现代社会不可或缺的一部…...
AI自动生成PPT哪个软件好?智能生成PPT不再熬夜做课件
大概这世上,都是职场牛马对“PPT”这三个字母的头痛反应最大吧! 是的,就连各个年级段的老师也是很头痛——愁着怎样能在排版整齐的情况下,将必考知识点都呈现在PPT每一张幻灯片页面里...... 近期打听到用人工智能生成ppt课件&am…...
C# OOP面试题精选 面向新手/SOLID原则/设计模式++ 长期更新
1.整理目的 相当于0.1版本,旨在学习/提升/复习 关于面向对象模块的知识 目前,记录了一些比较容易混淆或者突然想不起的冷门内容 还有一些个人经过实战后总结的内容,其中还指明了很多实例和分析链接以更加方便地复习 【金山文档 | WPS云文…...
安全见闻(2)——开阔眼界,不做井底之蛙
内容预览 ≧∀≦ゞ 安全见闻二:Web程序构成与潜在漏洞声明导语前端语言及潜在漏洞前端语言前端框架与代码库代码库的概念和用途流行的JavaScript框架常见的代码库 前端潜在漏洞 后端语言及潜在漏洞常见后端语言协议问题后端潜在漏洞 数据库及潜在漏洞数据库分类数据…...
ProtoBuf 的含义和安装
ProtoBuf 是什么 Protocol Buffers 是 Google 的⼀种语⾔⽆关、平台⽆关、可扩展的序列化结构数据的⽅法,它可⽤ 于(数据)通信协议、数据存储等。 Protocol Buffers 类⽐于、 XML,是⼀种灵活,⾼效,⾃动化机…...
C++位操作实战:掩码、提取与组装
在C编程中,位操作是一项基础且强大的技术,它允许程序员在二进制级别上直接操作数据。这种能力对于性能优化、内存节省以及底层硬件控制至关重要。本文将深入探讨C中的掩码操作、字节提取与组装,并通过实例展示这些技术的实际应用。 一、位运算…...
PVE虚拟机强制重启
在Proxmox VE (PVE) 中,强制重启虚拟机的方法有几种,取决于具体场景和虚拟机的状态。以下是常用的两种方法: 1. 使用PVE Web UI强制重启虚拟机 如果虚拟机无法正常关闭或重启,可以使用PVE Web界面中的强制关机/重启选项…...
Adobe Acrobat DC 打印PDF文件,没有打印出注释的解决方法
adobe acrobat在打印的时候,打印不出来注释内容(之前一直可以,突然就不行),升级版本、嵌入字体等等都试过,也在Google找了半天和问了GPT也么找着办法。 无奈之下,自己通过印前检查,…...
主机名学习
1.主机名 定义:主机名是一个人类可读的标识符,通常由字母、数字和连接符组成,用于标识网络中的设备。主机名可以是局部的(例如局域网中的设备名)或者全局的(通过 DNS 解析成 IP 地址)。 解析&…...
SpringBoot循环依赖
在Spring Boot(以及Spring框架)中,循环依赖是指两个或多个Bean互相依赖,导致Spring在创建这些Bean时无法正常进行依赖注入。例如,假设有两个类A和B,A依赖于B,而B又依赖于A。在这种情况下&#x…...
一道面试题:为什么要使用Docker?
先来笼统地看一下 1、环境一致性 众所周知,开发过程中一个常见的问题是环境一致性问题,由于开发环境,测试环境,生产环境不一致,导致有些bug并未在开发过程中被发现,而Docker的镜像提供了除内核外完整的运…...
类的创建、构造器、实例属性、实例方法
Creating Classes # Class: blueprint for creating new Objects # Object: instance of a class # Class: Human # Objects: John, Mary, Jack# 类名定义每个单词的首字母大写 class Point:# 每个方法至少有一个参数def draw(self):print("draw")# 创建Point对象 p…...
js读取.txt文件内容
方法一:FileReader() <input type"file" id"fileInput" /><script>const fileInput document.getElementById(fileInput)fileInput.addEventListener(change, function (e) {const file e.target.files[0]const reader new Fil…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器
拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件: 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...
机器学习的数学基础:线性模型
线性模型 线性模型的基本形式为: f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回归问题 利用最小二乘法,得到 ω \boldsymbol{\omega} ω和 b b b的参数估计$ \boldsymbol{\hat{\omega}}…...
JS红宝书笔记 - 3.3 变量
要定义变量,可以使用var操作符,后跟变量名 ES实现变量初始化,因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符,可以创建一个全局变量 如果需要定义…...
