补办手机卡需要什么| 二聚体是什么| 高烧拉肚子是什么原因| 雷达是什么| 熊猫为什么被称为国宝| 产妇能吃什么水果| 早上起床有眼屎是什么原因| 延时吃什么药| e大饼是什么牌子| 银屑病是什么引起的| 咖啡烘培度有什么区别| 肋软骨炎挂什么科| 头晕恶心想吐挂什么科| 手指脱皮是什么原因| 火字旁的字有什么| 鲁迅是什么样的人| 身上长水泡是什么原因| 下面干涩是什么原因导致的| 乙肝五项一五阳性什么意思| 身上有白点是什么原因| 肛门下坠感是什么症状| 耀眼是什么意思| 玑是什么意思| 孕前检查什么时候去最合适| 什么的桃花| 尿频吃什么药最好| 中医四诊是什么| 口腔溃疡是什么引起的| 肾精亏虚是什么意思| 一什么木屋| 西装外套配什么裤子| 雌激素分泌过多是什么原因引起的| 副乳有什么危害吗| 桃花劫是什么意思| fsa是什么意思| 河水什么的流着| 心绞痛吃什么药最好| 细菌感染吃什么抗生素| 狗狗咳嗽吃什么药好得快| 两毛四是什么军衔| 水木年华是什么意思| 三月有什么节日| 盔甲是什么意思| 7月26是什么星座| 水瓶座和什么座最配对| 子宫内膜异位症是什么意思| 孕妇梦见摘桃子是什么意思| 三叉神经痛有什么症状| 堂哥的儿子叫什么| jk制服什么意思| 腰突然疼是什么原因| 鸡骨草有什么功效| 腰疼去医院挂什么科| 拿什么证明分居两年| 前壁后壁有什么区别| 吃什么拉什么是什么原因| 左边头痛什么原因| 八院是什么医院| 乳腺4a类是什么意思| 梦见粉条是什么意思| 肠胃炎可以喝什么饮料| xo酱是什么酱| 吃中药为什么要忌口| 四个人念什么| 宫颈息肉有什么症状| 昱五行属性是什么| 腰肌劳损是什么原因造成的| 湿疹吃什么食物好得快| 降低压吃什么药| 澳大利亚人说什么语言| 检查肺部最好做什么检查最准确| 什么是辛辣刺激性食物| 苗侨伟为什么叫三哥| 脚趾头疼是什么原因| 绿豆不能跟什么一起吃| 怀孕什么时候可以同房| 进是什么结构| 梦见牛肉有什么征兆| 黄明胶是什么| 凝聚力是什么意思| 前列腺增生吃什么药效果最好| 6月份是什么星座| 过问是什么意思| 脂溢性脱发是什么意思| 蟋蟀用什么唱歌| 蜜蜡是什么材料| lhrh是什么激素| pd950是什么金| 尿液发黄是什么病| 过期的酸奶有什么用| mono是什么意思| 脑内散在缺血灶是什么意思| 水为什么是蓝色的| 胸口闷疼是什么原因| 上腹部饱胀是什么原因| 奥康属于什么档次| 佛龛是什么| 肉蔻炖肉起什么作用| 梦见大水是什么意思| 浑身疼吃什么药| 蚊子会传播什么疾病| 胃一阵一阵的疼是什么原因| 嗜酸性肉芽肿是什么病| 刘备代表什么生肖| 肝功能四项检查什么| 土色是什么颜色| 犀利是什么意思| 九月二十八是什么星座| 双的反义词是什么| 吃什么盐最好| 猪朋狗友是什么意思| 夏天煲什么汤| 重阳节干什么| 被电击后身体会有什么后遗症| 为什么会得丹毒| 阿里巴巴是干什么的| 动脉硬化挂什么科| 小叶增生是什么原因导致的| 小螃蟹吃什么| 不可磨灭是什么意思| 诗情画意的意思是什么| 肠胃炎可以吃什么药| 纪年是什么意思| 旺是什么意思| 喜鹊叫有什么兆头| 保胎吃什么食物好| 孕妇吃什么坚果比较好| 大水冲了龙王庙什么意思| 三点水加四读什么| 什么酷暑| 扁尖是什么| 2月20日是什么星座| 孩子呕吐吃什么药| 俊五行属什么| 嗯嗯嗯是什么意思| 梭边鱼是什么鱼| hisense什么牌子| 蝎子喜欢吃什么| 吃阿胶对女人有什么好处| 屎壳郎是什么意思| 83年属什么| 尿素氮偏低是什么意思| 盐冻虾是什么意思| 生理盐水敷脸有什么效果| 都市丽人是什么意思| 全科医生是什么意思| 猪八戒的真名叫什么| 玛丽珍鞋是什么意思| 高血钾是什么意思| 代偿期和失代偿期是什么意思| 情调是什么意思| 阴道口痛什么原因| 梅毒通过什么传播| 慎重考虑是什么意思| 如来是什么意思| 失眠是什么意思| 脑供血不足做什么检查| 资讯是什么意思| 月经要来之前有什么症状| 入殓师是做什么的| hcg是什么激素| 血压高吃什么食物好| 挂失补办身份证需要什么| 肠炎发烧吃什么药| 肝浸润是什么意思| 老人头发由白变黑是什么原因| 猫的耳朵有什么作用| 暗送秋波是什么意思| 脾肾亏虚的症状是什么| 吃什么可以让阴茎变硬| 百思不得其解什么意思| 三庭五眼是什么意思| 男人眼袋大是什么原因造成的| 郁金香的花语是什么| 会厌炎是什么病| 天丝是什么材料| 10月生日是什么星座| 什么是雾霾| 婴儿湿疹用什么| 什么叫专科| 小孩吃火龙果有什么好处| 锐字五行属什么| 新白娘子传奇许仙为什么用女的演| 林是什么生肖| 总胆红素偏高说明什么| 妇科病有什么症状| 定增股票是什么意思| 冻感冒了吃什么药| 亲子鉴定需要什么| 什么水果是热性的| 幻和是什么意思| 隐翅虫皮炎用什么药| 梦见狐狸是什么预兆| 炒菜勾芡用什么淀粉| 听吧新征程号角吹响是什么歌| 有容乃大什么意思| 肱骨头小囊变什么意思| 脸上过敏用什么药膏| 壮的偏旁叫什么名字| 天宫是什么意思| 什么是蝴蝶宝宝| 年柱金舆是什么意思| 雨水是什么季节| 痛风什么引起的原因有哪些| 闰年是什么| 婴儿胎毛什么时候剃最好| 鼻炎是什么原因引起的| 肚子右边是什么部位| 圣诞礼物什么时候送| 四不像长什么样| 宅心仁厚是什么意思| 7月7是什么节日| 3月27号是什么星座| 甘露是什么| 什么的废墟| 肠粘连是什么原因引起| 印度神油是什么东西| 一什么青蛙| 疱疹用什么药可以根治| 6月3日是什么星座| 什么是美尼尔氏综合症| 女主是什么意思| 甘的部首是什么| 枸杞有什么用| 肾阳虚吃什么药最好| 窦性心律室性早搏是什么意思| bf是什么| 阑珊是什么意思| 虎眼石五行属什么| 欢什么喜什么| ca125是查什么的| 什么贤什么能| 为什么萤火虫会发光| 更年期出虚汗吃什么药| 梦见自己假牙掉了是什么意思| 塑料是用什么做的| 睡眠不好总做梦是什么原因| 不丹为什么不跟中国建交| 丈夫早亡的女人什么命| 八段锦是什么| 什么条什么理| 人为什么会说梦话| 金族念什么| 粽子的叶子是什么叶| 吃什么升血小板快| 早餐吃什么不会胖| 什么的麦子| 新生儿屁多是什么原因| 医共体是什么意思| 梦见自己剪头发是什么意思| 拜阿司匹林和阿司匹林有什么区别| 澳大利亚属于什么国家| 3月14日是什么日子| 去黄疸吃什么药| 精子成活率低吃什么药| 结扎对男人有什么伤害| 张柏芝什么星座| 脚没力气是什么原因| 小腿疼痛什么原因引起的| 胃胀吃什么药效果最好| 鱼非念什么| o型血为什么招蚊子| 乔迁之喜送什么花| 肝郁吃什么药| 百度
这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 ? 论坛首页 ? 嵌入式开发 ? 软件与操作系统 ? rtthread硬件定时器框架

