FreeRTOS的简单介绍

news2025/7/22 22:41:46

一、FreeRTOS介绍

FreeRTOS并不是实时操作系统,因为它是分时复用的

利用CubeMX快速移植

二、快速移植流程

1. 在 SYS 选项里,将 Debug 设为 Serial Wire ,并且将 Timebase Source 设为 TIM2 (其它定时器也行)。为何要如此配置?下文解说。

裸机的时钟源默认是 SysTick ,但是开启 FreeRTOS 后, FreeRTOS 会占用 SysTick (用来生成 1ms定时,用于任务调度),所以需要需要为其他总线提供另外的时钟源。

2. RCC 里的 HSE 设置为 Crystal/Ceramic Resonator

3. 打开串口

4. 时钟按下图配置

5. 选择 FREERTOS 选项,并将 Interface 改为 CMSIS_V1

6. 配置项目信息,并导出代码。

三、任务的创建与删除

实操

四、任务的调度

void StarttaskKEY1(void const * argument)
{
  /* USER CODE BEGIN StarttaskKEY1 */
  /* Infinite loop */
  for(;;)
  {
      if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
          {
          printf("KEY1被按下来\r\n");
          if(taskLED1Handle  ==  NULL)
          {
              printf("任务不存在,准备创建任务1!\r\n");
        
          osThreadDef(taskLED1, StarttaskLED1, osPriorityNormal, 0, 128);
          taskLED1Handle = osThreadCreate(osThread(taskLED1), NULL);
          if(taskLED1Handle != NULL )
          
             printf("任务创建完成!\r\n");

          }
          else
          {
          printf("删除任务!\r\n");
          osThreadTerminate(taskLED1Handle);
          taskLED1Handle = NULL;
          }

          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET);
      
      
      
      }
    osDelay(10);
  }
  /* USER CODE END StarttaskKEY1 */
}

/* USER CODE BEGIN Header_StarttaskKEY2 */
/**
* @brief Function implementing the taskKEY2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StarttaskKEY2 */
void StarttaskKEY2(void const * argument)
{
  /* USER CODE BEGIN StarttaskKEY2 */
    static int flag =0;
  /* Infinite loop */
  for(;;)
  {
      
      if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
          {
          printf("KEY2被按下来\r\n");
          if(flag == 0)
          {
          osThreadSuspend(taskLED2Handle);
              printf("任务2已暂停!\r\n");
              flag=1;
          }
         else
         {
         osThreadResume(taskLED2Handle);
         printf("任务2已恢复\r\n");
         flag=0;

         }

          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET);
      
      
      
      }
    osDelay(1);
  }
  /* USER CODE END StarttaskKEY2 */
}

六、队列

队列又称消息队列,是一种常用于任务间通信的数据结构,队列可以在任务与任务间、中断和任务间传递信息。

队列项目:队列中的每一个数据;

队列长度:队列能够存储队列项目的最大数量;

创建队列时,需要指定队列长度及队列项目大小

代码如下:

void StarttaskSend(void const * argument)
{
  /* USER CODE BEGIN StarttaskSend */
    uint16_t buf =100;
    BaseType_t status ;
  /* Infinite loop */
  for(;;)
  {
       if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
          {
            status=xQueueSend(myQueueHandle,&buf,0);    //第一个数据是句柄  第二个是到队列中的数据 第三个是超时
            if(status == pdTRUE)
                printf("写入队列成功,写入值为%d\r\n",buf);
            else
                printf("写入队列失败\r\n");
            
              
          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET);
      
      
      
      }
    osDelay(1);
  }
  /* USER CODE END StarttaskSend */
}

