首页 > 其他分享 >02.FreeRTOS的移植

02.FreeRTOS的移植

时间:2024-07-28 21:25:40浏览次数:6  
标签:02 FreeRTOS void delay SysTick include OS 移植

文章目录

FreeRTOS移植到STM32F103ZET6上的详细步骤

1. 移植前的准备工作

  • **基础工程:**内存管理部分的例程源码和基本定时器的例程源码
    在这里插入图片描述

    使用实验8 基本定时器和实验36 内存管理两个实验,内存管理实验做为移植的目标文件,为了获得定时器的功能,需要把基本定时器实验部分的TIMER文件夹拷贝到内存管理实验的BSP文件夹里面。

  • FreeRTOS源码:

    本例程使用的是FreeRTOS内核源码的版本V10.4.6,即FreeRTOS v2021.00。获取路径:软件资料→FreeRTOS学习资料→FreeRTOSv2202112.00.zip。
    在这里插入图片描述

2. 添加FreeRTOS文件

  1. 添加FreeRTOS源码,在基础工程的Middlewares文件夹中新建一个FreeRTOS子文件夹:
    在这里插入图片描述

    将FreeRTOS内核源码的 Source 文件夹下的所有文件添加到工程的 FreeRTOS 文件夹中:
    在这里插入图片描述

  2. 将文件添加到工程

    打开基础工程,新建两个文件分组,分别为Middlewares/FreeRTOS_COREMiddlewares/FreeRTOS_PORT

    Middlewares/FreeRTOS_CORE:存放FreeRTOS内核C源码文件

    Middlewares/FreeRTOS_PORT:存放FreeRTOS内核的移植文件,分别添加heap_x.cport.c
    在这里插入图片描述

    然后把相关文件拷贝到这两个路径下:
    在这里插入图片描述

    1. 添加头文件路径

      一个是FreeRTOS/include,另一个是port.c的路径

      在这里插入图片描述

    2. 添加FreeRTOSConfig.h文件

      因为需要对配置文件进行裁剪并且要结合STM32单片机,我们直接从移植好的例程里面拷贝即可

      在这里插入图片描述

