FreeRTOS系统---Delay死延迟函数(STM32标准库)

一、取消注释

先取消“#include "stm32f10x_it.h"”“FreeRTOSConfig.h”当中关于下面宏的注释:

#define        xPortSysTickHandler        SysTick_Handler

二、添加宏 

“FreeRTOSConfig.h”添加下面的宏:

#define        INCLUDE_xTaskGetSchedulerState         1

三、重构Delay函数 

delay.c

#include "delay.h"

static uint16_t fac_ms = 8;  // 用于存储每毫秒的 SysTick 计数
static uint32_t fac_us;      // 用于存储每微秒的 SysTick 计数

// SysTick 中断服务函数,用于 FreeRTOS 的时钟节拍
extern void xPortSysTickHandler(void);
void SysTick_Handler(void)
{
    // 如果 FreeRTOS 调度器已经启动,则调用 FreeRTOS 的 SysTick 处理函数
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
    {
        xPortSysTickHandler();
    }
}

// 初始化延时函数
// 当使用操作系统时,此函数会初始化操作系统的时钟节拍
// SysTick 的时钟固定为 HCLK 时钟的 1/8
void delay_init(void)
{
#if SYSTEM_SUPPORT_OS  // 如果需要支持操作系统
    u32 reload;
#endif

    // 配置 SysTick 时钟源为 HCLK(系统时钟)
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
    fac_us = SystemCoreClock / 1000000;  // 计算每微秒的 SysTick 计数

#if SYSTEM_SUPPORT_OS  // 如果需要支持操作系统
    // 计算 SysTick 重装载值,用于 FreeRTOS 的时钟节拍
    reload = SystemCoreClock / 1000000;  // 每秒钟的计数次数,单位为 M
    reload *= 1000000 / configTICK_RATE_HZ;  // 根据 FreeRTOS 的时钟节拍频率设定溢出时间
    fac_ms = 1000 / configTICK_RATE_HZ;  // 代表操作系统可以延时的最小单位(毫秒)

    // 配置 SysTick 中断并启动
    SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;  // 开启 SysTick 中断
    SysTick->LOAD = reload;  // 设置重装载值
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;  // 开启 SysTick
#else
    // 非操作系统下,计算每毫秒的 SysTick 计数
    fac_ms = (u16)fac_us * 1000;
#endif
}

// 延时 n 微秒
// nus: 要延时的微秒数
void delay_us(u32 nus)
{
    u32 ticks;
    u32 told, tnow, tcnt = 0;
    u32 reload = SysTick->LOAD;  // 获取 SysTick 的重装载值
    ticks = nus * fac_us;  // 计算需要的节拍数

    told = SysTick->VAL;  // 获取当前 SysTick 计数器的值
    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;  // 时间超过或等于要延迟的时间,退出循环
        }
    }
}

// 延时 n 毫秒
// nms: 要延时的毫秒数
void delay_ms(u32 nms)
{
    // 如果 FreeRTOS 调度器已经启动
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
    {
        // 如果延时时间大于操作系统的最小时间周期,则使用 FreeRTOS 的延时函数
        if (nms >= fac_ms)
        {
            vTaskDelay(nms / fac_ms);  // FreeRTOS 延时,不会阻止任务调度
        }
        nms %= fac_ms;  // 剩余时间使用普通方式延时
    }
    delay_us((u32)(nms * 1000));  // 普通方式延时
}

// 延时 n 毫秒,不会引起任务调度
// nms: 要延时的毫秒数
void delay_xms(u32 nms)
{
    u32 i;
    for (i = 0; i < nms; i++)
        delay_us(1000);  // 循环调用 delay_us 实现毫秒延时
}

delay.h

#ifndef __DELAY_H
#define __DELAY_H
 
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
 
void delay_init(void);
void delay_us(uint32_t us);									//?óê±?¢??
void delay_ms(uint32_t ms);									//?óê±oá??
 
void delay_xms(uint32_t ms);								//·a×°è????D??μ??óê±oˉêy
 
#endif


注:其中delay_us()和deay_xms()不会引起FreeRTOS任务切换。

### 实现基于 STM32F103C8T6 和 FreeRTOS 的延时功能 在嵌入式开发中,FreeRTOS 提供了一种轻量级的操作系统解决方案,适用于资源受限的微控制器。对于 STM32F103C8T6 平台,可以通过配置 FreeRTOS 来实现任务调度和时间管理等功能。以下是结合 STM32F103C8T6 标准库FreeRTOS 实现延时函数的具体方法。 #### 1. 配置 FreeRTOS 环境 为了使 FreeRTOS 能够正常运行于 STM32F103C8T6 上,需完成以下初始化工作: - **移植层设置**:确保 `port.c` 和 `portmacro.h` 文件已适配至 Cortex-M3 架构。 - **时钟源配置**:通过标准库配置 SysTick 或其他定时器作为 RTOS 时间基准[^1]。 SysTick 是 ARM Cortex-M3 内部集成的一个简单计数器模块,默认用于提供操作系统的时间片支持。如果使用标准库,则需要手动调用相关 API 初始化硬件资源。 #### 2. 创建任务并引入 vTaskDelay 函数 FreeRTOS 中提供了多种方式来处理延迟操作,其中最常用的是 `vTaskDelay()` 方法。此函数允许当前执行线程进入阻塞状态直到指定时间段结束为止。下面是一个简单的例子展示如何创建两个独立的任务并通过它们之间的交互体现延时效果: ```c #include "stm32f1xx_hal.h" #include "FreeRTOS.h" #include "task.h" void TaskA(void *pvParameters); void TaskB(void *pvParameters); int main(void){ HAL_Init(); /* Initialize peripherals here */ xTaskCreate(TaskA, "TASK_A", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 1, NULL ); xTaskCreate(TaskB, "TASK_B", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 1, NULL ); vTaskStartScheduler(); while(1){}; } // Example task A which waits for some ticks before printing message. void TaskA(void* pvParameters){ TickType_t xLastWakeTime; const portTickType xFrequency = pdMS_TO_TICKS(500); xLastWakeTime = xTaskGetTickCount(); for (;;){ printf("Task A Running\n"); // Wait until next cycle based on frequency defined above. vTaskDelayUntil(&xLastWakeTime ,xFrequency ); } } // Another example showing different delay period than previous one. void TaskB(void* pvParameters){ for (;;) { printf("Task B Running Every Second \n"); // Block this task from running again immediately by delaying it. vTaskDelay(pdMS_TO_TICKS(1000)); } } ``` 上述代码片段展示了两个不同周期的任务定义过程,并利用了 `vTaskDelay()` 及其变体形式 `vTaskDelayUntil()`. 这两种机制都可以有效地控制程序流程中的等待间隔,从而简化多线程环境下的同步逻辑设计. #### 3. 关键点说明 - **优先级设定**: 不同任务间应分配合理的优先级别以满足实际需求场景的要求; - **堆栈大小调整**: 根据具体应用负载情况合理规划每项工作的所需内存空间长度; - **错误检测机制构建**: 添加必要的异常捕获手段以便及时发现潜在隐患问题; --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值