搜索
bottom↓
回复: 0

RTOS的精确延时功能扩展

[复制链接]

出870入263汤圆

发表于 2012-5-10 08:34:18 | 显示全部楼层 |阅读模式
本帖最后由 armstrong 于 2012-5-10 08:43 编辑

大家都知道,OS有一个系统时基,这个时基大多取值为100,200,500,1000。一般都不会大于1000,1000的时候,意味着每1毫秒就产生一次时基中断,OS时基函数也就被执行一次,如果这个时基中断产生的太频繁,对系统性能是有很大影响的。假设我们的系统时基选择100,那就是延时精度为10毫秒。这种精度很让人烦恼不是吗?
那么怎样提供一个精确的RTOS延时而又不增加系统负担呢?
在延时段死循环执行指定数量的指令?不是!因为这是最浪费CPU资源的做法!
把RTOS时基增加?也不是!因为每个时基都会耗费CPU资源,增加时基就意味着增加CPU资源耗费!
这里,我在LPC17xx上使用RIT模块实现了一个精确延时模块,目前精度为10微秒,系统是ucos-ii,供大家参考。
原理很简单,就是维护一个链表结构。有几个线程正在延时,就有几个链表节点,链表节点不占用堆内存,用的是线程局部堆栈。
延时计数硬件不用每10微秒产生中断,中断次数就等于链表的节点数而已!如果不用RIT硬件模块,其他硬件定时器一样可以实现的。
贴上代码先,然后再来分析。

头文件内容:
typedef struct {
    u32_t ticks;
    OS_EVENT *ev;
    void *next;
} hp_tmr_t;

void hp_timer_init(void);
void hp_delay(u32_t ticks);
void hp_delay_ex(hp_tmr_t *tmr);

C文件内容:
static u32_t hpTickBase;
static hp_tmr_t *hpList = NULL;
////////////////////////////////////////////////////////////////////////////////
//|          |
//| 函数名称 |: hp_timer_init
//| 功能描述 |:
//|          |:
//| 参数列表 |:
//|          |:
//| 返    回 |:
//|          |:
//| 备注信息 |: 10uS延时单位。
//|          |:
////////////////////////////////////////////////////////////////////////////////
void hp_timer_init(void)
{
    u32_t utmp;
   
    target_enable_power(PCONP_RIT);
    utmp = target_get_apbclk(PCLK_RIT);
    utmp /= 100000u;    /* 每10uS的APB时钟计数。*/
    hpTickBase = utmp;
   
    NVIC_DisableIRQ(RIT_IRQn);
    LPC_RIT->RIMASK = 0u;
    // 清除中断标志并停止计数器。
    LPC_RIT->RICTRL = ((1<<2)|(1<<0));
    NVIC_EnableIRQ(RIT_IRQn);
}

////////////////////////////////////////////////////////////////////////////////
//|          |
//| 函数名称 |: RIT_IRQHandler
//| 功能描述 |:
//|          |:
//| 参数列表 |:
//|          |:
//| 返    回 |:
//|          |:
//| 备注信息 |:
//|          |:
////////////////////////////////////////////////////////////////////////////////
void RIT_IRQHandler(void)
{
    DECL_CPU_SR;
    u32_t tmval;
    hp_tmr_t *p;
   
    // 清除中断标志并停止计数器。
    LPC_RIT->RICTRL = ((1<<2)|(1<<0));
    OS_ENTER_CRITICAL();
    OSIntNesting++;
    p = hpList;
    while(p && (p->ticks == 0)){
        if(p->ev){
            OSSemPost(p->ev);
        }
        p = (hp_tmr_t *)p->next;
    }
    hpList = p;
    if(p){
        tmval = p->ticks*hpTickBase;
        tmval += LPC_RIT->RICOUNTER;
        LPC_RIT->RICOMPVAL = tmval;
        p->ticks = 0;
        LPC_RIT->RICTRL = ((1<<2)|(1<<3));
    }
    OS_EXIT_CRITICAL();
   
    OSIntExit();
}

