跟着野火学FreeRTOS:第二段(事件组)

     在小节里面介绍了二进制信号量,计数信号量,互斥量和递归互斥量等功能,其中二进制信号量和计数信号量(也包括队列)常用于任务和任务之间以及任务和中断之间的同步,她们具有以下属性:

  • 当等待的事件没有发生的时候可以让等待的任务进入阻塞状态
  • 当等待的事件发生之后可以将因为等待事件发生而进入阻塞状态的任务唤醒,如果有多个任务在等待同一个事件发生的话,那么此时被唤醒的是优先级最高的任务,其它任务依然还是处于阻塞状态。

     这里即将要介绍的事件组( E v e n t G r o u p s Event\quad Groups EventGroups)也可以用于任务和任务之间以及任务和中断之间的同步,但是和二进制信号量,计数信号量(也包括队列)不同的是:

  1. 事件组可以用于等待多个事件的发生而进行同步,而不是像二进制信号量和计数信号量(也包括队列)只能用于等待单一的事件而进行同步
  2. 当等待的事件中的事件发生的时候可以唤醒多个任务而不是像二进制信号量和计数信号量(也包括队列)只能用于唤醒多个任务中优先级最高的那个任务。

     事件组以上的特有属性使得事件组非常适合于多个任务的同步,可以将事件的发生广播给多个任务,也允许一个任务等待一个或多个事件的发生来同步。事件组在 F r e e R T O S FreeRTOS FreeRTOS的源码的 e v e n t g r o u p s . c event_groups.c eventgroups.c文件中用一个结构体来定义,如图1所示。当宏 c o n f i g U S E _ 16 _ B I T _ T I C K S configUSE\_16\_BIT\_TICKS configUSE_16_BIT_TICKS被定义为0的时候,变量 u x E v e n t B i t s uxEventBits uxEventBits的低24位可以用来表示24个事件的状态,如果对应的比特位的值为1则表面对应的事件已经发生,反之对应的事件没有发生,变量 u x E v e n t B i t s uxEventBits uxEventBits的高8位用于特殊用途(对应于图2中的那些宏定义,至于其具体的含义需要通过相应的源码来了解其具体含义)。当宏 c o n f i g U S E _ 16 _ B I T _ T I C K S configUSE\_16\_BIT\_TICKS configUSE_16_BIT_TICKS被定义为1的时候,变量 u x E v e n t B i t s uxEventBits uxEventBits的低8位可以用来表示8个事件的状态,如果对应的比特位的值为1则表面对应的事件已经发生,反之对应的事件没有发生,变量 u x E v e n t B i t s uxEventBits uxEventBits的高8位用于特殊用途(对应于图2中的那些宏定义,至于其具体的含义需要通过相应的源码来了解其具体含义)。

 
图1.
 
图2.

     在图3的例子中,这里宏 c o n f i g U S E _ 16 _ B I T _ T I C K S configUSE\_16\_BIT\_TICKS configUSE_16_BIT_TICKS被定义为0,比特位1,4,和7对应的事件已经发生而其它比特位对应的事件还没有发生。事件组可以被多个任务或中断接入,任何任务都有权限对事件组结构体中的变量 u x E v e n t B i t s uxEventBits uxEventBits的低8位或低24位的比特位进行置位,任何任务也都有权限对事件组结构体中的变量 u x E v e n t B i t s uxEventBits uxEventBits进行读取。事件组的结构体的 x T a s k s W a i t i n g F o r B i t s xTasksWaitingForBits xTasksWaitingForBits元素是一个用来记录因为在等待事件组的某个或某些事件而被阻塞的任务。

 
图3.

     下面来简单的看几个事件组的 A P I API API接口函数,其它的 A P I API API接口函数可以自己去看看图4所示的文档的详细介绍。

 
