[资源共享] 《芯圣51内核单片机HC89F0xx库分享》-软定时器库

[复制链接]
 楼主| 正版长小强 发表于 2023-11-10 09:29 | 显示全部楼层 |阅读模式
本帖最后由 正版长小强 于 2023-11-11 07:40 编辑

#每日话题# #申请原创# #技术资源#
                            《芯圣51内核单片机HC89F0xx库分享》- 软定时器库
一、前言
       项目需要近期接触芯圣HC89F0xx系列51核单片机 ,超高的 性价比、灵活性 深深的吸引了我 。 为后续项目更快落地,开始做基础功能的封装库工作。
       在代码编写过程中 时间要素是关键的  ,初期往往使用阻塞式Delay 延时函数 ,慢慢的 会借用定时器 ,状态机 方式  ,几年前在51核上做一个软定时器模块,一直在用,芯圣上也可以使用 ,为项目功能验证带来极大便利 。现在分享出来  。

往期分享地址 :
《芯圣51内核单片机HC89F0xx库分享》-GPIO库
/*************************************************************************************************************************/

二、分享内容
      软件定时器工作原理 , 首先需要为软定时器提供一个 基准心跳 一般是10mS ,  这决定了定时器的计时最小单位 。心跳 可以是其他的  。软定时器 提供了一个定时器结构体 ,以及相关的 操作接口  。
     1:  声明一个软定时器      xdata new_t   sec_t;       定时器是静态的 ,声明了就如变量一般一直存在 ,占用内容 ,推荐大家在xdata 区域定义
     2:  配置定时器  new_time_create(&sec_t ,NEW_TIME_TICK_SEC,NEW_TIME_MODE_WHILE,sec_run);   
                              &sec_t :我们刚刚声明的定时器地址
                              NEW_TIME_TICK_SEC :设定定时器溢出时间 ,这个宏定义与 基准心跳有关 10mS 时值是100 ,注意定时器的计数值范围是 0 - 255 U8 类型
                              NEW_TIME_MODE_WHILE :定时器工作模式 ,默认代码 两种 持续工作 、到达时间后关闭  ,可通过修改代码实现设定次数
                              sec_run :回调函数  ,定时器到达时间后会执行这个函数 ,当前没有做参数功能 。
     3:启动定时器  new_time_cmd(&sec_t,NEW_TIME_ON);
使用过程很简单 ,需要注意 :不要重复配置定时器(没有做定时器ID 管理 ,制作了链表功能,注意就好 最小配置) 会导致定时器链表异常 ,内存溢出。
/*************************************************************************************************************************/

三、移植过程
      在主函数中 10mS 周期 new_time_run_main();   
      在中断函数中10mS 调用 new_time_run_clock();  
      注意不要在中断函数中调用new_time_run_main();  会让定时周期不可控, 如果你对定时器时间要求很低 可以把这两个函数都放在 主函数 10mS 变量盘内。
      例:
      bit   t_10ms_flag = 0;
      void Timer1_ISR (void) interrupt TIMER1_VECTOR        
     {
        
            TL1 = TL1_VALUE;
            TH1 = TH1_VALUE;
        #ifdef  USER_NEW_TIME
                    new_time_run_clock();
        #endif                  
     }
         //主函数 while(1) 循环内
                if(t_10ms_flag == 1)                //10MS 心跳标志
                {
                    #ifdef  USER_NEW_TIME
                            new_time_run_main();
                   #endif
                        t_10ms_flag = 0;
                }

如果不出意外 :就可以开心的使用软定时器了 ,如果你内存允许 ,可以开很多软定时器  。
/*************************************************************************************************************************/

四、定时器数据机构 、宏定义
struct   new_time
{
        unsigned char                  settime;     //设定时间
        unsigned char                  contr;        //当前时间               
        unsigned char                   mode:1;        //模式                                                        
        unsigned char            on_off:1;        //开关               
        unsigned char            oveflag:1;        //溢出标志        
        void                                   (*run)(void);        //回调函数
        struct                           new_time  *up_p;     //链表
        struct                           new_time  *down_p;
};
typedef  struct   new_time   new_t;