////////////////////////////////////////////////////////////////////////////////
//|          |
//| 函数名称 |: __internal_delay
//| 功能描述 |:
//|          |:
//| 参数列表 |:
//|          |:
//| 返    回 |:
//|          |:
//| 备注信息 |: 10uS延时单位。
//|          |:
////////////////////////////////////////////////////////////////////////////////
static void __internal_delay(hp_tmr_t *tmr)
{
    hp_tmr_t *p;
    DECL_CPU_SR;
    INT8U err;
    u32_t cnt;
   
    tmr->next = 0;
    OS_ENTER_CRITICAL();
    // 清除中断标志并停止计数器。
    LPC_RIT->RICTRL = ((1<<2)|(1<<0));
    p = hpList;
    if(p){
        cnt = LPC_RIT->RICOMPVAL;
        cnt -= LPC_RIT->RICOUNTER;
        cnt /= hpTickBase;
        LPC_RIT->RICOMPVAL -= cnt*hpTickBase;
        p->ticks += cnt;
        if(p->ticks > tmr->ticks){
            p->ticks -= tmr->ticks;
            tmr->next = p;
            hpList = tmr;
        }else{
            while(1){
                tmr->ticks -= p->ticks;
                if(p->next == NULL){
                    p->next = tmr;
                    break;
                }
                if(((hp_tmr_t *)p->next)->ticks >= tmr->ticks){
                    ((hp_tmr_t *)p->next)->ticks -= tmr->ticks;
                    tmr->next = p->next;
                    p->next = tmr;
                    break;
                }
                p = p->next;
            }
        }
        cnt = hpList->ticks;
        LPC_RIT->RICOMPVAL += cnt*hpTickBase;
        hpList->ticks = 0;
    }else{
        // 列表为空。
        hpList = tmr;
        cnt = tmr->ticks*hpTickBase;
        cnt += LPC_RIT->RICOUNTER;
        LPC_RIT->RICOMPVAL = cnt;
        tmr->ticks = 0;
    }
    // 启动计数器。
    LPC_RIT->RICTRL = ((1<<2)|(1<<3));
    OS_EXIT_CRITICAL();
   
    OSSemPend(tmr->ev, 0, &err);
}

////////////////////////////////////////////////////////////////////////////////
//|          |
//| 函数名称 |: hp_delay
//| 功能描述 |:
//|          |:
//| 参数列表 |: ticks 延时时间,单位是10uS。
//|          |:
//| 返    回 |:
//|          |:
//| 备注信息 |: 注意:100MHZ主频时,调用该函数会有10uS以上的代码执行开销,因此:
//|          |:       当ticks参数为1时,当函数返回时就已经过去10+10uS时间了。
//|          |:       当ticks参数为100时,实际上延时了1000+10uS,以此类推。
////////////////////////////////////////////////////////////////////////////////
void hp_delay(u32_t ticks)
{
    OS_EVENT *ev = OSSemCreate(0);
    INT8U err;
   
    if(ev && ticks){
        hp_tmr_t tmr;
        tmr.ticks = ticks;
        tmr.ev = ev;
        __internal_delay(&tmr);
        OSSemDel(ev, OS_DEL_ALWAYS, &err);
    }
}

////////////////////////////////////////////////////////////////////////////////
//|          |
//| 函数名称 |: hp_delay_ex
//| 功能描述 |:
//|          |:
//| 参数列表 |:
//|          |:
//| 返    回 |:
//|          |:
//| 备注信息 |: 10uS延时单位。
//|          |:
////////////////////////////////////////////////////////////////////////////////
void hp_delay_ex(hp_tmr_t *tmr)
{
    if(tmr && tmr->ev && tmr->ticks){
        __internal_delay(tmr);
    }
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-26 01:16

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表