共4条 1/1 1 跳转至

rtthread硬件定时器框架

高工
2025-08-04 23:07:31     打赏
百度 官翻版本产品是在返厂或是某些不达标产品的基础上,通过维修检测而重新销售。

      硬件定时器,在配置上,其实可以分得很细,比如比较器,电容式触摸按键的时间窗口,PWM基础时钟,定时器。在RTThread的框架,硬件定时器特指定时器,其主要完成两类功能,一类是单次定时器,顾名思义,就是设定时间到了只执行一次的定时器,另一类是周期定时器,也就是说,定时时间到了,定时器产生中断回调并重新计数,下一次中断的到来再产生中断回调并重新计数,直到用户主动停止定时器。

硬件定时器代码分析

代码路径

\components\drivers\hwtimer\*

对驱动开放的接口

定时器注册接口

#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops hwtimer_ops =
{
    rt_hwtimer_init,
    rt_hwtimer_open,
    rt_hwtimer_close,
    rt_hwtimer_read,
    rt_hwtimer_write,
    rt_hwtimer_control
};
#endif

rt_err_t rt_device_hwtimer_register(rt_hwtimer_t *timer, const char *name, void *user_data)
{
    struct rt_device *device;

    RT_ASSERT(timer != RT_NULL);
    RT_ASSERT(timer->ops != RT_NULL);
    RT_ASSERT(timer->info != RT_NULL);

    device = &(timer->parent);

    device->type        = RT_Device_Class_Timer;
    device->rx_indicate = RT_NULL;
    device->tx_complete = RT_NULL;

#ifdef RT_USING_DEVICE_OPS
    device->ops         = &hwtimer_ops;
#else
    device->init        = rt_hwtimer_init;
    device->open        = rt_hwtimer_open;
    device->close       = rt_hwtimer_close;
    device->read        = rt_hwtimer_read;
    device->write       = rt_hwtimer_write;
    device->control     = rt_hwtimer_control;
#endif
    device->user_data   = user_data;

    return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
}

      从定时器注册接口来看,硬件定时器框架需要驱动注册时提供rt_hwtimer_t *的配置,具体此结构体指针需要配置的内容,暂时并不清晰,需对比驱动实现才能明白。另外,此驱动对上层应用按照设备驱动框架暴露了所有的接口,具体接口实现的功能,需要一个一个的查看。

