uCOSii的任务延时和软件定时器

news2024/11/25 11:58:26

uCOSii的任务延时和软件定时器

1、心跳节拍

    操作系统的心跳节拍称为一个Tick。uCOSii中有一个专用的心跳节拍函数:OSTimeTick(),每调用一次,系统时间计数器OSTime计数器就会加1次。为了能调用这个心跳节拍函数,我们使用CPU的滴答时钟(SysTick)。

2、STM32在OS下的滴答时钟配置

#include "delay.h"

#define SYSTEM_SUPPORT_OS       1   //1表示支持OS,0表示不支持OS

     

#if SYSTEM_SUPPORT_OS

#include "includes.h"  //includes.h包含了ucos使用到的所有头文件     

#endif

static u8  fac_us=0;//us延时倍乘数            

static u16 fac_ms=0;//ms延时倍乘数,在ucos下,代表每个节拍的ms数

#if SYSTEM_SUPPORT_OS

//如果SYSTEM_SUPPORT_OS定义了,说明要支持OS了

//当delay_us()和delay_ms()需要支持OS的时候,需要定义3个宏和3个函数。

//首先3个宏定义:

//RTOS_Running:用于表示OS当前是否正在运行,以决定是否可以使用相关函数

//RTOS_TicksPerSecond:用于表示OS设定的时钟节拍,delay_init将根据这个参数来初始化滴答时钟(SysTick)

//RTOS_InterruptNesting:用于表示OS中断嵌套级别,因为中断里面不可以调度,delay_ms使用该参数来决定如何运行

//然后是3个函数:

//RTOS_SchedLock()用于锁定OS任务调度,禁止调度

//RTOS_SchedUnlock()用于解锁OS任务调度,重新开启调度

//RTOS_TimeDelay()用于OS延时,可以引起任务调度.

//支持UCOSII

#ifdef OS_CRITICAL_METHOD

//OS_CRITICAL_METHOD定义了,说明要支持UCOSII

#define RTOS_Running        OSRunning   //0表示OS不运行;1表示OS在运行

#define RTOS_TicksPerSecond OS_TICKS_PER_SEC  //OS时钟节拍,即每秒调度次数

#define RTOS_InterruptNesting   OSIntNesting    //中断嵌套级别,即中断嵌套次数

#endif

//支持UCOSIII

#ifdef CPU_CFG_CRITICAL_METHOD

//CPU_CFG_CRITICAL_METHOD定义了,说明要支持UCOSIII 

#define RTOS_Running        OSRunning   //0表示OS不运行;1表示OS在运行

#define RTOS_TicksPerSecond OSCfg_TickRate_Hz  //OS时钟节拍,即每秒调度次数

#define RTOS_InterruptNesting   OSIntNestingCtr    //中断嵌套级别,即中断嵌套次数

#endif

//函数功能:us级延时时,关闭任务调度(防止打断us级延迟)

void RTOS_SchedLock(void)

{

#ifdef CPU_CFG_CRITICAL_METHOD  //当前操作系统使用的是UCOSIII

    OS_ERR err;

    OSSchedLock(&err); //UCOSIII的方式,禁止调度,防止打断us延时

#else   //当前操作系统使用的是UCOSII

    OSSchedLock();    //UCOSII的方式,禁止调度,防止打断us延时

#endif

}

//函数功能:us级延时时,恢复任务调度

void RTOS_SchedUnlock(void)

{  

#ifdef CPU_CFG_CRITICAL_METHOD //当前操作系统使用的是UCOSIII

    OS_ERR err;

    OSSchedUnlock(&err);  //UCOSIII的方式,恢复调度

#else   //当前操作系统使用的是UCOSII

    OSSchedUnlock();       //UCOSII的方式,恢复调度

#endif

}

//函数功能:调用OS自带的延时函数延时

//ticks:延时的节拍数

void RTOS_TimeDelay(u32 ticks)