图4.
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
    BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
                                          const EventBits_t uxBitsToSet,
                                          BaseType_t * pxHigherPriorityTaskWoken )
    {
        BaseType_t xReturn;

        traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet );
        xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */

        return xReturn;
    }

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
                                 const EventBits_t uxBitsToWaitFor,
                                 const BaseType_t xClearOnExit,
                                 const BaseType_t xWaitForAllBits,
                                 TickType_t xTicksToWait )

     接口 x E v e n t G r o u p S e t B i t s xEventGroupSetBits xEventGroupSetBits用来对事件组的结构体里面的变量 u x E v e n t B i t s uxEventBits uxEventBits的低24位或低8位的比特位进行置位,表示对应的比特位表示的事件已经发生,参数 x E v e n t G r o u p xEventGroup xEventGroup表示将要对其进行置位操作的事件组,参数 u x B i t s T o S e t uxBitsToSet uxBitsToSet表示将要对那些比特位进行置位,如果参数 u x B i t s T o S e t uxBitsToSet uxBitsToSet的值为 0 x 00000024 0x00000024 0x00000024且置位操作之前事件组的结构体里面的变量 u x E v e n t B i t s uxEventBits uxEventBits的值为 0 x 00008100 0x00008100 0x00008100,那置位之后事件组的结构体里面的变量 u x E v e n t B i t s uxEventBits uxEventBits的值应该为 0 x 00008124 0x00008124 0x00008124(假设在此期间没有其它任务对这个事件组进行置位或清除操作),也就是说置位操作不会将置位操作以前已经是值1的比特位变成值0,这是因为在进行置位操作的时候进行的是或运算。该接口不能在中断中调用,因为 F r e e R T O S FreeRTOS FreeRTOS的设计理念不允许在中断中进行会产生不确定行行为的操作,这是因为事件组中的事件的发生可以唤醒多个事件,至于具体是几个,我们是无法知道的,因此对事件组的置位操作属于是不确定的操作。该接口对应的中断版本为 x E v e n t G r o u p S e t B i t s F r o m I S R xEventGroupSetBitsFromISR xEventGroupSetBitsFromISR,该接口将事件组的置位操作(其实最后调用的也是接口 x E v e n t G r o u p S e t B i t s xEventGroupSetBits xEventGroupSetBits)转移到 t h e R T O S d a e m o n t a s k the\quad RTOS\quad daemon\quad task theRTOSdaemontask(该点涉及的内容应该是在 S o f t w a r e T i m e r M a n a g e m e n t Software\quad Timer\quad Management SoftwareTimerManagement章节)中进行。我们再来看以下接口 x E v e n t G r o u p W a i t B i t s xEventGroupWaitBits xEventGroupWaitBits,该接口用来等待事件组中的某个单一事件或多个事件的发生,如果等待的事件没有发生则等待参数 x T i c k s T o W a i t xTicksToWait xTicksToWait指定的时间,如果在这个参数指定的时间之内等待的事件发生了,则等待事件的任务会被马上唤醒,如果在这个参数指定的时间之内等待的事件没有发生,也就是等待超时了,等待事件的任务也会离开等待状态。参数 u x B i t s T o W a i t F o r uxBitsToWaitFor uxBitsToWaitFor表示要等待的事件,参数 x W a i t F o r A l l B i t s xWaitForAllBits xWaitForAllBits就很好的体现了事件组的使用可以用来等待多个事件的这个特殊属性,当这个参数的值为pdFALSE的时候,如果参数 u x B i t s T o W a i t F o r uxBitsToWaitFor uxBitsToWaitFor指定了5个事件,那么只要这5个事件中的任何一个发生,等待的任务就会被唤醒,当这个参数的值为pdTRUE的时候,如果参数 u x B i t s T o W a i t F o r uxBitsToWaitFor uxBitsToWaitFor指定了5个事件,那么只有这5个事件全部发生的时候,等待的任务才会被唤醒。
     接下来弄了个简单的例子来简单的跑一跑事件组,主要代码如下所示,完整的工程代码在这里,这个例子创建了两个任务,一个任务用来等待事件组中的三个事件的发生,如果这三个事件没有发生的话就一直等待,另一个任务用来对这三个事件在事件组中对应的比特位进行置位,这三个事件分别对应开发板上面的三个按键的一次按下,当开发板上面的三个按键都被按下一次之后,等待事件的任务就会被唤醒。

static EventGroupHandle_t Event_Handle =NULL;



/* Definitions for the event bits in the event group. */
#define KEY0_PRESSED_BIT   ( 1UL << 0UL ) /* Event bit 0, which is set by a task. */
#define KEY1_PRESSED_BIT   ( 1UL << 5UL ) /* Event bit 5, which is set by a task. */
#define KEY_UP_PRESSED_BIT ( 1UL << 9UL ) /* Event bit 9, which is set by a task. */




