FreeRTOS移植到STM32F103C8T6(HAL库)

目录

一、将STM32F103ZET6代码变更成STM32F103C8T6

二、 将FreeRTOS码源添加到文件

三、代码更改适配

四、测试 


一、将STM32F103ZET6代码变更成STM32F103C8T6

点击魔法棒,点击Device,选择芯片为STM32F103C8T6

 进行编译,无报错无警告:

二、 将FreeRTOS码源添加到文件

先进入官网获取FreeRTOS码源:https://www.freertos.org/a00110.html

将获取到的源码中的FreeRTOS/Source文件夹移植到工程文件中的Middlewares下

 点击文件拓展工具,添加Middlewares/FreeRTOS_CODE与Middlewares/FreeRTOS_PORT两个组

将相关代码添加到这两个新建组中 

 

引入相关头文件地址 

将 FreeRTOSConfig.h添加到User中

三、代码更改适配

sys.h文件

将宏SYS_SUPPORT_OS定义为1

#define SYS_SUPPORT_OS  1 

usart.c文件

USART_UX_IRQHandler适配更改:

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)/* 重新开启中断并接收数据 */ 
    { 
      /* 如果出错会卡死在这里 */ 
    } 
} 

删除无关头文件

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

delay.c文件

将如下代码删除

static uint16_t g_fac_ms = 0; 
#ifdef  OS_CRITICAL_METHOD
#define delay_osrunning OSRunning   /* OS是否运行标记,0,不运行;1,在运行 */ 
#define delay_ostickspersec OS_TICKS_PER_SEC /* OS时钟节拍,即每秒调度次数 */ 
#define delay_osintnesting OSIntNesting  /* 中断嵌套级别,即中断嵌套次数 */ 
#endif
#ifdef  CPU_CFG_CRITICAL_METHOD
#define delay_osrunning OSRunning   /* OS是否运行标记,0,不运行;1,在运行 */ 
#define delay_ostickspersec OSCfg_TickRate_Hz /* OS时钟节拍,即每秒调度次数 */ 
#define delay_osintnesting OSIntNestingCtr  /* 中断嵌套级别,即中断嵌套次数 */ 
#endif 
static void delay_osschedlock(void) 
{ 
#ifdef CPU_CFG_CRITICAL_METHOD /* 使用UCOSIII */ 
    OS_ERR err; 
    OSSchedLock(&err);   /* UCOSIII的方式,禁止调度,防止打断us延时 */ 
#else       /* 否则UCOSII */ 
    OSSchedLock();    /* UCOSII的方式,禁止调度,防止打断us延时 */ 
#endif 
}
static void delay_osschedunlock(void) 
{ 
#ifdef CPU_CFG_CRITICAL_METHOD /* 使用UCOSIII */ 
    OS_ERR err; 
    OSSchedUnlock(&err);  /* UCOSIII的方式,恢复调度 */ 
#else       /* 否则UCOSII */ 
    OSSchedUnlock();    /* UCOSII的方式,恢复调度 */ 
#endif 
} 
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 
} 

将代码添加到 SysTick中断服务函数之前

extern void xPortSysTickHandler(void); 

修改SysTick_Handler()

void SysTick_Handler(void) 
{ 
    HAL_IncTick(); 
    /* OS开始跑了,才执行正常的调度处理 */ 
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) 
    { 
        xPortSysTickHandler(); 
    } 
} 

xPortSysTickHandler()

void SysTick_Handler(void) 
{ 
    HAL_IncTick(); 
    /* OS开始跑了,才执行正常的调度处理 */ 
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) 
    { 
        xPortSysTickHandler(); 
    } 
} 

SysTick_Handler 函数

delay_init()

void delay_init(uint16_t sysclk) 
{ 
#if SYS_SUPPORT_OS 
    uint32_t reload; 
#endif 
    SysTick->CTRL = 0; 
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8); 
     
    g_fac_us = sysclk / 8; 
#if SYS_SUPPORT_OS 
    reload = sysclk / 8; 
    /* 使用configTICK_RATE_HZ计算重装载值 
     * configTICK_RATE_HZ在FreeRTOSConfig.h中定义 
     */ 
    reload *= 1000000 / configTICK_RATE_HZ; 
    /* 删除不用的g_fac_ms相关代码 */ 
    SysTick->CTRL |= 1 << 1; 
    SysTick->LOAD = reload; 
    SysTick->CTRL |= 1 << 0; 
#endif 
} 

delay_us()

void delay_us(uint32_t nus) 
{ 
    uint32_t ticks; 
    uint32_t told, tnow, tcnt = 0; 
    uint32_t reload = SysTick->LOAD; 
    /* 删除适用于µC/OS用于锁定任务调度器的自定义函数 */ 
    ticks = nus * g_fac_us; 
    told = SysTick->VAL; 
    while (1) 
    { 
      tnow = SysTick->VAL; 
      if (tnow != told) 
      { 
       if (tnow < told) 
       { 
        tcnt += told - tnow; 
       } 
       else 
       { 
        tcnt += reload - tnow + told; 
       } 
       told = tnow; 
       if (tcnt >= ticks)  
       { 
        break; 
       } 
      } 
    } 
    /* 删除适用于µC/OS用于解锁任务调度器的自定义函数 */ 
}  