硬件定时器中断处理函数

void rt_device_hwtimer_isr(rt_hwtimer_t *timer)
{
    rt_base_t level;

    RT_ASSERT(timer != RT_NULL);

    level = rt_hw_interrupt_disable();

    timer->overflow ++;

    if (timer->cycles != 0)
    {
        timer->cycles --;
    }

    if (timer->cycles == 0)
    {
        timer->cycles = timer->reload;

        rt_hw_interrupt_enable(level);

        if (timer->mode == HWTIMER_MODE_ONESHOT)
        {
            if (timer->ops->stop != RT_NULL)
            {
                timer->ops->stop(timer);
            }
        }

        if (timer->parent.rx_indicate != RT_NULL)
        {
            timer->parent.rx_indicate(&timer->parent, sizeof(struct rt_hwtimerval));
        }
    }
    else
    {
        rt_hw_interrupt_enable(level);
    }
}

      与串口框架类似,硬件定时器也向驱动暴露了中断处理接口,其中,如果是单次触发模式,则在中断处理中向驱动发送停用定时器命令。若注册了中断回调函数,则在产生处理完定时器内部资源后,主动向回调注册方发起回调处理事件。此外,可以看到,定时器的时间计数更新,也是在此中断处理函数中执行的,隐含了在open或者control接口中,有定时器时间转换成计数更新值和计数重复次数设置的逻辑,此逻辑在后面分析时需注意。