3. 修改SYSTEM文件

  1. sys.h文件

    sys.h文件的修改很简单,在sys.h文件中使用了宏SYS SUPPORT_OS来定义是否支持OS,因为要支持FreeRTOS,因此应当将宏SYS SUPPORT_OS定义为1,具体修改如下所示:

    修改前:

    /**
     * SYS_SUPPORT_OS用于定义系统文件夹是否支持OS
     * 0,不支持OS
     * 1,支持OS
     */
    #define SYS_SUPPORT_OS          0
    

    修改后:

    /**
     * SYS_SUPPORT_OS用于定义系统文件夹是否支持OS
     * 0,不支持OS
     * 1,支持OS
     */
    #define SYS_SUPPORT_OS          1
    
    
  2. usart.c文件

    usart.c文件的修改也很简单,一共有两个地方需要修改,首先就是串口的中断服务函数,原本在使用uCOS的时候,进入和退出中断需要添加OSIntEnter()和OSIntExit()两个函数,这是uCOS对于中断的相关处理机制,而FreeRTOS中并没有这种机制,因此将这两行代码删除,修改后串口的中断服务函数如下所示:

    修改前:

    void USART_UX_IRQHandler(void)
    {
    #if SYS_SUPPORT_OS                          /* 使用OS */
        OSIntEnter();    
    #endif
    
        HAL_UART_IRQHandler(&g_uart1_handle);   /* 调用HAL库中断处理公用函数 */
    
    #if SYS_SUPPORT_OS                          /* 使用OS */
        OSIntExit();
    #endif
    
    }
    

    修改后:

    void USART_UX_IRQHandler(void)
    {
    
    
        HAL_UART_IRQHandler(&g_uart1_handle);   /* 调用HAL库中断处理公用函数 */
    
    		while (HAL_UART_Receive_IT( &g_uart1_handle,(uint8_t *)g_rx_buffer,RXBUFFERSIZE) != HAL_OK)/* 重新开启中断并接收数据 */
    		{
    			/* 如果出错会卡死在这里 */
    		}
    
    }
    

    接下来usart.c要修改的第二个地方就是导入的头文件,因为在串口的中断服务函数当中已经删除了uCOS的相关代码,并且也没有使用到FreeRTOS的相关代码,因此将usart.c中包含的关于OS的头文件删除,要删除的代码如下所示:

    /* 如果使用 os,则包括下面的头文件即可. */
    #if SYS_SUPPORT_OS
    #include "includes.h" /* os 使用 */
    #endif
    
  3. delay.c文件

    (1)删除适用于 µC/OS 但不适用于 FreeRTOS 的相关代码

    /* 定义 g_fac_ms 变量, 表示 ms 延时的倍乘数,
    * 代表每个节拍的 ms 数, (仅在使能 os 的时候,需要用到)
    */
    static uint16_t g_fac_ms = 0;
    /*
    * 当 delay_us/delay_ms 需要支持 OS 的时候需要三个与 OS 相关的宏定义和函数来支持
    * 首先是 3 个宏定义:
    * delay_osrunning :用于表示 OS 当前是否正在运行,以决定是否可以使用相关函数
    * delay_ostickspersec :用于表示 OS 设定的时钟节拍,
    * delay_init 将根据这个参数来初始化 systick
    * delay_osintnesting :用于表示 OS 中断嵌套级别,因为中断里面不可以调度,
    * delay_ms 使用该参数来决定如何运行
    * 然后是 3 个函数:
    * delay_osschedlock :用于锁定 OS 任务调度,禁止调度
    * delay_osschedunlock :用于解锁 OS 任务调度,重新开启调度
    * delay_ostimedly :用于 OS 延时,可以引起任务调度.
    * 
    * 本例程仅作 UCOSII 和 UCOSIII 的支持,其他 OS,请自行参考着移植
    */
    /* 支持 UCOSII */
    #ifdef OS_CRITICAL_METHOD /* OS_CRITICAL_METHOD 定义了
     * 说明要支持 UCOSII
     */
    #define delay_osrunning OSRunning /* OS 是否运行标记,0,不运行;1,在运行 */
    #define delay_ostickspersec OS_TICKS_PER_SEC /* OS 时钟节拍,即每秒调度次数 */
    #define delay_osintnesting OSIntNesting /* 中断嵌套级别,即中断嵌套次数 */
    #endif
    /* 支持 UCOSIII */
    #ifdef CPU_CFG_CRITICAL_METHOD /* CPU_CFG_CRITICAL_METHOD 定义了
     * 说明要支持 UCOSIII
     */
    #define delay_osrunning OSRunning /* OS 是否运行标记,0,不运行;1,在运行 */
    #define delay_ostickspersec OSCfg_TickRate_Hz /* OS 时钟节拍,即每秒调度次数 */
    #define delay_osintnesting OSIntNestingCtr /* 中断嵌套级别,即中断嵌套次数 */
    #endif
    /**
    * @brief us 级延时时,关闭任务调度(防止打断 us 级延迟)
    * @param 无
    * @retval 无
    */
    static void delay_osschedlock(void)
    {
    #ifdef CPU_CFG_CRITICAL_METHOD /* 使用 UCOSIII */
     OS_ERR err;
     OSSchedLock(&err); /* UCOSIII 的方式,禁止调度,防止打断 us 延时 */
    #else /* 否则 UCOSII */
     OSSchedLock(); /* UCOSII 的方式,禁止调度,防止打断 us 延时 */
    #endif
    }
    /**
    * @brief us 级延时时,恢复任务调度
    * @param 无
    * @retval 无
    */
    static void delay_osschedunlock(void)
    {
    #ifdef CPU_CFG_CRITICAL_METHOD /* 使用 UCOSIII */
     OS_ERR err;
     OSSchedUnlock(&err); /* UCOSIII 的方式,恢复调度 */
    #else /* 否则 UCOSII */
     OSSchedUnlock(); /* UCOSII 的方式,恢复调度 */
    #endif
    }
    /**
    * @brief us 级延时时,恢复任务调度
    * @param ticks: 延时的节拍数
    * @retval 无
    */
    static void delay_ostimedly(uint32_t ticks)
    {
    #ifdef CPU_CFG_CRITICAL_METHOD
     OS_ERR err;
     OSTimeDly(ticks, OS_OPT_TIME_PERIODIC, &err); /* UCOSIII 延时采用周期模式 */
    #else
     OSTimeDly(ticks); /* UCOSII 延时 */
    #endif
    }
    

    (2)添加 FreeRTOS 的相关代码

    只需要在delay.c文件中使用 extern关键字导入一个FreeRTOS函数一 xPortSysTickHandler()即可,这个函数是用于处理FreeRTOS系统时钟节拍的,本教程是使用 SysTick作为FreeRTOS操作系统的心跳,因此需要在SysTick的中断服务函数中调用这个函数,因此将代码添加到SysTick中断服务函数之前,代码修改如下:

    extern void xPortSysTickHandler(void);
    

    (3)修改部分内容

    最后要修改的内容包括两个,分别是包含头文件和 4 个函数。

    包含头文件:

    //修改前:
    #include "includes.h"
    //修改后: 
    #include "FreeRTOS.h"
    #include "task.h"
    

    4个函数:

    (1) SysTick_Handler()

    修改前:

    void SysTick_Handler(void)
    {
        /* OS 开始跑了,才执行正常的调度处理 */
        if (delay_osrunning == OS_TRUE)
        {
            /* 调用 uC/OS-II 的 SysTick 中断服务函数 */
            OS_CPU_SysTickHandler();
        }
        HAL_IncTick();
    }
    

    修改后:

    void SysTick_Handler(void)
    {
    	HAL_IncTick();
    	
    	if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
    	{
    		xPortSysTickHandler();
    	}
    }
    

    (2) delay_init()

    修改前:

    void delay_init(uint16_t sysclk)
    {
    #if SYS_SUPPORT_OS                                      /* 如果需要支持OS */
        uint32_t reload;
    #endif
        g_fac_us = sysclk;                                  /* 由于在HAL_Init中已对systick做了配置,所以这里无需重新配置 */
    #if SYS_SUPPORT_OS                                      /* 如果需要支持OS. */
        reload = sysclk;                                    /* 每秒钟的计数次数 单位为M */
        reload *= 1000000 / delay_ostickspersec;            /* 根据delay_ostickspersec设定溢出时间,reload为24位
                                                             * 寄存器,最大值:16777216,在168M下,约合0.09986s左右
                                                             */
        g_fac_ms = 1000 / delay_ostickspersec;              /* 代表OS可以延时的最少单位 */
        SysTick->CTRL |= 1 << 1;                            /* 开启SYSTICK中断 */
        SysTick->LOAD = reload;                             /* 每1/delay_ostickspersec秒中断一次 */
        SysTick->CTRL |= 1 << 0;                            /* 开启SYSTICK */
    #endif 
    }
    

    修改后:

    void delay_init(uint16_t sysclk)
    {
    #if SYS_SUPPORT_OS                                      /* 如果需要支持OS */
        uint32_t reload;
    #endif
    	SysTick->CTRL = 0;
    	HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8);
    	
        g_fac_us = sysclk / 8;                                  /* 由于在HAL_Init中已对systick做了配置,所以这里无需重新配置 */
    	
    #if SYS_SUPPORT_OS                                      /* 如果需要支持OS. */
        reload = sysclk / 8;                                    /* 每秒钟的计数次数 单位为M */
        reload *= 1000000 / configTICK_RATE_HZ;            /* 根据delay_ostickspersec设定溢出时间,reload为24位
                                                             * 寄存器,最大值:16777216,在168M下,约合0.09986s左右
                                                             */             /* 代表OS可以延时的最少单位 */
        SysTick->CTRL |= 1 << 1;                            /* 开启SYSTICK中断 */
        SysTick->LOAD = reload;                             /* 每1/delay_ostickspersec秒中断一次 */
        SysTick->CTRL |= 1 << 0;                            /* 开启SYSTICK */
    #endif 
    }
    

    (3) delay_us()

    修改前:

    void delay_us(uint32_t nus)
    {
        uint32_t ticks;
        uint32_t told, tnow, tcnt = 0;
        uint32_t reload = SysTick->LOAD;        /* LOAD的值 */
        ticks = nus * g_fac_us;                 /* 需要的节拍数 */
        
    #if SYS_SUPPORT_OS                          /* 如果需要支持OS */
        delay_osschedlock();                    /* 锁定 OS 的任务调度器 */
    #endif
    
        told = SysTick->VAL;                    /* 刚进入时的计数器值 */
        while (1)
        {
            tnow = SysTick->VAL;
            if (tnow != told)
            {
                if (tnow < told)
                {
                    tcnt += told - tnow;        /* 这里注意一下SYSTICK是一个递减的计数器就可以了 */
                }
                else
                {
                    tcnt += reload - tnow + told;
                }
                told = tnow;
                if (tcnt >= ticks) 
                {
                    break;                      /* 时间超过/等于要延迟的时间,则退出 */
                }
            }
        }
    
    #if SYS_SUPPORT_OS                          /* 如果需要支持OS */
        delay_osschedunlock();                  /* 恢复 OS 的任务调度器 */
    #endif 
    
    }
    

    修改后:

    void delay_us(uint32_t nus)
    {
        uint32_t ticks;
        uint32_t told, tnow, tcnt = 0;
        uint32_t reload = SysTick->LOAD;        /* LOAD的值 */
        ticks = nus * g_fac_us;                 /* 需要的节拍数 */
    
        told = SysTick->VAL;                    /* 刚进入时的计数器值 */
        while (1)
        {
            tnow = SysTick->VAL;
            if (tnow != told)
            {
                if (tnow < told)
                {
                    tcnt += told - tnow;        /* 这里注意一下SYSTICK是一个递减的计数器就可以了 */
                }
                else
                {
                    tcnt += reload - tnow + told;
                }
                told = tnow;
                if (tcnt >= ticks) 
                {
                    break;                      /* 时间超过/等于要延迟的时间,则退出 */
                }
            }
        }
    }
    

    (4) delay_ms()

    修改前:

    void delay_ms(uint16_t nms)
    {
        
    #if SYS_SUPPORT_OS  /* 如果需要支持OS, 则根据情况调用os延时以释放CPU */
        if (delay_osrunning && delay_osintnesting == 0)     /* 如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度) */
        {
            if (nms >= g_fac_ms)                            /* 延时的时间大于OS的最少时间周期 */
            {
                delay_ostimedly(nms / g_fac_ms);            /* OS延时 */
            }
    
            nms %= g_fac_ms;                                /* OS已经无法提供这么小的延时了,采用普通方式延时 */
        }
    #endif
    
        delay_us((uint32_t)(nms * 1000));                   /* 普通方式延时 */
    }
    

    修改后:

    void delay_ms(uint16_t nms)
    {
        uint32_t i;
    	
    	for(i=0; i<nms; i++)
    	{
    		delay_us(1000);
    	}
    }
    