#define   NEW_TIME_TICK_SEC  (100)  //定时器每秒最大定时次数

#define   NEW_TIME_ON                        1          //定时器状态打开
#define   NEW_TIME_OFF                        0        //定时器状态关闭

#define   NEW_TIME_MODE_WHILE        0         //定时器循环触发模式        
#define   NEW_TIME_MODE_ONE                1         //定时器触发一次后处于关闭状态        


/*************************************************************************************************************************/
五、源码分享
  1. #ifdef  USER_NEW_TIME       
  2. struct   new_time
  3. {
  4.         unsigned char                  settime;
  5.         unsigned char                  contr;               
  6.         unsigned char           mode:1;                                                               
  7.         unsigned char            on_off:1;                       
  8.         unsigned char            oveflag:1;               
  9.         void                                   (*run)(void);       
  10.         struct                           new_time  *up_p;
  11.         struct                           new_time  *down_p;
  12. };
  13. typedef  struct   new_time   new_t;


  14. #define   NEW_TIME_TICK_SEC  (100)  //定时器每秒最大定时次数

  15. #define   NEW_TIME_ON                        1          //定时器状态打开
  16. #define   NEW_TIME_OFF                        0        //定时器状态关闭

  17. #define   NEW_TIME_MODE_WHILE        0         //定时器循环触发模式       
  18. #define   NEW_TIME_MODE_ONE                1         //定时器触发一次后处于关闭状态       

  19. /*
  20.         函数功能:创建一个软定时器
  21.         参数:*nt定时器结构,settime 定时时间10ms最小单位 ,mode 模式,(*run)定时器到达时间要运行的函数
  22.         返回:无
  23. */
  24. extern void    new_time_create(new_t     *nt,unsigned char settime,unsigned char mode,void   (*run)(void));
  25. /*
  26.         函数功能:控制某个定时器状态
  27.         参数:*nt定时器结构,off_on 定时器状态
  28.         返回:无
  29.         副作用:无
  30. */
  31. extern void    new_time_cmd(new_t     *nt,unsigned char off_on);

  32. /*
  33.         函数功能:修改定时器周期
  34.         参数:*nt定时器结构,settime 定时时间10ms最小单位
  35.         返回:无
  36. */
  37. extern void   new_time_set(new_t     *nt,unsigned short settime);
  38. /*
  39.         函数功能:清空定时器计时值
  40.         参数:*nt定时器结构
  41.         返回:无
  42. */
  43. extern void   new_time_reset(new_t     *nt);
  44. /*
  45.         函数功能:删除这个定时器检查任务
  46.         参数:*nt定时器结构
  47.         返回:无
  48. */
  49. /*
  50. extern void   new_time_delete(new_t     *nt);
  51. */
  52. /*
  53.         函数功能:查询计时结束的定时器并执行指向函数
  54.         参数:无
  55.         返回:无
  56.         循环调用  
  57. */
  58. extern   void   new_time_run_main(void);


  59. #endif
  1. #ifdef  USER_NEW_TIME
  2. xdata unsigned  char  new_time_num=0;
  3. xdata new_t  *new_time_p = 0;                //最后定时器的地址

  4. xdata new_t  *new_time_C_p = 0;                //最后定时器的地址
  5. xdata new_t  *new_time_R_p = 0;                //最后定时器的地址
  6. xdata new_t  *new_time_S_p = 0;                //最后定时器的地址

  7. //new_t
  8. //定时器创建
  9. void    new_time_create(new_t     *nt,unsigned char settime,unsigned char mode,void   (*run)(void))
  10. {
  11.                 memset(nt,0,sizeof(struct   new_time));
  12.         //        if(up_t->down_p == 0)
  13.                 {
  14.                         nt->contr = 0;
  15.                         nt->mode = mode;
  16.                         nt->settime  = settime;
  17.                         nt->run = run;
  18.                         if(new_time_num ==0)
  19.                         {
  20.                                 nt->up_p = nt;
  21.                 nt->down_p = nt;
  22.                 new_time_C_p = nt;
  23.                 new_time_R_p = nt;
  24.                                 new_time_S_p = nt;
  25.                         }
  26.                                 else
  27.                                 {   
  28.                                         nt->down_p = new_time_p;
  29.                     nt->up_p = new_time_p->up_p;
  30.                     new_time_p->up_p = nt;
  31.                                 }
  32.                         new_time_p = nt;
  33.                         new_time_num++;       
  34.                         new_time_S_p->down_p = nt;
  35.                 }
  36.                
  37. }
  38. //设定定时器
  39. void   new_time_set(new_t     *nt,unsigned short settime)
  40. {
  41.         nt->settime  = settime;
  42.         nt->contr = 0;
  43.        
  44. }
  45. //删除定时器
  46. /*
  47. void   new_time_delete(new_t     *nt)
  48. {
  49. xdata        new_t     *up_t_p = (new_t     *)nt->up_p;                //上一个定时器
  50. xdata        new_t     *up_t_d = (new_t     *)nt->down_p;        //下一个定时器
  51.         unsigned   char    dflag =0;
  52.         if((up_t_p ==0 )&&(up_t_d == 0))return;
  53.         if( new_time_num > 1)                        //已经创建定时器
  54.         {
  55.                 if(up_t_p!=0)                //如果上一个定时器存在
  56.                 {
  57.                         if(up_t_d!=0)up_t_p->down_p = nt->down_p;//如果下边存在定时器把下链表地址改为此地址
  58.                                 else {up_t_p->down_p =0; new_time_p = (new_t  *)up_t_p;}        //如果下面没有定时器了把最后定时器的指针改为上一个定时器
  59.                         dflag =1;                //定时器数量减
  60.                 }
  61.                         else
  62.                         {
  63.                                 up_t_d->up_p = 0;
  64.                                 dflag =1;
  65.                         }
  66.                 if(up_t_d!=0)//如果下一个定时器存在
  67.                 {
  68.                                 if(up_t_p!=0)up_t_d->up_p = nt->up_p;
  69.                                         else up_t_d->up_p = 0;
  70.                                 dflag =1;
  71.                 }
  72.                 if(dflag)new_time_num  --;
  73.                
  74.         }
  75.         else if( new_time_num == 1)
  76.         {
  77.                  new_time_num = 0;         //定时器数量清空
  78.                  new_time_p = 0;                //指针链表清零
  79.         }
  80.         m_memset((unsigned char *)nt,0,sizeof(new_t));
  81. }
  82. */
  83. //定时器计时器值初始值
  84. void   new_time_reset(new_t     *nt)
  85. {
  86.         nt->contr = 0;
  87. }

  88. //打开或者关闭定时器
  89. void    new_time_cmd(new_t     *nt,unsigned char off_on)
  90. {
  91. //        if(nt->on_off != off_on)       
  92.      {   nt->on_off = off_on; }   
  93. }
  94. // 定时器溢出运行函数
  95. void   new_time_run_main(void)
  96. {
  97.                 while(new_time_R_p)                //定时器是否已经结束
  98.                 {
  99.                                 if(new_time_R_p->oveflag != 0)
  100.                                 {
  101.                                                 new_time_R_p->oveflag = 0 ;
  102.                                                 new_time_R_p->run();               
  103.                                 }
  104.                                 new_time_R_p = new_time_R_p->down_p;
  105.                                 if(new_time_R_p == new_time_S_p) break;
  106.                 }
  107. }
  108. // 定时器运行
  109. static void   new_time_one_run(new_t     *nt)
  110. {
  111.                 if(nt->on_off == NEW_TIME_ON)
  112.                 {
  113.                         nt->contr ++;
  114.                         if(nt->contr>= nt->settime)
  115.                         {
  116.                                
  117.                                 if(nt->mode == NEW_TIME_MODE_ONE)
  118.                                 {
  119.                                         nt->on_off = NEW_TIME_OFF;
  120.                                 }
  121. //                                if(nt->mode > 0)  //适配指定定时溢出次数
  122. //                                {
  123. //                                        nt->mode -- ;
  124. //                                        if(nt->mode == 0)
  125. //                                        {nt->on_off = NEW_TIME_OFF;}
  126. //                                }
  127.                                 nt->contr = 0;                //计时器清零
  128.                                 nt->oveflag = 1;        //溢出
  129.                         }
  130.                 }
  131. }
  132. //定时器心跳
  133. void   new_time_run_clock(void)
  134. {
  135.                 while(new_time_C_p)                //定时器是否已经结束
  136.                 {
  137.                                 new_time_one_run(new_time_C_p);
  138.                                 new_time_C_p = new_time_C_p->down_p;
  139.                                 if(new_time_C_p == new_time_S_p) break;
  140.                 }
  141. }
  142. #endif