{

#ifdef CPU_CFG_CRITICAL_METHOD //当前操作系统使用的是UCOSIII

    OS_ERR err;

    OSTimeDly(ticks,OS_OPT_TIME_PERIODIC,&err); //UCOSIII延时ticks个节拍

#else  //当前操作系统使用的是UCOSII

    OSTimeDly(ticks); //UCOSII延时ticks个节拍

#endif

}

//函数功能:CPU的滴答时钟(SysTick)中断服务函数

void SysTick_Handler(void)

{  

    if(RTOS_Running==1)//OS开始跑了,才执行正常的调度处理

    {

        OSIntEnter();

        //进入中断时,用OSIntNesting来统计中断嵌套次数

        //告知uCOSii系统,当前中断服务程序正在执行;

        OSTimeTick();//调用ucos的心跳节拍函数              

        OSIntExit();

        //退出中断时,用OSIntNesting来统计中断嵌套次数

        //告知uCOSii系统,当前的中断已经处理完成,触发任务切换软中断

    }

}

#endif

              

//函数功能:CPU的滴答时钟(SysTick)初始化

//当使用OS的时候,此函数会初始化OS的时钟节拍

//SYSTICK的时钟固定为HCLK时钟的1/8

//SYSCLK:系统时钟

void delay_init(void)

{

#if SYSTEM_SUPPORT_OS //如果需要支持OS.

    u32 reload;

#endif

    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);

    //选择外部时钟HCLK/8

    fac_us=SystemCoreClock/8000000; //为系统时钟的1/8  

#if SYSTEM_SUPPORT_OS               //如果需要支持OS.

    reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为K    

    reload*=1000000/RTOS_TicksPerSecond;

    //根据RTOS_TicksPerSecond设定溢出时间

    //reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右  

    fac_ms=1000/RTOS_TicksPerSecond; //代表OS可以延时的最小单位

    SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;   //开启SYSTICK中断

    SysTick->LOAD=reload; //每1/RTOS_TicksPerSecond秒中断一次 

    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启CPU的滴答时钟(SysTick)  

#else

    fac_ms=(u16)fac_us*1000;//不支持OS,代表每个ms需要的systick时钟数   

#endif

}                                  

#if SYSTEM_SUPPORT_OS  //如果需要支持OS.

//函数功能:延时nus

//nus为要延时的us数.                                              

void delay_us(u32 nus)

{      

    u32 ticks;

    u32 told,tnow,tcnt=0;

    u32 reload=SysTick->LOAD; //LOAD的值             

    ticks=nus*fac_us;         //需要的节拍数             

    tcnt=0;

    RTOS_SchedLock();//阻止OS调度,防止打断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;//时间超过/等于要延迟的时间,则退出.

        } 

    };

    RTOS_SchedUnlock();//恢复OS调度                                       

}

//函数功能:延时nms

//nms:要延时的ms数

void delay_ms(u16 nms)

{  

    if(RTOS_Running&&RTOS_InterruptNesting==0)     

    {//如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)      

        if(nms>=fac_ms) //延时的时间大于OS的最小时间周期

        {

            RTOS_TimeDelay(nms/fac_ms); //OS延时

        }

        nms%=fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时   

    }

    delay_us((u32)(nms*1000));//普通方式延时 

}

#else //不用OS时

//函数功能:延时nus

//nus为要延时的us数.                                              

void delay_us(u32 nus)

{      

    u32 temp;            

    SysTick->LOAD=nus*fac_us;                   //时间加载           

    SysTick->VAL=0x00;                          //清空计数器

    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;    //开始倒数   

    do

    {

        temp=SysTick->CTRL;

    }while((temp&0x01)&&!(temp&(1<<16)));       //等待时间到达  

    SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;    //关闭计数器

    SysTick->VAL =0X00;                          //清空计数器  

}

//函数功能:延时nms

//注意nms的范围