4. 修改中断相关文件

FreeRTOS系统时基定时器的中断(SysTick中断)SVC中断PendSV中断
SysTick的中断服务函数在delay.c文件中已经定义了,并且FreeRTOS也提供了SVC和PendSV的中断服务函数,因此需要将HAL库提供的这三个中断服务函数注释掉,这里采用宏开关的方式让HAL库中的这三个中断服务函数不加入编译,使用的宏在sys.h中定义,因此还需要导入Sysh头文件,请读者按照表2.1.4.1找到对应的文件进行修改,修改后的代码如下所示:

/* 导入 sys.h 头文件 */
#include "./SYSTEM/SYS/sys.h"

/* 加入宏开关 */
#if (!SYS_SUPPORT_OS)
void SVC_Handler(void)
{
}
#endif

#if (!SYS_SUPPORT_OS)
void PendSV_Handler(void)
{
}
#endif

#if (!SYS_SUPPORT_OS)
void SysTick_Handler(void)
{
 HAL_IncTick();
}
#endif

5. 修改FreeRTOSConfig.h文件

FreeRTOSConfig.h

#define   configPRIO_BITS   __NVIC_PRIO_BITS

stm32f103xe.h文件中修改:

#define __NVIC_PRIO_BITS   4U

为:

#define __NVIC_PRIO_BITS   4