static void vEventBitSettingTask(void* parameter)
{	
    while (1)
    {
		if( Key_Scan(1) == KEY0_PRES )       
		{
		    printf( "KEY 0 has been pressed.\r\n" );					
		    xEventGroupSetBits(Event_Handle,KEY0_PRESSED_BIT);  									
		}
		if( Key_Scan(1) == KEY1_PRES )       
		{
		    printf( "KEY 1 has been pressed.\r\n" );					
		    xEventGroupSetBits(Event_Handle,KEY1_PRESSED_BIT);  									
		}
		if( Key_Scan(1) == WKUP_PRES )       
		{
		    printf( "KEY UP has been pressed.\r\n" );					
		    xEventGroupSetBits(Event_Handle,KEY_UP_PRESSED_BIT);  									
		}				
		vTaskDelay(pdMS_TO_TICKS(20));  
    }	
}


static void vEventBitReadingTask(void* parameter)
{	 
    BaseType_t xReturn = pdTRUE;
    while (1)
    {
        xEventGroupWaitBits(Event_Handle, 
                            KEY0_PRESSED_BIT | KEY1_PRESSED_BIT | KEY_UP_PRESSED_BIT,
                            pdTRUE,   
                            pdTRUE,
                            portMAX_DELAY);
	    printf( "All three keys has been pressed.\r\n" );									
    }
}


int main(void)
{	 
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4);
	KEY_Init();
    uart_init(115200);	
	
	printf("Event groups demo start.\r\n");
	
	
    /* Before an event group can be used it must first be created. */
    Event_Handle = xEventGroupCreate();
	
    /* Create the task that sets event bits in the event group. */
    xTaskCreate( vEventBitSettingTask, "Bit Setter", 1000, NULL, 1, NULL );
    /* Create the task that waits for event bits to get set in the event group. */
    xTaskCreate( vEventBitReadingTask, "Bit Reader", 1000, NULL, 2, NULL );
 
    /* Start the scheduler so the created tasks start executing. */
    vTaskStartScheduler();	
	
    /* If all is well then main() will never reach here as the scheduler will
    now be running the tasks. If main() does reach here then it is likely that
    there was insufficient heap memory available for the idle task to be created.
    Chapter 2 provides more information on heap memory management. */
    while(1);   	
}

     下面来看一下用接口 x E v e n t G r o u p S e t B i t s xEventGroupSetBits xEventGroupSetBits和接口 x E v e n t G r o u p W a i t B i t s xEventGroupWaitBits xEventGroupWaitBits不太好实现多个任务同步的场景,假设任务 A A A接收到某事件之后需要将和此事件相应的操作分担给任务 B B B,任务 C C C和任务 D D D去执行,在任务 B B B,任务 C C C和任务 D D D完成相应的操作之前,任务 A A A不会再接收事件,因此这4个任务需要相互同步。每一个任务的同步点都是对应的任务已经完成了相应的操作,任务 A A A的同步点就是接收到了事件,任务 B B B,任务 C C C和任务 D D D的同步点都是完成了和任务 A A A接收的事件对应的操作,每一个任务到达自己的同步点之后都不能再继续前进,除非任务 A A A,任务 B B B,任务 C C C和任务 D D D都到达了自己的同步点。此时这种场景可以用接口 x E v e n t G r o u p S y n c xEventGroupSync xEventGroupSync来实现多个任务的同步,这个接口的原型如下所示:

EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
                             const EventBits_t uxBitsToSet,
                             const EventBits_t uxBitsToWaitFor,
                             TickType_t xTicksToWait )

     参数 u x B i t s T o S e t uxBitsToSet uxBitsToSet用来对事件组的结构体里面的变量 u x E v e n t B i t s uxEventBits uxEventBits的低24位或低8位的比特位进行置位,对于上面的场景来说就相当于任务 A A A的接收到了事件,任务 B B B,任务 C C C或任务 D D D完成了和任务 A A A接收的事件对应的操作,参数 u x B i t s T o W a i t F o r uxBitsToWaitFor uxBitsToWaitFor用来表示要等待的事件,对于上面的场景来说就相当于任务 A A A,任务 B B B,任务 C C C和任务 D D D都到达了自己的同步点。接下来再弄了个简单的例子来简单的跑一跑接口 x E v e n t G r o u p S y n c xEventGroupSync xEventGroupSync,主要代码如下所示,这个例子模拟了上面的场景,创建了4个任务,其实哲理创建的4个任务的函数都是一样的,根据传入的参数来区别是那一个任务,每一个任务的延时不同,用来模拟所需相应操作的时间。任务 A A A延时1秒,任务 B B B延时2秒,任务 C C C延时5秒,任务 D D D延时10秒,任务 A A A延时最少是因为上面的场景是任务 A A A在接收到事件时候,任务 B B B,任务 C C C和任务 D D D才开始相关操作的执行,至于任务 B B B,任务 C C C和任务 D D D每个任务具体的相关操作的时间都是不固定的。我们从打印中可以看出只有当所有任务的延时都结束之后,任务 A A A,任务 B B B,任务 C C C和任务 D D D才会一同退出同步点。这里任务中在执行打印语句的时候会先进入临界段( C r i t i c a l S e c t i o n s Critical\quad Sections CriticalSections),打印语句执行玩之后再退出临界段,这是因为串口打印是被多个任务共享的,如果有多个任务同时在向串口打印字符的话,会造成打印出的字符顺序混乱。