//SysTick->LOAD为24位寄存器,所以,最大延时为:

//nms<=0xffffff*8*1000/SYSCLK

//SYSCLK单位为Hz,nms单位为ms

//对72M条件下,nms<=1864

void delay_ms(u16 nms)

{                

    u32 temp;         

    SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)

    SysTick->VAL =0x00;                         //清空计数器

    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;    //开始倒数 

    do

    {

        temp=SysTick->CTRL;

    }while((temp&0x01)&&!(temp&(1<<16)));       //等待时间到达  

    SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;    //关闭计数器

    SysTick->VAL =0X00;                         //清空计数器            

}

#endif

3、uCOSii任务延时

在使用OSTimeDlyHMSM()和OSTimeDly()之前,先要在os_cfg.h文件中设置好OS_TICKS_PER_SEC,如下:

#define OS_TICKS_PER_SEC  1000u  /*设置OSTimeDlyHMSM()函数中每秒的节拍数*/

const char TEST1_TASK_rn_REG[]="\r\n";

const char TEST1_TASK_REG[]="TEST1_TASK";

//TEST1_TASK任务

void TEST1_TASK(void *pdata)

{

    u32 time;

    (void)pdata;

    while(1)

    {

       printf("%s",TEST1_TASK_rn_REG);

        printf("%s",TEST1_TASK_REG);

//     OSTimeDlyHMSM(0,0,0,500);//当前任务延时0.5秒

       OSTimeDly(500);

    //当前任务延时500个节拍

    //当OS_TICKS_PER_SEC=1000时,这里就是0.5秒

       OSTimeDlyResume(TEST2_TASK_PRIORITY);

       //唤醒一个“因OSTimeDly()或OSTimeDlyHMSM()而挂起的任务”

       time=OSTimeGet();//读取OSTime的值

       printf("%s",TEST1_TASK_rn_REG);

       printf("time=%u",time);

       OSTimeSet(0);//设置OSTime=0

    }

}

const char TEST2_TASK_rn_REG[]="\r\n";

const char TEST2_TASK_REG[]="TEST2_TASK";

//TEST2_TASK任务

void TEST2_TASK(void *pdata)

{

    (void)pdata;

    while(1)

    {

       printf("%s",TEST2_TASK_rn_REG);

        printf("%s",TEST2_TASK_REG);

       OSTimeDlyHMSM(0,0,5,0);//当前任务延时5秒,合计5000个节拍

    }

}

测试结果:

4、uCOSii软件定时器

在使用“软件定时器”之前,先要在os_cfg.h文件中设置好OS_TMR_CFG_TICKS_PER_SEC,如下:

#define OS_TMR_CFG_TICKS_PER_SEC 1000u  /*设置软件定时器的时钟源频率为0.001Hz*/

#include "TEST1_TASK.h"

#include "stdio.h"

 //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "My_Task_Priority.h"

OS_TMR   *MySoftTimer1;//软件定时器1

void TEST1_TASK(void *pdata);

const char TEST1_TASK_rn_REG[]="\r\n";

const char MySoftTimer1_TASK_REG[]="MySoftTimer1_TASK";

//函数功能:MySoftTimer1软件定时器的回调函数

void MySoftTimer1_Callback(OS_TMR *ptmr,void *p_arg)

{

    printf("%s",TEST1_TASK_rn_REG);

    printf("%s",MySoftTimer1_TASK_REG);

}

//TEST1_TASK任务

void TEST1_TASK(void *pdata)

{

    u8 err;

    (void)pdata;

//#define OS_TMR_CFG_TICKS_PER_SEC 1000u

    MySoftTimer1=OSTmrCreate( 0,\

                              1000,\

                              OS_TMR_OPT_PERIODIC,\

                             (OS_TMR_CALLBACK)MySoftTimer1_Callback,\

                              0,\

                              (u8*)"tmr1",\

                             &err);

    //1000ms执行一次,自动重

    OSTmrStart(MySoftTimer1,&err);//启动软件定时器MySoftTimer1

    while(1)

    {

        OSTimeDlyHMSM(0,0,0,10);//当前任务延时0.01秒,合计10个节拍

    }

}

 

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

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