在这里插入图片描述

6. 可选步骤

  1. 修改工程目标名称:

    本教程是以标准例程-HAL库版本的内存管理实验工程为基础工程,内存管理实验工程的工程日标名为“MALLOC”,为了规范工程,笔者建议将工程目标名修改为“FreeRTOS”或根据读者的实际场景进行修改,修改如下图所示:
    在这里插入图片描述

  2. 移出USMART调试组件:

    由于本教程并未使用到USMART调试组件,因此建议将USMART调试组件从工程中移除,如果读者需要使用USMART调试组件的话,也可选择保留,移除USAMRT调试组建后工程文件分组如下图所示(这里以正点原子的STM32F1系列开发板为例,其他开发板类似),修改后文件组为:
    在这里插入图片描述

  3. 添加定时器驱动:

    由于在后续的实验中需要使用到$TM32的基本定时器外设,因此需要向工程中添加定时器的相关驱动文件,读者也可在后续实验需要用到定时器的时候再进行添加。将定时器的相关驱动文件添加到工程的Drivers/BSP文件分组中,如下图所示(这里以正点原子的STM32F1系列开发板为例,其他开发板类似):
    )
    在这里插入图片描述

  4. 添加应用程序:

    添加freertos_demo.cfreertos_demo.h测试文件,对于 main.c 主要是在main()函数中完成一些硬件的初始化,最后调用 freertos_demo.c文件中的freertos_demo()函数。

    main.c

    #include "./SYSTEM/sys/sys.h"
    #include "./SYSTEM/usart/usart.h"
    #include "./SYSTEM/delay/delay.h"
    #include "./BSP/LED/led.h"
    #include "./BSP/LCD/lcd.h"
    #include "./BSP/KEY/key.h"
    #include "./BSP/SRAM/sram.h"
    #include "./MALLOC/malloc.h"
    #include "freertos_demo.h"
    
    
    const char *SRAM_NAME_BUF[SRAMBANK] = {" SRAMIN ", " SRAMEX "};
    
    
    int main(void)
    {
        HAL_Init();                             /* 初始化HAL库 */
        sys_stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
        delay_init(72);                         /* 延时初始化 */
        usart_init(115200);                     /* 串口初始化为115200 */
        led_init();                             /* 初始化LED */
        lcd_init();                             /* 初始化LCD */
        key_init();                             /* 初始化按键 */
        sram_init();                            /* SRAM初始化 */
        my_mem_init(SRAMIN);                    /* 初始化内部SRAM内存池 */
        my_mem_init(SRAMEX);                    /* 初始化外部SRAM内存池 */
    
        lcd_show_string(30,  50, 200, 16, 16, "YIZHI successed", RED);
    
        freertos_demo();
    }
    

    freertos_demo.c

    #include "freertos_demo.h"
    #include "./SYSTEM/usart/usart.h"
    #include "./BSP/LED/led.h"
    #include "./BSP/LCD/lcd.h"
    
    #include "FreeRTOS.h"
    #include "task.h"
    
    
    #define START_TASK_PRIO 1                   // 任务优先级 
    #define START_STK_SIZE  128                 // 任务堆栈大小 
    TaskHandle_t            StartTask_Handler;  // 任务句柄 
    void start_task(void *pvParameters);        // 任务函数 
    
    #define TASK1_PRIO      2                   // 任务优先级 
    #define TASK1_STK_SIZE  128                 // 任务堆栈大小 
    TaskHandle_t            Task1Task_Handler;  // 任务句柄 
    void task1(void *pvParameters);             // 任务函数 
    
    #define TASK2_PRIO      3                   // 任务优先级 
    #define TASK2_STK_SIZE  128                 // 任务堆栈大小 
    TaskHandle_t            Task2Task_Handler;  // 任务句柄 
    void task2(void *pvParameters);             // 任务函数 
    
    
    /*创建开始任务*/
    void freertos_demo(void)
    {   
        xTaskCreate((TaskFunction_t )start_task,            // 任务函数 
                    (const char*    )"start_task",          // 任务名称 
                    (uint16_t       )START_STK_SIZE,        // 任务堆栈大小 
                    (void*          )NULL,                  // 传入给任务函数的参数 
                    (UBaseType_t    )START_TASK_PRIO,       // 任务优先级 
                    (TaskHandle_t*  )&StartTask_Handler);   // 任务句柄 
        vTaskStartScheduler();
    }
    
    
    /*创建两任务1和任务2*/
    void start_task(void *pvParameters)
    {
        taskENTER_CRITICAL();           // 进入临界区 
    	
        // 创建任务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);
    				
        vTaskDelete(StartTask_Handler); // 删除开始任务 
    				
        taskEXIT_CRITICAL();            // 退出临界区 
    }
    
    
    /*任务一: LED0闪烁*/
    void task1(void *pvParameters)
    {  
        while(1)
        {
            LED0_TOGGLE();                                                  
            vTaskDelay(1000);   //延时1000ticks 
        }
    }
    
    
    /*任务二: LED1闪烁*/
    void task2(void *pvParameters)
    {  
        while(1)
        {
    		LED1_TOGGLE();
            vTaskDelay(500);    //延时500ticks 
        }
    }
    

    freertos_demo.h

    #ifndef __FREERTOS_DEMO_H
    #define __FREERTOS_DEMO_H
    
    void freertos_demo(void);
    
    #endif
    