硬件定时器资源初始化接口

static rt_err_t rt_hwtimer_init(struct rt_device *dev)
{
    rt_err_t result = RT_EOK;
    rt_hwtimer_t *timer;

    timer = (rt_hwtimer_t *)dev;
    /* try to change to 1MHz */
    if ((1000000 <= timer->info->maxfreq) && (1000000 >= timer->info->minfreq))
    {
        timer->freq = 1000000;
    }
    else
    {
        timer->freq = timer->info->minfreq;
    }
    timer->mode = HWTIMER_MODE_ONESHOT;
    timer->cycles = 0;
    timer->overflow = 0;

    if (timer->ops->init)
    {
        timer->ops->init(timer, 1);
    }
    else
    {
        result = -RT_ENOSYS;
    }

    return result;
}

      从注册函数上看,硬件定时器会尝试将定时器的共做频率设置在1MHz上,若定时器无法满足要求,则按照定时器支持的最低频率执行。另外,从此函数中可以看到,驱动必须实现init函数,否则硬件定时器无法工作。

硬件定时器打开接口

static rt_err_t rt_hwtimer_open(struct rt_device *dev, rt_uint16_t oflag)
{
    rt_err_t result = RT_EOK;
    rt_hwtimer_t *timer;

    timer = (rt_hwtimer_t *)dev;
    if (timer->ops->control != RT_NULL)
    {
        timer->ops->control(timer, HWTIMER_CTRL_FREQ_SET, &timer->freq);
    }
    else
    {
        result = -RT_ENOSYS;
    }

    return result;
}

      从实现上看,打开接口实际调用的是control接口的HWTIMER_CTRL_FREQ_SET命令,control的具体调用信息,只能等待会查看control接口时才能明白。

硬件定时器关闭接口

static rt_err_t rt_hwtimer_close(struct rt_device *dev)
{
    rt_err_t result = RT_EOK;
    rt_hwtimer_t *timer;

    timer = (rt_hwtimer_t*)dev;
    if (timer->ops->init != RT_NULL)
    {
        timer->ops->init(timer, 0);
    }
    else
    {
        result = -RT_ENOSYS;
    }

    dev->flag &= ~RT_DEVICE_FLAG_ACTIVATED;
    dev->rx_indicate = RT_NULL;

    return result;
}

      从实现上,感觉此接口有些让人摸不着头脑,让驱动资源初始化为0是什么意思?这个功能也只有后续分析驱动函数中的init实现时才能彻底明白了。另外,关闭函数同步把应用的回调函数清除了。

硬件定时器读接口

static rt_ssize_t rt_hwtimer_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    rt_hwtimer_t *timer;
    rt_hwtimerval_t tv;
    rt_uint32_t cnt;
    rt_base_t level;
    rt_int32_t overflow;
    float t;

    timer = (rt_hwtimer_t *)dev;
    if (timer->ops->count_get == RT_NULL)
        return 0;

    level = rt_hw_interrupt_disable();
    cnt = timer->ops->count_get(timer);
    overflow = timer->overflow;
    rt_hw_interrupt_enable(level);

    if (timer->info->cntmode == HWTIMER_CNTMODE_DW)
    {
        cnt = (rt_uint32_t)(timer->freq * timer->period_sec) - cnt;
    }
    if (timer->mode == HWTIMER_MODE_ONESHOT)
    {
        overflow = 0;
    }

    t = overflow * timer->period_sec + cnt/(float)timer->freq;
    tv.sec = (rt_int32_t)t;
    tv.usec = (rt_int32_t)((t - tv.sec) * 1000000);
    size = size > sizeof(tv)? sizeof(tv) : size;
    rt_memcpy(buffer, &tv, size);

    return size;
}

      从读接口可以看出,应用层传递的buffer实际上要求是rt_hwtimerval_t的结构体。另外读接口实际的功能应该是获取目前已计时的时间长度。

