文章目录

  • 1.网红软件定时器MultiTimer
    • 1.1 MultiTimer 简介
    • 1.2 准备工作
    • 1.3 MultiTimer 使用
      • 1.3.1 新建工程
      • 1.3.2 修改主函数
      • 1.3.3 增加串口打印功能
    • 1.4 MultiTimer功能测试
    • 1.5 MultiTimer借鉴
  • 2.个人常用软件定时器
    • 2.1 个人常用软件定时器介绍
    • 2.2 功能测试
  • 3.例程分享

在开发嵌入式软件时,定时器是必不可少的,或用于实时系统的心跳、延时,或用于裸机系统中的周期性任务等。因为硬件定时器资源有限,并且还有可能用于PWM,输入捕获等功能,所以更多的人会基于一个硬件定时器实现多个软件定时器,用于对时间精度要求没那么高的场合,如发送周期性CAN报文,定时采集传感器信号等。本文基于S32K144平台介绍笔者常用的两种软件定时器,希望对读者有用。

1.网红软件定时器MultiTimer

1.1 MultiTimer 简介

MultiTimer是最近比较火的一个开源项目,作者为0x1abin,github地址为:GitHub - 0x1abin/MultiTimer at master,遵循MIT开源许可协议,目前已收获502 stars。

MultiTimer是一个软件定时器扩展模块,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。

1.2 准备工作

  • S32K144EVB-Q100
  • S32DS For ARM 2.2
  • PC端的串口调试部助手

1.3 MultiTimer 使用

MultiTimer的README文档对于如何使用MultiTimer介绍的非常详细。本文基于S32K144平台并参考README文档介绍如何使用MultiTimer。

1.3.1 新建工程

  1. 选择从例程中新建工程,如下图:
  2. 选择lpit_periodic_interrupt_s32k144的例程,并重命名为lpit_multitimer_s32k144,如下图,点击Finish:
  3. 配置lpit组件,设置定时器周期为1ms,并使能中断,如下图:
  4. multi_timer.cmulti_timer.h复制到工程所在的文件夹,并按F5刷新一下,就能在工程树看到了,如下图所示(串口打印相关的文件后面再介绍):
  5. 确认multi_timer.h中设置的tick值,如下图:
/*
It means 1 tick for 1ms.
Your can configurate for your tick time such as 5ms/10ms and so on.
*/
#define CFG_TIMER_1_TICK_N_MS   1

源代码此处的注释有误,如果想要tick为5ms,宏定义改为5是不行的,需要将硬件定时器的中断周期改为5ms。如果此处改为5,会导致软件定时器的超时时间变为原来的1/5。

1.3.2 修改主函数

  1. 首先在main.c中包含multi_timer.h,并创建两个软件定时器,如下:
#include "multi_timer.h"/* 创建两个软件定时器 */
struct Timer timer1;
struct Timer timer2;
  1. 然后对两个软件定时器进行初始化并启动,如下:
    /* 软件定时器初始化*/timer_init(&timer1, timer1_callback, 1000, 2000, NULL); //1s looptimer_start(&timer1);timer_init(&timer2, timer2_callback, 50, 0, NULL); //50ms delaytimer_start(&timer2);printf("timer start!\r\n");

timer_init函数的定义如下,其中第三个函数表示第一次的超时时间,第四个参数表示第2次到第N次的超时时间。第4个参数如果为0,那么该软件定时器只发生一次超时,对应的回调函数也只执行一次。

void timer_init(struct Timer* handle, void (*timeout_cb)(void *arg), uint32_t timeout, uint32_t repeat, void *arg)
  1. 接着在1ms的硬件定时器中断里调用timer_ticks(),如下:
/*!* @brief: LPIT interrupt handler.*         When an interrupt occurs clear channel flag and toggle LED0*/
void LPIT_ISR(void)
{/* Clear LPIT channel flag */LPIT_DRV_ClearInterruptFlagTimerChannels(INST_LPIT1, (1 << LPIT_CHANNEL));/* 软件定时器的ticks,此处为1ms*/timer_ticks();
}
  1. 最后实现两个软件定时器的回调函数,注意不能有耗时过长的操作,如下:
/* 每个软件定时器的回调函数,不能在回调函数做耗时操作,否则会导致其他定时器无法正常超时 */
void timer1_callback(void *arg)
{/* Toggle LED0 */PINS_DRV_TogglePins(LED_GPIO_PORT, (1 << LED0_PIN_INDEX));printf("timer1 timeout! arg: %p\r\n", arg);
}void timer2_callback(void *arg)
{printf("timer2 timeout! arg: %p\r\n", arg);
}

1.3.3 增加串口打印功能

  1. 首先在工程中增加lpuart组件,在组件库中找到lpuart,双击即可添加,如下图:
  2. 然后点击添加到工程的lpuart组件,选择lpuart1,波特率设为115200,如下:
  3. 配置下lpuart对应的pin脚,RX选择PTC6,TX选择PTC7,如下:
  4. 工程中需要增加四个文件,如下所示:

    其中,printf.c,uart_console_io.c,uart.h在S32DS For ARM 2.2安装目录下,uart.c需要自己编写。
  • printf.c地址如下:
  • uart_console_io.c地址如下:
  • uart.h地址如下:
  • uart.c需要自己实现如下四个函数
#include "uart.h"
#include "lpuart1.h"
UARTError InitializeUART(UARTBaudRate baudRate)
{//lpuart1_InitConfig0.baudRate = baudRate;/* Initialize LPUART instance */LPUART_DRV_Init(INST_LPUART1, &lpuart1_State, &lpuart1_InitConfig0);return kUARTNoError;
}UARTError ReadUARTPoll(char* c)
{UARTError err = kUARTNoError;err = LPUART_DRV_ReceiveDataBlocking(INST_LPUART1, (uint8_t *)c, 1, 1000);return err;
}UARTError ReadUARTN(void* bytes, unsigned long length)
{UARTError err = kUARTNoError;err = LPUART_DRV_ReceiveDataBlocking(INST_LPUART1, (uint8_t *)bytes, length, 1000);return err;
}UARTError WriteUARTN(const void* bytes, unsigned long length)
{UARTError err = kUARTNoError;uint32_t bytesRemaining;err = LPUART_DRV_SendData(INST_LPUART1, (const uint8_t *const)bytes, length);/* Wait for transfer to be completed */while(LPUART_DRV_GetTransmitStatus(INST_LPUART1, &bytesRemaining) != STATUS_SUCCESS);return err;
}
  1. 工程的属性中的库需要更改为ewl_c no I/O
  2. 工程属性中的linker的库需要全部删除,否则编译时会发生错误
  3. 在main.c中包含stdio.h之后,就可以调用printf函数在串口打印信息了。

1.4 MultiTimer功能测试

将程序下载到S32K144EVB中,在串口助手打印的信息如下:

从打印信号可以看出,各个定时器的运行符合预期。

1.5 MultiTimer借鉴

MultiTimer使用了单链表操作,且代码量不大,可以借鉴该项目学习单链表。网络上对该项目的解读文章非常多,笔者推荐阅读如下这个:

MultiTimer | 一款可无限扩展的软件定时器

2.个人常用软件定时器

除了网红定时器MultiTimer,笔者再推荐一个自己经常使用的软件定时器。

2.1 个人常用软件定时器介绍

  1. 需要将上一章节的工程中的multi_timer.cmulti_timer.h换成自己编写的soft_timer.csoft_timer.h,工程树如下:
  2. soft_timer.h主要定义定时器相关的枚举和结构体,如下所示:
typedef enum
{TIMER1,TIMER2,VTIMER_NUM,
} VtimerName_t;typedef struct
{unsigned char  enable;unsigned int     msec;
} Vtimer_t,*PVtimer;
  1. soft_timer.c主要实现定时器的初始化,启动,判断以及心跳函数等,如下所示:
Vtimer_t sVtimer[VTIMER_NUM];void vtimer_Init()
{unsigned char i;for (i=0; i<VTIMER_NUM; i++){sVtimer[i].msec = 0;sVtimer[i].enable = false;}vtimer_SetTimer(TIMER1, TIMER1_PERIOD);vtimer_SetTimer(TIMER2, TIMER2_PERIOD);
}void vtimer_SetTimer(VtimerName_t name, unsigned int msec)
{if(false == sVtimer[name].enable){sVtimer[name].msec = msec;sVtimer[name].enable = true;}
}
bool vtimer_TimerElapsed(VtimerName_t name)
{if((sVtimer[name].msec == 0) && (sVtimer[name].enable == true)){sVtimer[name].enable = false;return true;}else{return false;}
}void vtimer_UpdateHandler(void)
{/*Enter each 1ms*/unsigned char i;for (i=0; i<VTIMER_NUM; i++){if (sVtimer[i].msec && (sVtimer[i].enable == true)){sVtimer[i].msec--;    }else{sVtimer[i].msec = 0;}}
}
  1. main.c中在硬件定时器中断中调用心跳函数,如下所示:
/*!* @brief: LPIT interrupt handler.*         When an interrupt occurs clear channel flag and toggle LED0*/
void LPIT_ISR(void)
{/* Clear LPIT channel flag */LPIT_DRV_ClearInterruptFlagTimerChannels(INST_LPIT1, (1 << LPIT_CHANNEL));/* 软件定时器的ticks,此处为1ms*/vtimer_UpdateHandler();
}
  1. 在main函数中调用初始化函数和判断函数,如下所示:
/* 软件定时器初始化*/
vtimer_Init();
printf("timer start!\r\n");while(1)
{if(vtimer_TimerElapsed(TIMER1) == true){vtimer_SetTimer(TIMER1, TIMER1_PERIOD);/* Toggle LED0 */PINS_DRV_TogglePins(LED_GPIO_PORT, (1 << LED0_PIN_INDEX));printf("timer1 timeout!\r\n");}if(vtimer_TimerElapsed(TIMER2) == true){vtimer_SetTimer(TIMER2, TIMER2_PERIOD);printf("timer2 timeout!\r\n");}
}

2.2 功能测试

将程序下载到S32K144EVB,串口助手打印信息如下:

打印信息符合预期。

3.例程分享

本文使用的两个例程已上传百度网盘,分享如下:

  • 链接:https://pan.baidu.com/s/1u6ja9roGR8_Krg7YrMpOsQ
  • 提取码:yrlw

如果觉得本文对你有用,不妨给个一键三连!!!

