目录
背景
为什么会用到软件定时器
定时器的工作流程
软件定时器是怎么实现的
软件定时器与硬件定时器比较
遇到了什么问题
问题解决与总结
事故现场回顾
相关文章补充
硬件环境:蓝牙芯片TLSR8258
软件环境:泰凌微官 的eclipse 及 工程例程
目标:使用软件定时器完成程序移植,修改灯的回调函数
接触蓝牙芯片之后了解到一个事实,它的主函数死循环中运行蓝牙协议栈,延时函数只能慎用,不能滥用,滥用则看门狗复位(大概时间为2S),所有的功能都是通过回调函数实现的,蓝牙接收回调,中断回调,定时回调(定时回调不见得是中断回调,因为软件定时器) 后来突然意识到另一个事实:蓝牙芯片大概是跑不了RTOS的,有不同见解的希望可以在评论区留言
为什么会用到软件定时器
定时器的工作流程
软件定时器需要一个精确的基准时间,因此是基于定时器(硬件定时器)实现的,通常硬件定时器是怎么使用的呢/p>
定时器的流程: 定时器先完成初始化, 当定时溢出时,跳转执行中断服务程序(中断回调函数),若为单次执行则结束,若为多次执行则将重装载值用于计数,产生下次定时中断。如果有多个硬件定时器,且同时定时溢出,会根据中断优先级高低先后响应,
只不过,有些中断回调函数比较长,比较耗时,若放在中断服务程序,会导致实时性受到影响(一是可能上一次的程序没执行完又产生了下一次定时中断,二是如果优先级较高,那其它优先级的中断就得不到及时响应,使用中断的时候应该都有个意识不能把延时函数放在中断服务程序里吧,因此如果中断比较多,中断服务程序的代码又比较长,都是在响应中断后将某个标志位置一,然后在主循环里查找到该标志位置一,先清零,然后执行相应程序,可能还有个关中断和开中断防止打断。
有软件定时器内味了(还没有提软件定时器的工作流程,有点儿自嗨了哈),但是硬件定时器是查找标志位,软件定时器是在逐个查找链表结点的成员变量(计数值)然后比较,即使都是在主循环中,但还是感觉硬件定时器快一些
软件定时器是怎么实现的
使用嵌入式大杂烩分享的Multi_timer软件定时器功能的程序模块,只有五个函数,定时器初始化,开启定时器,关闭定时器,计数数值,主循环执行。
定时器初始化,就是将定时器结构体变量的成员变量赋值,一个是设定值,一个是重装载值,还有一个是回调函数的函数指针
开启定时器,主要就是将结构体变量插入到链表中
关闭定时器,主要就是将结构体变量从链表中删除
计数数值,就是对硬件定时器的定时中断进行计数
主循环执行,就是逐个检查链表结点,是否溢出设定值,超过则意为定时中断,先用重装载值加上当前计数数值设定下次溢出时间,在此之前会先检查重装载值是否为0,若为0则将该结点从链表中删除(但结构体变量还存在,回调函数也可执行,只不过下次检查链表节点就没有该结构体变量了),然后执行回调函数。
我的理解方式是“增” “删” “改” “查”(这四个字最早接触应该是数据库的四项基本操作) 和 初始化
增:增加结构体变量到链表中
删:将结构体变量从链表中删除
改:每到定时中断时间则修改计数值
查:主循环中逐个查找链表上的软件定时器变量,若达到定时时间则执行该结构体变量的回调函数
初始化:初始化设置,极其常见,硬件外设调用自不必说,PID算法,操作系统等都需要初始化,应该是调用任何功能都会有个初始化,或显式或隐式
软件定时器与硬件定时器比较
硬件定时中断 相比软件定时回调 要更快响应 。因为可以立即跳转执行相应程序,软件定时是基于硬件定时的基础上计数,但执行相应程序(响应)是循环查找判断是否溢出设定值,且是在执行完主循环别的程序代码块之后
硬件定时器比软件定时器精度更高。硬件定时器是对定时器脉冲进行计数,可以在多少us时(即多少个定时器脉冲)产生定时中断,而软件定时要达到这种精度是无法做到的,因为需要设定1us定时中断用于计数,而如此频繁的定时中断势必打断其它函数运行,而且频繁的压栈弹出等操作,程序极可能是不能正常运行了的
遇到了什么问题
说起来还是第一次做关于灯的程序,动态的模式(闪烁,流水灯,随机闪烁,呼吸,颜色渐变)都是通过定时回调函数实现的。等等,不就是点个灯吗,放在main死循环里不行吗不行,因为while死循环里主要运行蓝牙协议栈,如果用延时函数延时个几秒,程序就因不喂看门狗而跑飞了。那就延时前后都加个喂狗就行了吗,不行,要是延时时间超过该喂狗的时间还是会出现这问题,那修改喂狗时间不就行了吗… …有个原则:实现自己的功能如非必要不能修改底层函数
底层无非就是IO口设置,pwm占空比设置,使用时遇到任何使用占空比的都没有动作,然而使用IO口设置的均可以正常工作,而且pwm占空比设置的回调函数也是可以进入的,但就是没执行。其实到这儿就该判断并非是软件定时器的问题了,为什么件定时器的工作流程。但我当时却不是这么想的,事后诸葛亮,自己写总结的时候才知道自己当时的想法是多么不成熟。 可能是对现象那么执迷(更该说成是执疑),对故障现象该抱着什么样的态度,欢迎在评论区留言
问题解决与总结
当时的情况是pwm设置直接放在主循环里可以执行。看现象不知道问题出在哪儿,然后就脑子就乱了。可能有人会觉得明摆着没有软件定时器的问题了,但如果因为软件定时器需要的两个标准函数库因为编译时找不到我就注销了呢。 各种尝试,后来将该源文件和main文件放在同一目录下,该代码就可以在回调函数里执行了,最后再一点点回溯,最后确定问题是软件定时器的回调函数用static修饰了,能想象吗span style=”color:#3399ea;”>按理说static修饰了,你直接执行不了回调函数不就好了吗不是,偏偏能执行,能执行还存在问题。会不会是编译器的问题呢程中不包含标准函数库又算怎么一回事strong>对故障现象该抱着什么样的态度,欢迎在评论区留言 话说我为什么将回调函数用static修饰呢一直在思考该怎么形成自己的代码风格,想的是外部调用的函数就在头文件中声明,没有外部调用的则将其前面加个static,然后在源文件的头部进行声明,后期阅读时方便理解实现了哪些函数,都有什么功能,修改也会提供一丝便利。最开始对于定时回调函数我是拿不定该不该用static修饰的,但后来就将其划为static修饰的了,一次教训:对于拿不定的那就想着如何不让事情向更糟的情况发展。
事故现场回顾
定时器回调函数有 设置灯闪烁 和 设置灯pwm占空比 两种, 实现灯闪烁的都正常,但是实现灯占空比的都没反应,
首先保证能正常进入回调函数,在设置灯pwm占空比的回调函数中添加了一个灯翻转来指示,灯正常闪烁,pwm设置占空比还是没反应
那问题就好说了,肯定就是设置占空比函数有问题(设置占空比函数是我调用几个底层函数封装的)
本来定时器回调函数是通过multi_timer_loop函数在main_loop主循环里链表查找,然后通过函数指针调用的,要修改验证占空比函数是否有问题就先直接放到main_loop中,确保不确定因素只有设置占空比函数,因为我偶尔留意到multi_timer是用到c99标准的函数库,我不确定找不到会不会导致软件定时器功能异常
然而,要真是这样就好了,直接将设置占空比函数放在main_loop主循环里,竟然灯有反应了,那是否占空比实际一直为0呢,将占空比直接赋值给一个全局变量方便调试查看,结果占空比也是一直变化的(病急乱投医心理,已经误入歧途了),在main_loop中写了实现相同功能的语句,灯开始呼吸了。
然后将这能实现功能的语句封装成函数,放在rgb_led源文件中,然后在main_loop中调用,还是可以
后来不知怎么想到试着将源文件放到mesh目录下的,结果软件定时器回调可以调节占空比了
我觉得问题解决了,然后告诉了上级,他说不行,有个原则是不能更改工程结构,将文件都放到那个文件夹下更改了目录结构,最后帮着找到了问题的根源:static,被外部调用的函数修饰成了内部函数
相关文章补充
值得一看,不过人家好像说的是硬件定时器。第5章 定时器执行任务 – 生命不息 折腾不止
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!