static EventGroupHandle_t Event_Handle =NULL;

/* Definitions for the event bits in the event group. */
#define TASK_A_BIT   ( 1UL << 0UL )  /* Event bit 0, which is set by task A. */
#define TASK_B_BIT   ( 1UL << 5UL )  /* Event bit 5, which is set by task B. */
#define TASK_C_BIT   ( 1UL << 9UL )  /* Event bit 9, which is set by task C. */
#define TASK_D_BIT   ( 1UL << 13UL ) /* Event bit 13,which is set by task D. */

static void vSyncingTask( void *pvParameters )
{	
    EventBits_t uxThisTasksSyncBit;
    const EventBits_t uxAllSyncBits = ( TASK_A_BIT | TASK_B_BIT | TASK_C_BIT | TASK_D_BIT );
    /* Four instances of this task are created - each task uses a different event
       bit in the synchronization. The event bit to use is passed into each task
       instance using the task parameter. Store it in the uxThisTasksSyncBit
       variable. 
	  */
    uxThisTasksSyncBit = ( EventBits_t ) pvParameters;	
    while (1)
    {
        /* Simulate this task taking some time to perform an action by delaying for a
        period of time. Each task's delay time is different.This prevents all four instances of this task reaching
        the synchronization point at the same time, and so allows the example's behavior to be observed more easily. */
        if(uxThisTasksSyncBit==((EventBits_t)(TASK_A_BIT)))
	    {
            vTaskDelay(pdMS_TO_TICKS(1000));						
		}
        else if(uxThisTasksSyncBit==((EventBits_t)(TASK_B_BIT)))
		{
            vTaskDelay(pdMS_TO_TICKS(2000));								
		}				
        else if(uxThisTasksSyncBit==((EventBits_t)(TASK_C_BIT)))
		{
            vTaskDelay(pdMS_TO_TICKS(5000));								
		}
        else if(uxThisTasksSyncBit==((EventBits_t)(TASK_D_BIT)))
		{
            vTaskDelay(pdMS_TO_TICKS(10000));								
		}					
        /* Print out a message to show this task has reached its synchronization
        point. pcTaskGetTaskName() is an API function that returns the name assigned
        to the task when the task was created. */
        taskENTER_CRITICAL();				
		printf("%s reached sync point\r\n",pcTaskGetTaskName( NULL ));
		taskEXIT_CRITICAL();				
        /* Wait for all the tasks to have reached their respective synchronization points. */
        xEventGroupSync( Event_Handle,/* The event group used to synchronize. */ 
                         uxThisTasksSyncBit, /* The bit set by this task to indicate it has reached the synchronization point. */ 
                         uxAllSyncBits,/* The bits to wait for, one bit for each task taking part in the synchronization. */
                         portMAX_DELAY  /* Wait indefinitely for all three tasks to reach the synchronization point. */
				       );
        /* Print out a message to show this task has passed its synchronization
        point. As an indefinite delay was used the following line will only be
        executed after all the tasks reached their respective synchronization
        points. */	
        taskENTER_CRITICAL();				
		printf("%s exited sync point\r\n",pcTaskGetTaskName( NULL ));
		taskEXIT_CRITICAL();
    }	
}