目前在 芯圣上还属于验证阶段 大家踊跃 尝试 。


评论

@flybluefox  发表于 2023-11-10 09:31
@芯圣电子官方QQ  发表于 2023-11-10 09:30
@21小跑堂  发表于 2023-11-10 09:30
 楼主| 正版长小强 发表于 2023-11-10 09:49 | 显示全部楼层
创建 两个定时器 通过串口发送内容
微信图片_20231110094557.png
微信图片_20231110094606.png
weifeng90 发表于 2023-11-13 07:40 来自手机 | 显示全部楼层
软定时器的驱动源来源于硬件定时器。
 楼主| 正版长小强 发表于 2023-11-13 11:02 | 显示全部楼层
weifeng90 发表于 2023-11-13 07:40
软定时器的驱动源来源于硬件定时器。

我理解是的 ,需要提供 时钟源,才能实现
tpgf 发表于 2023-12-4 12:51 | 显示全部楼层
和软定时器库对应的有硬定时器库吗
drer 发表于 2023-12-4 16:47 | 显示全部楼层
这个软件定时器的最小计时精度是多少啊
coshi 发表于 2023-12-4 20:59 | 显示全部楼层
软定时器的时钟源可以选择什么呢
qcliu 发表于 2023-12-4 21:30 | 显示全部楼层
这个软定时器库可以由用户进行修改吗
kxsi 发表于 2023-12-5 08:49 | 显示全部楼层
可以在库里边为定时器选择时钟源吗
wiba 发表于 2023-12-5 10:01 | 显示全部楼层
软定时器和我们常说的定时器不是一个部件吗