硬件定时器写接口

      既然读接口是读取已计时时间长度的功能,那写接口大概率是设置计时器工作模式和定时长度的功能了。

      而从上面实现上来看,写功能确实是这么个功能。另外,硬件定时器注册接口中所使用到的cycles和reload的设置,在这个接口中暴露出来了,即函数timeout_calc的实现。

硬件定时器控制接口

      从switch的实现上来看,control接口实现了四个基本的功能:

            1. 停止计时器HWTIMER_CTRL_STOP,直接调用驱动提供的stop函数,此函数驱动必须实现

            2. 设置定时器工作频率接口 HWTIMER_CTRL_FREQ_SET,此接口和open函数共用,因此可以看出,其实只要设置了工作频率,定时器就应该跑起来了

            3. 获取定时器参数接口 HWTIMER_CTRL_INFO_GET,由于只是获取已有的结构体,因此并未做开关全局中断的操作定时

            4. 工作模式设置接口 HWTIMER_CTRL_MODE_SET,顾名思义,此接口就是设置定时器的工作模式,即 单次模式(HWTIMER_MODE_ONESHOT)和周期模式(HWTIMER_MODE_PERIOD)二选一

结语

    至此,硬件定时器框架部分已全部解析完毕,从实现上来看,我们还是能看出,RTT目前代码开关全局中断的操作还是过于泛滥,个人理解此处的开关全局中断的操作完全可以使用开关特定定时器的方式实现,没必要全局开关中断,导致其他中断无法正常执行。

       另外,从硬件定时器暴露的接口上来看,硬件定时器并未暴露RTT文档中提出的应用层调用接口,也就意味着在框架层上还有一层封装(或者说,还有一套硬件定时器的实现逻辑),这个需要后续继续分析。可以提前剧透的点是,系统应用层暴露出来的定时器接口,仅仅可以实现systick级别的计时,而若要实现us级别的定时器,必须通过find,open,read,write,control接口直接调用本篇内容提供的硬件定时器接口。

      最后,我们分析完硬件定时器框架,可以获得如下适配硬件定时器模板,以便后续移植新平台时使用

typedef struct _timer
{
    char *name;
    struct repeating_timer repeat_timer;
    alarm_id_t alarm_id;
    rt_hwtimer_t timer;
}_timer_t;

static void _hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state);
static rt_err_t _hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode);
static void _hwtimer_stop(rt_hwtimer_t *timer);
static rt_uint32_t _hwtimer_count_get(rt_hwtimer_t *timer);
static rt_err_t _hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args);
static int64_t _hwtmr_isr(alarm_id_t id, void *user_data);

static const struct rt_hwtimer_ops _hwtimer_ops = {
    .init = _hwtimer_init,
    .start = _hwtimer_start,
    .stop = _hwtimer_stop,
    .count_get = _hwtimer_count_get,
    .control = _hwtimer_control
};

static const struct rt_hwtimer_info _hwtimer_info = {
    .maxfreq = 1000000UL,
    .minfreq = 1000000UL,
    .maxcnt = 0xFFFF,
    .cntmode = HWTIMER_MODE_PERIOD
};

static _timer_t timer0 = {.name = "timer0"};

static _timer_t *_timer_obj[] = {
        &timer0,
};


// TODO:硬件定时器中断处理实现
// 功能为调用硬件定时器中断回调处理函数rt_device_hwtimer_isr

static void _hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state)
{
    //TODO:通过state的值做硬件定时器的初始化和接初始化
}