int main(void)
{	 
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4);
	KEY_Init();
    uart_init(115200);	
	
	printf("Event groups demo start.\r\n");
	
	
    /* Before an event group can be used it must first be created. */
    Event_Handle = xEventGroupCreate();
	
    /* Create three instances of the task. Each task is given a different name,
    which is later printed out to give a visual indication of which task is
    executing. The event bit to use when the task reaches its synchronization point
    is passed into the task using the task parameter. */
    xTaskCreate( vSyncingTask, "Task A", 1000, (void * const)(TASK_A_BIT), 1, NULL );
    xTaskCreate( vSyncingTask, "Task B", 1000, (void * const)(TASK_B_BIT), 1, NULL );
    xTaskCreate( vSyncingTask, "Task C", 1000, (void * const)(TASK_C_BIT), 1, NULL );
    xTaskCreate( vSyncingTask, "Task D", 1000, (void * const)(TASK_D_BIT), 1, NULL );	
    /* Start the scheduler so the created tasks start executing. */
    vTaskStartScheduler();
	
    /* If all is well then main() will never reach here as the scheduler will
    now be running the tasks. If main() does reach here then it is likely that
    there was insufficient heap memory available for the idle task to be created.
    Chapter 2 provides more information on heap memory management. */
    while(1);   	
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/404302.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Sora----打破虚实之间的最后一根枷锁----这扇门的背后是人类文明的晟阳还是最后的余晖

目录 一.Sora出道即巅峰 二.为何说Sora是该领域的巨头 三.Sora无敌的背后究竟有怎样先进的处理技术 1.Spacetime Latent Patches 潜变量时空碎片&#xff0c;建构视觉语言系统 2.扩散模型与Diffusion Transformer&#xff0c;组合成强大的信息提取器 3.DiT应用于潜变量时…

每日五道java面试题之spring篇(三)

目录&#xff1a; 第一题 ApplicationContext和BeanFactory有什么区别&#xff1f;第二题 Spring中的事务是如何实现的&#xff1f;第三题 Spring中什么时候Transactional会失效&#xff1f;第四题 Spring容器启动流程是怎样的&#xff1f;第五题 Spring Boot、Spring MVC 和 S…

隐藏饿了么el-select组件的el-select-dropdown部分,只使用el-select的显示框

隐藏饿了么el-select组件的el-select-dropdown部分,只使用el-select的显示框 问题: 由于el-select组件的el-select-dropdown部分是自动插入在最外层Body上的&#xff0c;所以在当前组件的scoped中让el-select-dropdown组件display:none不会生效所以需要&#xff1a; :popper-…

ZS Associates致盛咨询是什么公司?排名怎么样?

随着商业化时代的加速演进&#xff0c;咨询公司在企业发展中的“智囊团”角色愈发突显。对于医药企业来说&#xff0c;一个优秀的咨询团队不仅可以帮助推动整体战略转型及内部改革&#xff0c;还对药品研发、营销起到优化促进作用。 那什么样的咨询企业可称之为优秀的咨询企业…

【Java EE初阶二十】http的简单理解(一)

1. 初识http HTTP 最新的版本应该是 HTTP/3.0&#xff0c;目前大规模使用的版本 HTTP/1.1&#xff1b; 下面来简单说明一下使用 HTTP 协议的场景: 1、浏览器打开网站 (基本上) 2、手机 APP 访问对应的服务器 (大概率) 前面的 TCP与UDP 和http不同&#xff0c;HTTP 的报文格式&a…

【方法】PDF如何与其它格式文件互相转换?

在工作上&#xff0c;有时候我们需要把PDF文件转换成其他格式的文件&#xff0c;比如Word、PPT、jpg等&#xff0c;或者是其他格式文件转换成PDF&#xff0c;那具体要如何操作呢&#xff1f;不清楚的小伙伴一起来看看吧&#xff01; 想把PDF文件转换成其他格式文件&#xff0c…

GoLand 相关

goland 下载依赖 go mod tidy&#xff1a;保持依赖整洁 go mod tidy 命令的作用是清理未使用的依赖&#xff0c;并更新 go.mod 以及 go.sum 文件。 go mod tidy 和 go mod vendor 两个命令是维护项目依赖不可或缺的工具。go mod tidy 确保了项目的 go.mod 文件精简且准确&…

掌握这几个技巧,才敢称为Jenkins大神!

01 Performance插件兼容性问题 自由风格项目中&#xff0c;有使用 Performance 插件收集构建产物&#xff0c;但是截至到目前最新版本&#xff08;Jenkins v2.298&#xff0c;Performance&#xff1a;v3.19&#xff09;&#xff0c;此插件和Jenkins都存在有兼容性问题&#xf…

openEuler安装MySQL客户端、openEuler安装MySQL-client、openEuler部署MySQL-client

MySQL客户端下载链接&#xff1a;https://downloads.mysql.com/archives/community/ mysql-community-client-5.7.30-1.el7.x86_64.rpm mysql-community-common-5.7.30-1.el7.x86_64.rpm mysql-community-libs-5.7.30-1.el7.x86_64.rpm 3个必选 8.0.22以上的版本是4个&…