/* USER CODE BEGIN Header_StarttaskReceive */
/**
* @brief Function implementing the taskReceive thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StarttaskReceive */
void StarttaskReceive(void const * argument)
{
  /* USER CODE BEGIN StarttaskReceive */
     uint16_t buf;
     BaseType_t status ;
  /* Infinite loop */
  for(;;)
  {
      if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
          {
            status=xQueueReceive(myQueueHandle,&buf,0);    //第一个数据是句柄  第二个是接收到的队列中的数据 第三个是超时
            if(status == pdTRUE)
                printf("读取队列成功,读取值为%d\r\n",buf);
            else
                printf("读取队列失败\r\n");
            
              
          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET);
      
      
      
      }
      
    osDelay(1);
  }
  /* USER CODE END StarttaskReceive */
}

七、二值信号量

八、计数型信号量

void StarttaskGive(void const * argument)
{
  /* USER CODE BEGIN StarttaskGive */
  /* Infinite loop */
  for(;;)
  {
       if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
          {
            if(xSemaphoreGive(myCountingSemHandle)  == pdTRUE)
                printf("计数型信号量放入成功\r\n");
            else
                printf("计数型信号量放入失败\r\n");
          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET);
      
      
      
      }
    osDelay(1);
  }
  /* USER CODE END StarttaskGive */
}

/* USER CODE BEGIN Header_StarttaskTake */
/**
* @brief Function implementing the taskTake thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StarttaskTake */
void StarttaskTake(void const * argument)
{
  /* USER CODE BEGIN StarttaskTake */
  /* Infinite loop */
  for(;;)
  {

      if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
          {
            if(xSemaphoreTake(myCountingSemHandle,0)  == pdTRUE)    //portMAX_DELAY  死等
                printf("计数型信号量获取成功\r\n");
            else
                printf("计数型信号量获取失败\r\n");
          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET);

      
      }
    osDelay(1);
  }
  /* USER CODE END StarttaskTake */
}

九、互斥量

在多数情况下,互斥型信号量和二值型信号量非常的相似,但是从功能上二值型信号量用于同步,而互斥型信号量用于资源保护。

互斥型信号量和二值型信号量还有一个最大的区别,互斥型信号量可以有效地解决优先级反转的现象。

互斥量的特点
唯一访问:即互斥量保证在任意时间段,只有一个任务能够持有互斥量,即独占访问共享资源
优先级继承:当一个高优先级任务因为等待互斥量而被阻塞时,此时正持有互斥量的低优先级任务会临时继承高优先级任务的优先级,以防止优先级反转问题。
递归锁定:同一个任务可以多次获得同一个互斥量(递归互斥),每次成功获取后需要对应次数的释放操作。

任务优先级反转示例:
设有三个任务:

任务A:高优先级

任务B:中优先级

任务C:低优先级

步骤:

任务C获取资源:低优先级任务C获取一个共享资源并开始执行;
任务A被阻塞:高优先级任务需要访问该资源,但由于任务C持有资源,任务A被阻塞并等待资源释放;
任务B运行:此时,中等优先级任务B开始运行,因为它不需要访问任务C持有的资源,因此它不会被阻塞。由于任务B的优先级高于任务C,任务B持续运行,占用了CPU时间。
任务C无法运行:任务C被任务B抢占,无法继续执行,也就无法释放高优先级任务A所需的资源。
任务A优先级被反转:结果是高优先级任务A被中等优先级任务B间接阻塞,直到任务B完成执行并且任务C重新获得CPU时间并释放资源。

十、事件标志组

事件标志位:用一个位,来表示事件是否发生

事件标志组:一组事件标志位的集合,可以简单的理解时间标志组,就是一个整体。

事件标志租的特点:

        它的每一个位表示一个时间(高8位不算);

        每一个事件的含义,由用户自己决定,如:bit0表示按键是否按下,bit1表示是否接收到消息...(这些位的值为1:表示事件发生了;值为0,表示事件未发生)

        任意任务或中断都可以读写这些位;

        可以等待某一位成立,或者等待多位同时成立;