delay_ms()

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

将#include "includes.h" 修改成

/* 添加公共头文件 (FreeRTOS 需要用到) */ 
#include "FreeRTOS.h" 
#include "task.h" 

完整delay.c文件:


#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"


static uint32_t g_fac_us = 0;       /* us延时倍乘数 */

/* 如果SYS_SUPPORT_OS定义了,说明要支持OS了(不限于UCOS) */
#if SYS_SUPPORT_OS

/* 添加公共头文件 (FreeRTOS 需要用到) */
#include "FreeRTOS.h"
#include "task.h"

extern void xPortSysTickHandler(void);

/**
 * @brief     systick中断服务函数,使用OS时用到
 * @param     ticks : 延时的节拍数  
 * @retval    无
 */  
void SysTick_Handler(void)
{
    HAL_IncTick();
    /* OS 开始跑了,才执行正常的调度处理 */
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
    {
        xPortSysTickHandler();
    }
}
#endif

/**
 * @brief     初始化延迟函数
 * @param     sysclk: 系统时钟频率, 即CPU频率(rcc_c_ck), 180MHz
 * @retval    无
 */  
void delay_init(uint16_t sysclk)
{
#if SYS_SUPPORT_OS                                      /* 如果需要支持OS */
    uint32_t reload;
#endif
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);/* SYSTICK使用外部时钟源,频率为HCLK */
    g_fac_us = sysclk;                                  /* 不论是否使用OS,g_fac_us都需要使用 */
#if SYS_SUPPORT_OS                                      /* 如果需要支持OS. */
    reload = sysclk;                                    /* 每秒钟的计数次数 单位为M */
    reload *= 1000000 / configTICK_RATE_HZ;            /* 根据delay_ostickspersec设定溢出时间,reload为24位
                                                         * 寄存器,最大值:16777216,在180M下,约合0.0932s左右
                                                         */
    SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;          /* 开启SYSTICK中断 */
    SysTick->LOAD = reload;                             /* 每1/delay_ostickspersec秒中断一次 */
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;           /* 开启SYSTICK */
#endif 
}

#if SYS_SUPPORT_OS                                      /* 如果需要支持OS, 用以下代码 */

/**
 * @brief     延时nus
 * @param     nus: 要延时的us数
 * @note      注意: nus的值,不要大于93206us(最大值即2^24 / g_fac_us @g_fac_us = 180)
 * @retval    无
 */ 
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;                      /* 时间超过/等于要延迟的时间,则退出 */
            }
        }
    }
        
} 

/**
 * @brief     延时nms
 * @param     nms: 要延时的ms数 (0< nms <= 65535) 
 * @retval    无
 */
void delay_ms(uint16_t nms)
{
    uint32_t i;
    for (i=0; i<nms; i++)
    {
        delay_us(1000);
    }
}

#else  /* 不使用OS时, 用以下代码 */

/**
 * @brief       延时nus
 * @param       nus: 要延时的us数.
 * @note        注意: nus的值,不要大于93206us(最大值即2^24 / g_fac_us @g_fac_us = 180)
 * @retval      无
 */
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;                      /* 时间超过/等于要延迟的时间,则退出 */
            }
        }
    }
}

/**
 * @brief       延时nms
 * @param       nms: 要延时的ms数 (0< nms <= 65535)
 * @retval      无
 */
void delay_ms(uint16_t nms)
{
    uint32_t repeat = nms / 65;     /*  这里用60,是考虑到可能有超频应用,比如180M的时候,delay_us最大只能延时93206us左右了 */
    uint32_t remain = nms % 65;

    while (repeat)
    {
        delay_us(65 * 1000);        /* 利用delay_us 实现 65ms 延时 */
        repeat--;
    }

    if (remain)
    {
        delay_us(remain * 1000);    /* 利用delay_us, 把尾数延时(remain ms)给做了 */
    }
}

/**
 * @brief       HAL库内部函数用到的延时
 * @note        HAL库的延时默认用Systick,如果我们没有开Systick的中断会导致调用这个延时后无法退出
 * @param       Delay : 要延时的毫秒数
 * @retval      None
 */
void HAL_Delay(uint32_t Delay)
{
     delay_ms(Delay);
}
#endif









stm32f1xx_it.c

/* 加入宏开关 */ 
#if (!SYS_SUPPORT_OS) 
void SVC_Handler(void) 
{ 
} 
#endif 
 
/** 
  * @brief This function handles PendSVC exception. 
  * @param None 
  * @retval None 
  */ 
/* 加入宏开关 */ 
#if (!SYS_SUPPORT_OS) 
void PendSV_Handler(void) 
{ 
} 
#endif 
 
/** 
  * @brief This function handles SysTick Handler. 
  * @param None 
  * @retval None 
  */ 