vue3 vite 经纬度逆地址解析

在web端测试经纬度逆地址解析有2中方式&#xff0c;先准备好两个应用key 第一种&#xff0c;使用“浏览器端”应用类型 const address ref() const latitude ref() // 经度 const longitude ref() // 纬度 const ak 你的key // 浏览器端 function getAddressWeb() {// 创建…

(全注解开发)学习Spring-MVC的第三天

全注解开发 第一部分 : 1.1 消除spring-mvc.xml 这些是原来spring-mvc.xml配置文件的内容 <!--1、组件扫描, 使Controller可以被扫描到--><context:component-scan base-package"com.itheima.controller"/><!--2、非自定义的Bean, 文件上传解析器--&…

【ESP32 IDF】静态库 libxxx.a 的使用

ESP32静态库生成和使用 1. 简单描述2. 生成静态库2. 使用静态库 1. 简单描述 开发方式为 IDF5.0参考连接为 【ESP32学习之路4——生成并使用.a静态库】 2. 生成静态库 新建组件 【printhelloword】修改里面的程序函数为hello void hello(void) {printf("你好&#xff…

腾讯大佬, 职场经验分享!

看一看别人的职业经历、生活感悟、观点思考&#xff0c;往往也可以给我们一些启发。 以下是正文&#xff0c;内容仅代表作者观点&#xff0c;文中的我也均指作者。 我觉得&#xff0c;你们可以静下心来&#xff0c;听听我的故事&#xff0c;相信你们会有收获的。 下周&#x…

LED智能互联办公室照明恒流调光IC芯片无频闪H5114

调光高辉度65536级/高精度3% LED降压型恒流驱动器H5114 产品描述 H5114是一款外围电路简单的多功能平 均电流型LED恒流驱动器&#xff0c;适用于5-90V电压范围的非隔离式大功率恒流LED驱动领域。 芯片采用了平均电流模式控制&#xff0c;输出电流精度在3&#xff05;&#xff…

创新性3D数据合成模型,微软推出EgoGen

随着AR、VR等设备的广泛应用,第一人称的应用开始增多。但在研发方面面临不同的挑战,例如&#xff0c;图像模糊、视觉混乱、遮挡更严重等&#xff0c;给视觉模型的训练带来重大挑战。 一方面,人工标注真实第一视角数据集&#xff0c;来培训深度学习模型的成本和难度都很高。另一…

月之暗面:Moonshot AI接口总结

前言&#xff1a; 开发者们只需访问 platform.moonshot.cn&#xff0c;便能创建自己的 API Key&#xff0c;进而将 Kimi 智能助手背后的同款 moonshot 模型能力&#xff0c;如长文本处理和出色的指令遵循等&#xff0c;集成至自己的产品中。这不仅增强了现有产品的功能&#x…

【原创教程】汇川H5U入门教案

一、新建H5U工程 1. 双击AutoShop软件桌面快捷方式,打开AutoShop软件。 2. 在菜单栏选择“文件 > 新建工程”或在工具栏单击 ,再打开的对话框中选择编辑器类型,再选择H5U作为PLC类型。 3. 输入工程名并选择保存路径,然后单击“确定”创建新工程,随即进入工程主界面…

【安卓基础5】中级控件

&#x1f3c6;作者简介&#xff1a;|康有为| &#xff0c;大四在读&#xff0c;目前在小米安卓实习&#xff0c;毕业入职 &#x1f3c6;本文收录于 安卓学习大全持续更新中&#xff0c;欢迎关注 &#x1f3c6;安卓学习资料推荐&#xff1a; 视频&#xff1a;b站搜动脑学院 视频…

汽车常识网:电脑主机如何算功率的计算方法?

今天汽车知识网就给大家讲解一下如何计算一台主机的功率。 它还会解释如何计算计算机主机所需的功率&#xff1f; &#xff1f; &#xff08;如何计算电脑主机所需的功率&#xff09;进行说明。 如果它恰好解决了您现在面临的问题&#xff0c;请不要忘记关注本站。 让我们现在就…

PyQt5图片浏览器

PyQt5图片浏览器 实现方式功能实现具体代码 界面实现pillow源码修改ImageQt错误主页面布局 项目开源地址 分享一个图片浏览器 实现方式 qt本身有一个QGraphicsView类用来当做视图框架。 具体参考&#xff1a;如何在pyqt中使用 QGraphicsView 实现图片查看器 不过大佬给的例子…