1. 创建事件标志组
EventGroupHandle_t xEventGroupCreate ( void );
参数:
返回值:
成功,返回对应事件标志组的句柄; 失败,返回 NULL
2. 设置事件标志位
EventBits_t xEventGroupSetBits ( EventGroupHandle_t xEventGroup , const EventBits_t uxBitsToSet );
参数:
xEventGroup :对应事件组句柄。 uxBitsToSet :指定要在事件组中设置的一个或多个位的按位
值。
返回值:
设置之后事件组中的事件标志位值。
3. 清除事件标志位
EventBits_t xEventGroupClearBits ( EventGroupHandle_t xEventGroup , const EventBits_t uxBitsToClear );
参数:
xEventGroup :对应事件组句柄。 uxBitsToClear :指定要在事件组中清除的一个或多个位的按位
值。
返回值:
清零之前事件组中事件标志位的值。
4. 等待事件标志位
EventBits_t xEventGroupWaitBits ( const EventGroupHandle_t xEventGroup , const EventBits_t uxBitsToWaitFor , const BaseType_t xClearOnExit , const BaseType_t xWaitForAllBits , TickType_t xTicksToWait );
参数: xEventGroup :对应的事件标志组句柄 uxBitsToWaitFor :指定事件组中要等待的一个或多个事件
位的按位值 xClearOnExit pdTRUE—— 清除对应事件位, pdFALSE—— 不清除 xWaitForAllBits
pdTRUE—— 所有等待事件位全为 1 (逻辑与), pdFALSE—— 等待的事件位有一个为 1 (逻辑或)
xTicksToWait :超时
返回值:
等待的事件标志位值:等待事件标志位成功,返回等待到的事件标志位 其他值:等待事件标志位
失败,返回事件组中的事件标志位

十一、任务通知

模拟二值信号量
void StartTasksend(void const * argument)
{
  /* USER CODE BEGIN StartTasksend */
  /* Infinite loop */
  for(;;)
  {
      if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
          {
            xTaskNotifyGive(TaskreceiveHandle);      //任务通知,不带通知值
            printf("任务通知,模拟二值信号量发送成功 ! \r\n");
            

          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET);
      
      
      
      }
    osDelay(10);
  }
  /* USER CODE END StartTasksend */
}

/* USER CODE BEGIN Header_StartTaskreceive */
/**
* @brief Function implementing the Taskreceive thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskreceive */
void StartTaskreceive(void const * argument)
{
  /* USER CODE BEGIN StartTaskreceive */
    uint32_t rev = 0;
    
  /* Infinite loop */
  for(;;)
  {
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
          {
            rev = ulTaskNotifyTake(pdTRUE , portMAX_DELAY);      //任务通知,不带通知值
              if(rev !=0)     //非0:接收成功,返回任务通知的通知值
                 printf("任务通知,模拟二值信号量接收成功 ! \r\n");

          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET);
      }
    osDelay(1);
  }
  /* USER CODE END StartTaskreceive */
}
模拟计数型信号量
void StartTasksend(void const * argument)
{
  /* USER CODE BEGIN StartTasksend */
  /* Infinite loop */
  for(;;)
  {
      if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
          {
            xTaskNotifyGive(TaskreceiveHandle);      //任务通知,不带通知值
            printf("任务通知,模拟计数型信号量发送成功 ! \r\n");
            

          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET);
      
      
      
      }
    osDelay(10);
  }
  /* USER CODE END StartTasksend */
}