/* 加入宏开关 */ 
#if (!SYS_SUPPORT_OS) 
void SysTick_Handler(void) 
{ 
  HAL_IncTick(); 
} 
#endif

FreeRTOSConfig.h

#define configPRIO_BITS  __NVIC_PRIO_BITS 
//#define __NVIC_PRIO_BITS  4U 
#define __NVIC_PRIO_BITS  4 

编译:无报错无警告

四、测试 

编写主函数:

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
 #include "./SYSTEM/delay/delay.h"
 #include "./SYSTEM/usart/usart.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO 1                   /* 任务优先级 */
#define START_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            StartTask_Handler;  /* 任务句柄 */
void start_task(void *pvParameters);        /* 任务函数 */

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO      2                   /* 任务优先级 */
#define TASK1_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task1Task_Handler;  /* 任务句柄 */
void task1(void *pvParameters);             /* 任务函数 */

/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO      3                   /* 任务优先级 */
#define TASK2_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task2Task_Handler;  /* 任务句柄 */
void task2(void *pvParameters);             /* 任务函数 */

/******************************************************************************************************/
void led_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
__HAL_RCC_GPIOC_CLK_ENABLE();

    gpio_initstruct.Pin = GPIO_PIN_13;                      /* LED0引脚 */
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */
    gpio_initstruct.Pull = GPIO_PULLUP;                    /* 上拉 */
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */
    HAL_GPIO_Init(GPIOC, &gpio_initstruct);                /* 初始化LED0引脚 */

//    gpio_initstruct.Pin = GPIO_PIN_5;                      /* LED1引脚 */
//    HAL_GPIO_Init(GPIOE, &gpio_initstruct);                /* 初始化LED1引脚 */
}

 

/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
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();
}

/**
 * @brief       start_task
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
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();            /* 退出临界区 */
}

/**
 * @brief       task1
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void task1(void *pvParameters)
{    
	
    while(1)
    {
			printf("task1\r\n");delay_ms(500);
    }
}

/**
 * @brief       task2
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void task2(void *pvParameters)
{    
		led_init();                         /* LED初始化 */
    while(1)
    { 
			printf("task2\r\n");delay_ms(500);
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);    /* PB5置1 */ 
        
        delay_ms(500);
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);  /* PB5置0 */
  
        delay_ms(500); 
    }
}


int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    delay_init(72);                     /* 延时初始化 */
		usart_init(115200);
		printf("start\r\n"); 
		freertos_demo();
//    while(1)
//    { 

//    }
}

编译烧入:

参考:第7讲 FreeRTOS移植_哔哩哔哩_bilibili

### STM32F103C8T6 HAL FreeRTOS 集成 #### 创建项目并配置环境 为了将FreeRTOS集成到STM32F103C8T6中,需先设置好开发环境。选择ARM架构,并指定适当版本的编译器和调试工具[^1]。 #### 使用CubeMX初始化项目结构 启动STM32CubeMX软件来生成初始代码框架。在此过程中,应确保所选设备型号为STM32F103C8Tx系列。对于操作系统的选择,在中间件选项里勾选FreeRTOS以便于后续操作。完成基本参数设定之后导出工程文件至IDE环境中继续编辑。 #### 添加FreeRTOS源码 按照指导说明,在项目资源管理视图下右键点击`Middlewares`文件夹,随后添加名为`FreeRTOS_CODE`以及`FreeRTOS_PORT`的新分组用于存放对应的移植层文件和其他必要的组件[^3]。 #### 编写应用程序逻辑 编写具体的应用程序时建议保持自定义部分独立于由CubeMX产生的模板外,这样可以方便维护更新而不影响原有功能模块。下面给出一段简单的例子展示如何利用多线程机制控制不同的LED灯交替亮灭: ```c #include "main.h" #include "cmsis_os.h" /* 定义两个任务句柄 */ osThreadId_t ledTaskHandle_1; osThreadId_t ledTaskHandle_2; void StartDefaultTask(void *argument){ while (1) { /* 控制第一个LED点亮一段时间后熄灭 */ HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); osDelay(500); // 延迟500ms /* 切换上下文给其他就绪态的任务执行 */ osThreadYield(); } } void StartBlinkTask(void *argument){ while (1) { /* 控制第二个LED工作周期不同于前者 */ HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6); osDelay(1000); // 延迟1s } } int main(void){ /* 初始化硬件及系统服务 */ HAL_Init(); SystemClock_Config(); /* 启动调度器前创建所需的任务实例 */ ledTaskHandle_1 = osThreadNew(StartDefaultTask , NULL, &led_attributes); ledTaskHandle_2 = osThreadNew(StartBlinkTask , NULL, &blink_attributes); /* 开启实时内核运行 */ osKernelStart(); /* 主循环体不会被执行到这里 */ for (;; ); } ``` 上述代码片段展示了怎样借助FreeRTOS API函数建立并发执行路径以达到同步或异步处理目的的同时维持良好的可读性和扩展性[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值