评论

软定时器特点 :依赖硬件定时器,消耗内存 ,内存满足没有数量限制 ,定时实时性低于硬件定时器。  发表于 2023-12-8 08:06
 楼主| 正版长小强 发表于 2023-12-8 08:04 | 显示全部楼层
coshi 发表于 2023-12-4 20:59
软定时器的时钟源可以选择什么呢

目前会依赖一个硬件定时器,不像ARM有 嘀嗒定时器,芯圣目前产生定时器中断功能有多中方法,都可以实现
 楼主| 正版长小强 发表于 2023-12-8 08:07 | 显示全部楼层
qcliu 发表于 2023-12-4 21:30
这个软定时器库可以由用户进行修改吗

可以的 ,很简单就是分享这些,没有做过多的 处理,提供最基本的 计时、回调、链表
 楼主| 正版长小强 发表于 2023-12-8 08:09 | 显示全部楼层
drer 发表于 2023-12-4 16:47
这个软件定时器的最小计时精度是多少啊

默认10ms,如果想低于1ms,建议直接硬件定时器 ,它功能侧重于解决 10ms 以上的 大时段 ,流程性功能程序时间管理
 楼主| 正版长小强 发表于 2023-12-8 08:10 | 显示全部楼层
tpgf 发表于 2023-12-4 12:51
和软定时器库对应的有硬定时器库吗

项目上对这方面的需求不是很高,用到的话会出一个
chenjun89 发表于 2023-12-8 20:53 来自手机 | 显示全部楼层
软件定时器很实用,用一个硬件定时器源可以实现很多定时器。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

60

主题

194

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部