/* USER CODE BEGIN Header_StartTaskreceive */
/**
* @brief Function implementing the Taskreceive thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskreceive */
void StartTaskreceive(void const * argument)
{
  /* USER CODE BEGIN StartTaskreceive */
    uint32_t rev = 0;
    
  /* Infinite loop */
  for(;;)
  {
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
          {
            rev = ulTaskNotifyTake(pdFALSE , portMAX_DELAY);      //任务通知,不带通知值   特别注意这里pdTRUE是二值  pdFALSE 是计数型
              if(rev !=0)     //非0:接收成功,返回任务通知的通知值
                 printf("任务通知,模拟计数型信号量接收成功 ! rev=  %d \r\n" , rev);

          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET);
      }
    osDelay(1);
  }
  /* USER CODE END StartTaskreceive */
}
模拟事件标志组
void StartTasksend(void const * argument)
{
  /* USER CODE BEGIN StartTasksend */
  /* Infinite loop */
  for(;;)
  {
      if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
          {
           printf("将bit0位置置1\r\n");
           xTaskNotify(TaskreceiveHandle,0x01,eSetBits);
          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET);
      
      
      
      }
      

            if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
          {
           printf("将bit1位置置1\r\n");
           xTaskNotify(TaskreceiveHandle,0x02,eSetBits);
          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET);
      
      
      
      }
   
    osDelay(10);
  }
  /* USER CODE END StartTasksend */
}

/* USER CODE BEGIN Header_StartTaskreceive */
/**
* @brief Function implementing the Taskreceive thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskreceive */
void StartTaskreceive(void const * argument)
{
  /* USER CODE BEGIN StartTaskreceive */
    uint32_t notify_val = 0;
    uint32_t event_bit =0;
    
  /* Infinite loop */
  for(;;)
  {
       xTaskNotifyWait(0,0xFFFFFFFF,&notify_val,portMAX_DELAY);
       if(notify_val & 0x01)     //判断bit0位是否为0
           event_bit |= 0x01;
       if(notify_val & 0x02)     //判断bit1位是否为1
           event_bit |=0x02;
       if(event_bit ==(0x03))     //只有两个位都置为1时才可以
       {
       printf("任务通知模拟事件标志组接收成功! \r\n");
           event_bit =0;
       
       }
       
  }
  /* USER CODE END StartTaskreceive */
}

模拟邮箱
void StartTasksend(void const * argument)
{
  /* USER CODE BEGIN StartTasksend */
  /* Infinite loop */
  for(;;)
  {
      if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
          {
           printf("按键1按下\r\n");
           xTaskNotify(TaskreceiveHandle,1,eSetValueWithOverwrite);     //eSetValueWithOverwrite 带覆写  eSetValueWithoutOverwrite  不带覆写
          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET);
      
      
      
      }
      

            if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
      {
       osDelay(20);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)
          {
           printf("按键2按下\r\n");
           xTaskNotify(TaskreceiveHandle,2,eSetValueWithOverwrite);
          }
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET);
      
      
      
      }
   
    osDelay(10);
  }
  /* USER CODE END StartTasksend */
}

/* USER CODE BEGIN Header_StartTaskreceive */
/**
* @brief Function implementing the Taskreceive thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskreceive */
void StartTaskreceive(void const * argument)
{
  /* USER CODE BEGIN StartTaskreceive */
    uint32_t notify_val = 0;
    uint32_t event_bit =0;
    
  /* Infinite loop */
  for(;;)
  {
      xTaskNotifyWait(0,0xFFFFFFFF,&notify_val,portMAX_DELAY);
      printf("接收到的通知值为: %d\r\n",notify_val);
      osDelay(1);
  }
  /* USER CODE END StartTaskreceive */
}

十二、延时函数

十三、软件定时器

void StartDefaultTask(void const * argument)
{
  /* USER CODE BEGIN StartDefaultTask */
    //osTimerStart(myTimer01Handle,1000);          //周期
    xTimerChangePeriod(myTimer01Handle,pdMS_TO_TICKS(1000),0);        //官方的定时函数      
    osTimerStart(myTimer02Handle,2000);          //单次
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

/* Callback01 function */
void Callback01(void const * argument)
{
  /* USER CODE BEGIN Callback01 */
    printf("lvshiyan shuai\r\n");
  /* USER CODE END Callback01 */
}

/* Callback02 function */
void Callback02(void const * argument)
{
  /* USER CODE BEGIN Callback02 */
    printf("lujingjing mei\r\n");

  /* USER CODE END Callback02 */
}

十四、中断

在stm32f1xx_it.c 文件中

void EXTI0_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI0_IRQn 0 */

  /* USER CODE END EXTI0_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
  /* USER CODE BEGIN EXTI0_IRQn 1 */
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    uint32_t snd=1;
    xQueueSendFromISR(myQueue01Handle,&snd,NULL);       //在中断中往队列的尾部写入信息


  /* USER CODE END EXTI0_IRQn 1 */
}