相关文章

极致呈现系列之:Echarts地图的浩瀚视野(二)

今天我将基于上一个博客讲到的Echarts地图的相关知识&#xff0c;来实现一个三维地图的效果&#xff0c;我将通过两种方式来实现&#xff0c;一种是伪3D效果的中国地图效果&#xff0c;为什么说是伪3D效果呢&#xff0c;跟着做完你就明白了&#xff1b;一种是真正的三维效果中国…

Eclipse添加Spket插件实现ExtJs智能提示

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、使用步骤1.解压Spket插件2.重启 Eclipse3.配置 Spket4.添加 Library5.添加 File6.将 extjs 设置为 Default7.将 *.js 文件的默认编辑器设置为 Spket JavaSc…

本地连接服务器搭建的 Redis 集群

本地连接服务器搭建的 Redis 集群 在实际运行测试中&#xff0c;存在两个问题 安全组或防火墙开放端口 主要开放10000端口。如果要连接 Redis集群的应用服务不和 Redis集群在一个局域网下&#xff0c;会出现连接异常。 第一个问题检查防火墙或安全组就可以解决&#xff0c;第…

我为开放原子全球开源峰会助力

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

Linux运维监控学习笔记1

1. 监控系统的概念&#xff1a; 监控系统&#xff0c;将所有需要监控的服务器及其各种各种需要的状态数据都实时地收集&#xff0c;并图形化地展示&#xff0c;并可以进行报警&#xff0c;让机器主动及时地与人沟通。 2. 为什么要监控&#xff1f; 答&#xff1a;实时地收集数…

练习:逻辑回归

练习2&#xff1a;逻辑回归 介绍 在本练习中&#xff0c;您将实现逻辑回归并将其应用于两个不同的数据集。还将通过将正则化加入训练算法&#xff0c;来提高算法的鲁棒性&#xff0c;并用更复杂的情形来测试模型算法。 在开始练习前&#xff0c;需要下载如下的文件进行数据上…

【开发细节】SpringBoot配置文件的spring.profiles下的active和include属性的区别和作用

目录 问题作用spring.profiles.activespring.profiles.include 总结 问题 我们经常在项目的application.yml中看到这样的配置&#xff0c;如下&#xff1a; 在 Spring Boot 中&#xff0c;spring.profiles.active 和 spring.profiles.include 属性都是用来配置 profile 的。 …

C++设计模式之单例模式(Singleton)

文章目录 定义前言1. 问题2. 解决方案 适用场景实现方式优点缺点与其他模式的关系懒汉单例模式代码1. 线程不安全的懒汉单例模式2. 线程安全的懒汉单例模式 饿汉单例模式代码Meyers Singleton优点&#xff1a;缺点&#xff1a; 定义 单例是一种创建型设计模式&#xff0c;让你…

从“五个女博士”事件,论品牌广告营销的正确姿势

【潮汐商业评论/原创】 “她经济”是一片浩浩荡荡又风云变幻的海&#xff0c;“美”则是其中贯穿女性一生的课题&#xff0c;如果说这两年这个课题有什么变化&#xff0c;那就是从“女为悦己者容”到“女为自己容”&#xff0c;女性追求美的出发点早就不再是取悦他人“服美役”…

从外资企业数字化趋势看MNC根植中国的新逻辑

导读&#xff1a;外企数字化发展&#xff0c;也要“在中国&#xff0c;为中国” 外资企业一直是中国经济发展的重要推动力量。根据商务部数据&#xff0c;2022年中国实际使用外商直接投资金额达到1891亿美元&#xff0c;创历史新高&#xff0c;同比增速为8%。中国经济强大的韧性…