标签:02,FreeRTOS,void,delay,SysTick,include,OS,移植
From: https://blog.csdn.net/Lshuangye/article/details/140756481

相关文章

  • IDEA 2024最新永久安装使用教程
    在软件开发的世界里,IntelliJIDEA作为Java、Kotlin等多语言开发者的首选IDE(集成开发环境),以其强大的功能、灵活的扩展性和卓越的智能辅助功能赢得了广泛的赞誉。随着人工智能(AI)技术的飞速发展,IntelliJIDEA也紧跟时代步伐,通过引入一系列AI编程插件,极大地提升了开发者的编码效率、代......
  • 视野修炼-技术周刊第94期 | 2024 开发者调查报告
    欢迎来到第94期的【视野修炼-技术周刊】,下面是本期的精选内容简介......
  • XMind v2024 解锁版下载及安装教程 (全球领先的商业思维导图软件)
    简述XMind是一款专业的全球领先的商业思维导图软件,在国内使用广泛,拥有强大的功能、包括思维管理、商务演示、与办公软件协同工作等功能。它采用全球先进的EclipseRCP软件架构,是集思维导图与头脑风暴于一体的可视化思考工具,能用来捕捉想法、理清思路、管理复杂信息并促进......
  • 中望CAD 机械 v2024 解锁版下载及安装教程 (CAD三维制图)
    简述中望CAD机械版是一款国产CAD制图软件,专为机械设计而打造。中望CAD机械版2024中文版拥有丰富的标准零件图库,提供绘图标准规范,并支持定制化需求。其智能注释功能更是一大亮点,通过一个命令即可完成80%的标注工作,极大提高了绘图效率。一、下载地址下载链接:中望CAD机械......
  • SMU Summer 2024 div2 3rd
    文章目录TheThirdWeek一、前言二、算法1.KMP算法2.线性DP<1>(最长上升子序列II)3.背包DP<1>(「木」迷雾森林)4.其它<1>(Ubiquity)三、总结TheThirdWeek战略上藐视敌人,战术上重视敌人————毛泽东主席一、前言周六打了场cf,只过了俩题而且比较慢,给我的id上......
  • 2024暑假集训测试14
    前言比赛链接。最可惜的一点还是本来T3暴力能拿\(20\),优化成\(15\)了,不然就rk2了,晚上可能又有泡面吃了。不过因为T2、T4两道水题,剩下两道不太可做(至少对于我是这样的),这两题不挂分的打的貌似都不错。T3没学过莫反输麻了。T1黑暗型高松灯本来应该是T4,学长特意......
  • 2024/07/28 每日一题
    LeetCode699掉落的方块方法1:暴力classSolution:deffallingSquares(self,positions:List[List[int]])->List[int]:n=len(positions);ans=[0]*n#记录每个方块落下后的高度fori,(left0,widen0)inenumerate(positions):......
  • PAT 乙级 真题练习 1002 写出这个数
    问题描述读入一个正整数n,计算其各位数字之和,用汉语拼音写出和的每一位数字。输入格式:每个测试输入包含1个测试用例,即给出自然数n的值。这里保证n小于10100。输出格式:在一行内输出n的各位数字之和的每一位,拼音数字间有1空格,但一行中最后一个拼音数字后没有空格......
  • 洛谷Day1--P1102 A-B数对 P1163 银行贷款
    目录一、引言二、题目及题解题目一:P1102A-B数对题目链接题解:哈希 题目二:P1163银行贷款题目链接题解:二分 三、小结一、引言今天是周日,代码随想录训练营的打卡休息一天。想着刷一点题巩固一下之前的所学,就做了两道洛谷的题,一道用的哈希(也可以二分,个人感觉麻烦......
  • 使用FreeRTOS官方移植,移植到STM32F1平台中
    本教程基本参照[野火]《FreeRTOS内核实现与应用开发实战指南》,本人相当推荐此教程,尤其是第一部分从0开始写内核,虽然比较晦涩,但是学完之后对FreeRTOS的运行原理还有框架的认识会有一个很大的提高。首先获取FreeRTOS的源码我们从官网下载9.0版本的压缩包解压后Plus中包含......