static rt_err_t _hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
{
    // TODO:硬件定时器启动实现
    return RT_EOK;
}

static void _hwtimer_stop(rt_hwtimer_t *timer)
{
    // TODO:硬件定时器停用实现
}

static rt_uint32_t _hwtimer_count_get(rt_hwtimer_t *timer)
{
    rt_uint32_t count;
    
    // TODO:获取硬件定时器计数值实现
    // count = xxxx;

    return count;
}

static rt_err_t _hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
{
    rt_err_t err = RT_EOK;
    _timer_t *_tmr = rt_container_of(timer, _timer_t, timer);

    switch (cmd)
    {
    case HWTIMER_CTRL_FREQ_SET:
        // TODO:获取硬件定时器工作频率实现
        break;
    case HWTIMER_CTRL_INFO_GET:
        // TODO: 读取硬件定时器参数实现
        break;
    case HWTIMER_CTRL_MODE_SET:
        // TODO:设置硬件定时器工作模式接口实现
        break;
    case HWTIMER_CTRL_STOP: 
        _hwtimer_stop(timer);
        break;
    }

    return err;
}

int rt_hw_hwtimer_init(void)
{
    int ret = RT_EOK;

    for (uint32_t i = 0; i < sizeof(_timer_obj) / sizeof(_timer_obj[0]); i++)
    {
        _timer_obj[i]->timer.info = &_hwtimer_info;
        _timer_obj[i]->timer.ops = &_hwtimer_ops;
        ret = rt_device_hwtimer_register(&_timer_obj[i]->timer, _timer_obj[i]->name, _timer_obj[i]);
        if (ret != RT_EOK)
        {
            LOG_E("%s register failed", _timer_obj[i]->name);
        }
    }

    return ret;
}

INIT_DEVICE_EXPORT(rt_hw_hwtimer_init);




关键词: rtthread     硬件     定时器     框架    

专家
2025-08-04 00:29:15     打赏
2楼

感谢分享


专家
2025-08-04 00:32:53     打赏
3楼

感谢分享


专家
2025-08-04 00:34:28     打赏
4楼

感谢分享


共4条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]
月经推迟7天是什么原因 余田是什么字 皮粉色是什么颜色 6月16日是什么日子 睡不着觉吃什么药效果好
西夏国是现在什么地方 鲫鱼喜欢吃什么 吃什么壮阳补肾 脑梗是什么原因 口臭看什么科
胃疼检查什么项目 曝光是什么意思 几月初几是叫什么历 生日可以送什么礼物 慢性荨麻疹吃什么药
尿道尿血是什么原因 什么的表演 农历六月十七是什么星座 长痣是什么原因引起的 两个立念什么
肠上皮化生是什么意思hcv8jop7ns5r.cn 唐宝是什么意思hcv9jop6ns7r.cn 胆囊壁胆固醇结晶是什么意思hcv8jop1ns5r.cn 松针泡水喝有什么功效hcv8jop2ns6r.cn 登革热是什么hcv8jop9ns2r.cn
四是什么生肖hcv8jop9ns8r.cn 欲壑难填是什么意思hcv8jop9ns5r.cn 什么水果可以美白hcv8jop5ns6r.cn 背部长痘痘是什么原因造成hebeidezhi.com 甲苯对人体有什么危害hcv8jop8ns8r.cn
桂花是什么颜色weuuu.com 雨中漫步是什么意思hcv9jop5ns8r.cn 大象什么颜色hcv8jop7ns4r.cn 饭圈什么意思hcv9jop4ns2r.cn 桑螵蛸是什么hcv9jop0ns2r.cn
肌红蛋白高是什么意思hcv7jop6ns2r.cn 阿胶糕什么人不能吃hcv8jop2ns1r.cn 反黑是什么意思hcv9jop0ns6r.cn colorful是什么牌子hcv9jop5ns5r.cn 马上风为什么拔不出来hcv9jop5ns7r.cn
百度