基于S32K144平台实现两种软件定时器相关推荐

  1. COS云存储有哪些优势?基于EasyCVR平台的两种监控视频数据存储方案

    随着物联网.AI.云计算.大数据等新兴技术的发展.海量设备的接入.视频质量的不断提升,监控视频存储也面临着巨大的挑战.当前用户对视频监控数据的存储问题,主要考虑到以下三个因素: 1)数据的安全性和稳定 ...

  2. matlab迭代求解,[基于matlab平台的三种迭代法求解矩阵方程]matlab迭代法求方程的根...

     数值分析第二次作业 学院:电子工程学院 基于matlab平台的三种迭代法求解矩阵方程组 求解系数矩阵由16阶Hilbert方程组构成的线性方程组的解,其中右端项为[2877/851,3491/14 ...

  3. Leetcode刷题 225题:用队列实现栈(基于Java和c++两种语言)

    ** Leetcode刷题 225题:用队列实现栈(基于Java和c++两种语言) ** 题目: 使用队列实现栈的下列操作: push(x) – 元素 x 入栈 pop() – 移除栈顶元素 top( ...

  4. Leetcode刷题 232题:用栈实现队列(基于python3和c++两种语言)

    Leetcode刷题 232题:用栈实现队列(基于python3和c++两种语言) 题目: 使用栈实现队列的下列操作: push(x) – 将一个元素放入队列的尾部. pop() – 从队列首部移除元 ...

  5. Leetcode刷题 155题: 最小栈(基于python3和c++两种语言)

    ** Leetcode刷题 155题: 最小栈(基于python3和c++两种语言) ** ** 题目: ** 设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈. ...

  6. Leetcode刷题 1441题: 用栈操作构建数组(基于python3和c++两种语言)

    Leetcode刷题 1441题: 用栈操作构建数组(基于python3和c++两种语言) ** 题目: ** 给你一个目标数组 target 和一个整数 n.每次迭代,需要从 list = {1,2 ...

  7. 认清SQL_Server_2005的基于行版本控制的两种隔离级别

    --认清SQL_Server_2005的基于行版本控制的两种隔离级别 --By:zc_0101  Date:2010-03-31 --快照隔离级别(snapshot)和已提交读快照隔离级别(read  ...

  8. 微信公众号服务器模式,微信公众平台的两种模式

    微信公众平台的两种模式,只有清楚了解了微信公众平台的两种模式,才能更好的实现自己想要的开发效果. 微信公众平台的高级模式中有两种模式:编辑模式和开发模式.这两种模式的运营思路完全不同.编辑模式基本围绕 ...

  9. vue中基于echarts和基于高德地图的两种地图下钻与上浮方式

    ** vue中基于echarts和基于高德地图的两种地图下钻与上浮方式 ** 基于echarts的地图下钻与上浮(浙江省为例) 第一步:在<template>中构建承载echarts的do ...

最新文章

  1. [算法]华为笔试题——拼音与英文转换
  2. python开发网页视频播放器_HTML5 VideoAPI,打造自己的Web视频播放器
  3. input ios问题
  4. Qt Creator怎样更改默认构建目录
  5. 如何使用EditPlus3编写汇编语言
  6. mysql表锁ix_S、X、IS、IX数据库锁机制 很详细的教程,简单易懂
  7. spring boot 2 整合 j2Cache
  8. 日版IPhone5完美上3G
  9. rpmbuild php,linux RPM打包时出错,求助!!!
  10. oracle查看表空间物理路径,oracle查看表空间物理文件的名称,路径及大小
  11. 《Wasserstein GAN》继续 GAN
  12. git 修改远端 commit 信息
  13. 【编程不良人】快速入门SpringBoot学习笔记06---RestFul、异常处理、CORS跨域、Jasypt加密
  14. 白杨SEO:小红书关键词搜索量怎么查?小红书关键词搜索长尾下拉词如何深处挖掘?
  15. 微信小程序底部弹窗(半屏弹窗)---WeUI组件使用
  16. linux 解压缩压缩文件(zip、rar、7z、tar)
  17. 用JAVA实现简单的WORD转PDF 亲测有效
  18. php显示文件内容,php读取文件内容_PHP读取文件内容并输出显示
  19. 《动手学深度学习》Task09:目标检测基础+图像风格迁移+图像分类案例1
  20. ubuntu 1604 ppa.launchpad.net下载速度慢

热门文章

  1. Linux网络收音机
  2. 林仕鼎谈数据中心计算(二):存储资源分层
  3. SIM卡的ICCID、IMSI
  4. 一站式移动办公SaaS将成为未来企业管理平台的最佳选择
  5. 快速将百度排名做到首页的方法
  6. FDTD add语句部分详细内容
  7. 脚本一键部署 (DHCP、dns、pxe、raid、nfs+apache+expect、lvm、磁盘分区、监控资源)
  8. 电子设备必须通过电磁兼容试验
  9. 小米网关+HomeAssistant获取智能硬件数据
  10. pymongo查询列表元素_pymongo的数组操作