linux下文件锁使用总结

linux锁存在强制锁&#xff08;mandatory lock&#xff09;和劝告锁&#xff08;advisory lock&#xff09;。所谓强制锁&#xff0c;就是一个进程获取了那把锁&#xff08;只有一把钥匙&#xff09;&#xff0c;只有一个进程可以操作&#xff0c;别的进程无能为力。所谓劝告锁…

【数据库】Mysql索引、事务与存储引擎

文章目录 一、索引介绍1. 索引的概念2. 索引的作用与副作用2.1 索引的作用2.2 索引的副作用2.3 如何实现索引 3. 创建索引的原则依据4. 索引的分类和创建4.1 普通索引直接创建索引修改表方式创建创建表的时指定索引 4.2 唯一索引直接创建唯一索引修改表方式创建创建表的时候指定…

实测Maven依赖包可通过域名抢注实现钓鱼攻击吗

先说结论&#xff1a;基本不可行 原理 Maven包中 groupId 字段是域名反写&#xff0c;比如你有一个 12345.com&#xff0c;就可以申请到 com.12345 的groupId。 很多开源项目都停止维护&#xff0c;但是很多人使用&#xff0c;这些团队可能忘记续费域名&#xff1b;同时目前…

keras运行debug解决protobuf版本冲突

# code 5.4 使用Keras实现异或网络 import numpy as np from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Activation from tensorflow.keras.optimizers import SGD x_train np.array([[0, 0],[0, 1],[1, 0],[1, 1] ]) y_train …

她98年的,我玩不过她...┭┮﹏┭┮

现在的小年轻真的卷得过分了。前段时间我们公司来了个98年的&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 最近和他聊了一次天&#xff0c;原来这位小老弟家里条…

高级VLAN_vlan聚合(Super VLAN)实验

vlan聚合(Super_VLAN) 就是在一个物理网络里面用多个vlan来隔离广播域,将这个vlan聚合成一个逻辑vlan就有了Super vlan,这些多个vlan共用一个ip子网和网关, 目的就是为了节约ip地址资源 普通vlan示意图 普通vlan就存在很多网关,有的vlan可能会存在只有20个主机设备,但是需要划…

罗德FSH13手持式频谱分析仪RohdeSchwarz

FSH4和R&S?FSH8是罗德与施瓦茨公司全新推出面向未来应用的手持式频谱分析仪。它集频谱分 析、天馈线分析、全功能矢量网络分析、矢量电压表、功率计主机、宽带通信解调等多种测试功能 于一身&#xff0c;拥有媲美中高档台式频谱仪的指标。R&S?FSH4和R&S?FSH8完美…

023+limou+C语言的“可变参数列表”和“命令行参数”以及“递归调用”

0.前言 您好&#xff0c;这里是limou3434的一篇博文&#xff0c;感兴趣可以看看我的其他内容。本次我给您带来了C语言的“可变参数列表”&#xff0c;要明白这些内容&#xff0c;您可能需要重新复习下C语言视角的栈帧空间知识。最后我还给出两个小的C语言知识点&#xff1a;“…

Metasploit渗透测试框架

文章目录 Metasploit渗透测试框架基于TCP协议收集主机信息开放端口扫描db_nmap查询网段内在线存活的主机半连接的方式进行半连接扫描使用auxiliary/sniffer下的psunffle模块进行密码嗅探 基于SNMP协议收集主机信息基于SSH协议收集主机信息实战-制作Linux恶意病毒获取公司服务权…

JAVA开发(通过Apollo注入配置信息的几种方式)

前言 在springCloud中有一个重要的组件就是配置中心&#xff0c;config:server&#xff0c;用于配置springboot中需要注入的各种配置项。但是现在发现越来越多的企业使用Apollo进行集成。博主在开发中也是使用Apollo进行配置。本文总结Apollo的的使用&#xff0c;集成到spring…