在freertos.c中

void StartDefaultTask(void const * argument)
{
  /* USER CODE BEGIN StartDefaultTask */
    uint32_t rev =0;
  /* Infinite loop */
  for(;;)
  {
     if( xQueueReceive(myQueue01Handle,&rev,portMAX_DELAY) == pdTRUE)
         printf("rev = %d \r\n",rev);
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入解析C++引用:从别名机制到函数特性实践

1.C引用 1.1引用的概念和定义 引用不是新定义⼀个变量,而是给已存在变量取了⼀个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同⼀块内存空间。比如四大名著中林冲,他有一个外号叫豹子头,类比到C里就…

项目交付后缺乏回顾和改进,如何持续优化

项目交付后缺乏回顾和改进可通过建立定期回顾机制、实施反馈闭环流程、开展持续学习和培训、运用数据驱动分析、培养持续改进文化来持续优化。 其中,实施反馈闭环流程尤其重要,它能够确保反馈信息得到有效传递、处理与追踪,形成良好的改进生态…

从0开始学习R语言--Day15--非参数检验

非参数检验 如果在进行T检验去比较两组数据差异时,假如数据里存在异常值,会把数据之间的差异拉的很大,影响正常的判断。那么这个时候,我们可以尝试用非参数检验的方式来比较数据。 假设我们有A,B两筐苹果&#xff0c…

EC2 实例详解:AWS 的云服务器怎么玩?☁️

弹性计算、灵活计费、全球可用,AWS EC2 全攻略 在 AWS 生态中,有两个核心服务是非常关键的,一个是 S3(对象存储),另一个就是我们今天的主角 —— Amazon EC2(Elastic Compute Cloud&#xff09…

第三发 DSP 点击控制系统

背景 ​ 在第三方 DSP 上投放广告,需要根据 DP Link 的点击次数进行控制。比如当 DP Link 达到 5000 后,后续的点击将不能带来收益,但是后续的广告却要付出成本。因此需要建立一个 DP Link 池,当 DP Link 到达限制后,…

【笔记】在 MSYS2 MINGW64 环境中降级 NumPy 2.2.6 到 2.2.4

📝 在 MSYS2 MINGW64 环境中降级 NumPy 到 2.2.4 ✅ 目标说明 在 MSYS2 的 MINGW64 工具链环境中,将 NumPy 从 2.2.6 成功降级到 2.2.4。 🧰 环境信息 项目内容操作系统Windows 11MSYS2 终端类型MINGW64(默认终端)Py…

vue入门环境搭建及demo运行

提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 vue简介:第一步:安装node.jsnode简介第二步:安装vue.js第三步:安装vue-cli工具第四步 :安装webpack第五步…

原始数据去哪找?分享15个免费官方网站

目录 一、找数据的免费官方网站 (一)国家级数据宝库:权威且全面 1.中国国家统计局 2.香港政府数据中心 3.OECD数据库 (二)企业情报中心:洞察商业本质 4.巨潮资讯 5.EDGAR数据库 6.天眼查/企查查&a…

宝塔部署 Vue + NestJS 全栈项目

宝塔部署 Vue NestJS 全栈项目 前言一、Node.js版本管理器1、安装2、配置 二、NestJS项目管理(等同Node项目)1、Git安装2、拉取项目代码3、无法自动认证4、添加Node项目5、配置防火墙(两道) 三、Vue项目管理1、项目上传2、Nginx安…

# [特殊字符] Unity UI 性能优化终极指南 — LayoutGroup篇

🎯 Unity UI 性能优化终极指南 — LayoutGroup篇 🧩 什么是 LayoutGroup? LayoutGroup 是一类用于 自动排列子节点 的UI组件。 代表组件: HorizontalLayoutGroupVerticalLayoutGroupGridLayoutGroup 可以搭配: Conte…

2024-2025-2-《移动机器人设计与实践》-复习资料-8……

2024-2025-2-《移动机器人设计与实践》-复习资料-1-7-CSDN博客 08 移动机器人基础编程 单选题(6题) 在ROS中,用于移动机器人速度控制的消息类型通常是? A. std_msgs/StringB. geometry_msgs/TwistC. sensor_msgs/ImageD. nav_ms…

如何监测光伏系统中的电能质量问题?分布式光伏电能质量解决方案

根据光伏相关技术规范要求,通过10(6)kV~35kV电压等级并网的变流器类型分布式电源应在公共连接点装设满足GB/T 19862要求的A级电能质量监测装置。用于监测分布式光伏发出的电能的质量,指标包括谐波、电压偏差、电压不平衡度、电压波动和闪变等。 CET中电…

SPL 轻量级多源混算实践 4 - 查询 MongoDB

除了以上常见数据源,还有 NoSQL、MQ 等数据源,其中以 MongoDB 最为常用。我们用 SPL 连接 MongoDB 做计算。 导入 MongoDB 数据。 外部库 SPL 支持的多种数据源大概分两类,一类是像 RDB 有 JDBC 直接使用,或者文件等直接读取&a…

Maestro CLI云端测试以及github cl,bitrise原生cl的测试流程

昨天我们了解了maestro测试框架以及maestro studio工具以及创建我们的第一个flow,然后通过例子在maestro cli云端进行测试请求并且成功,今天我们就在我们自己的app上简单的进行三种测试流程,maestro cli云端测试,github cl集成测试…

25年宁德时代新能源科技SHL 测评语言理解数字推理Verify题库

宁德时代新能源科技的SHL测评中,语言理解部分主要考察阅读理解、逻辑填空和语句排序等题型,要求应聘者在17分钟内完成30题。阅读理解需要快速捕捉文章主旨和理解细节信息;逻辑填空则要根据语句逻辑填入最合适的词汇;语句排序是将打…

AutoGenTestCase - 借助AI大模型生成测试用例

想象一下,你正在为一个复杂的支付系统编写测试用例,需求文档堆积如山,边缘场景层出不穷,手动编写让你焦头烂额。现在,有了AutoGenTestCase,这个AI驱动的“测试用例生成机”可以从需求文档中自动生成数百个测…

vue+cesium示例:3Dtiles三维模型高度调整(附源码下载)

接到一位知识星友的邀请,实现他需要3Dtiles三维模型的简单高度调整需求,适合学习Cesium与前端框架结合开发3D可视化项目。 demo源码运行环境以及配置 运行环境:依赖Node安装环境,demo本地Node版本:推荐v18。 运行工具:…

线程池RejectedExecutionException异常

文章目录 1、报错2、定位3、修复4、线程池使用的一点思考 1、报错 检索项目日志时,发现一个异常堆栈信息,核心报错: java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.CompletableFuture$AsyncSupply480a10c7…

当 “欧洲版 Cursor” 遇上安全危机

在 AI 编程助手蓬勃发展的当下,安全问题正成为行业不容忽视的隐忧。近期,AI 编程助手公司 Replit 与号称 “欧洲版 Cursor” 的 Lovable 之间,因安全漏洞问题掀起了一场风波,引发了业界的广泛关注。​ Replit 的员工 Matt Palmer…

【如何在IntelliJ IDEA中新建Spring Boot项目(基于JDK 21 + Maven)】

AA. 我的开发环境配置与核心工具链解析 一、开发环境全览 C:\Users\Again>java -version java version "21.0.1" 2023-10-17 LTS Java(TM) SE Runtime Environment (build 21.0.112-LTS-29) Java HotSpot(TM) 64-Bit Server VM (build 21.0.112-LTS-29, mixed m…