专家
公告
财富商城
电子网
旗下网站
首页
问题库
专栏
标签库
话题
专家
NEW
门户
发布
提问题
发文章
STM32
[代码分享]一个简单好用的轮询延时器模块
2019-12-16 22:38
发布
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
站内问答
/
STM32/STM8
5142
38
39
本帖最后由 Jmhh247 于 2017-5-23 10:08 编辑
关键字:延时器;非阻塞自由延时
在一些按键或其它形式的命令响应中,要求严格的话通常会需要队列缓存命令,以防丢失。
但是我通常还会遇到一些要求非常不严格的场景,这些场景甚至要限制响应的次数或频率(这里指不能响应太快)。
比如(只是个例子),我的产品是一个根据接收到的串口命令来工作的。串口命令发送的速度是不确定的,有时候1秒
会发送10帧命令过来,有的时候1秒确能发送100帧,但是这个产品每秒只打算处理20帧命令。而且由于命令有多个,
对于有些命令码可能每秒响应40帧或30帧等,这种场景用多个延时器就很合适了。
延时器模块的接口函数一共3个,如下:
/* Exported functions ------------------------------------------------------- */
bool zl_poll_delay_set(uint8_t chUserId, uint16_t hwTime);
bool zl_poll_delay_timeout(uint8_t chUserId);
void zl_poll_delay_tick(void);
复制代码
看下接口函数的实现,很简单的
/* Z L _ P O L L _ D E L A Y _ S E T */
/*-------------------------------------------------------------------------
功能描述 : 设定延时时间,同时启动延时。
输入参数 : uint8_t chUserId 延时器ID
uint16_t hwTime 延时时间
输出参数 : 无
返 回 值 :
修改历史
1.日 期 : 2017年2月6日
作 者 : zys
修改内容 : 新生成函数,OK。
-------------------------------------------------------------------------*/
bool zl_poll_delay_set(uint8_t chUserId, uint16_t hwTime)
{
if (chUserId >= ZL_POLL_DELAY_NUM) {
return false;
}
if (0 == hwTime) {
return false;
}
s_tPollBuf[chUserId].Time = hwTime;
return true;
}
/* Z L _ P O L L _ D E L A Y _ T I M E O U T */
/*-------------------------------------------------------------------------
功能描述 : 查询给定ID的延时器是否超时。
输入参数 : uint8_t chUserId
输出参数 : 无
返 回 值 : true 超时;false 未超时。
修改历史
1.日 期 : 2017年5月22日
作 者 : zys
修改内容 : 新生成函数。
-------------------------------------------------------------------------*/
bool zl_poll_delay_timeout(uint8_t chUserId)
{
if (chUserId >= ZL_POLL_DELAY_NUM) {
return false;
}
if ( !s_tPollBuf[chUserId].Time) {
return true;
}
return false;
}
/* Z L _ P O L L _ D E L A Y _ T I C K */
/*-------------------------------------------------------------------------
功能描述 : 延时模块的驱动任务,在心跳中断里运行。
输入参数 : void
输出参数 : 无
返 回 值 :
修改历史
1.日 期 : 2017年5月22日
作 者 : zys
修改内容 : 新生成函数。
-------------------------------------------------------------------------*/
void zl_poll_delay_tick(void)
{
uint8_t i;
for ( i = 0 ; i < ZL_POLL_DELAY_NUM; i++ ) {
if (s_tPollBuf[i].Time) {
s_tPollBuf[i].Time--;
}
}
}
复制代码
模块的使用
使用很简单,首先把模块源文件添加到工程中,然后把
void zl_poll_delay_tick(void)
复制代码
放到心跳中断里,我一般用1ms的心跳中断。
现在就能使用
bool zl_poll_delay_set(uint8_t chUserId, uint16_t hwTime)
复制代码
来设置延时器了,入参分别是延时器的ID和延时时间,延时时间单位和心跳中断有关,看自己需求了。。。
然后用
bool zl_poll_delay_timeout(uint8_t chUserId)
复制代码
来查询延时器是否超时,入参是要查询的延时器ID号。
延时器的可用最大数量通过宏定义配置
/* 定义可用的延时数量 */
#define ZL_POLL_DELAY_NUM 5
复制代码
模拟一个应用场景演示代码
/* 定义延时器信息,便于阅读修改 */
#define DELAY_ID0 0
#define DELAY_TIME0 50
#define DELAY_ID1 1
#define DELAY_TIME1 900
/* 模拟一个应用场景 */
void xxx_cmd_process(uint8_t chCmd)
{
switch (chCmd) {
case CMD_LEFT:
/* 该命令执行间隔不能小于50ms */
if (zl_poll_delay_timeout(DELAY_ID0)) {
zl_poll_delay_set(DELAY_ID0, DELAY_TIME0);
cmd_do_left();
}
break;
case CMD_RIGHT:
/* 该命令执行间隔不能小于900ms */
if (zl_poll_delay_timeout(DELAY_ID1)) {
zl_poll_delay_set(DELAY_ID1, DELAY_TIME1);
cmd_do_left();
}
break;
case CMD_UP:
/* 该命令无限制,来就执行 */
cmd_do_up();
break;
case CMD_DOWN:
break;
default:
break;
}
}
/* 在1ms心跳(时基)中断里运行 */
void st_systick_1ms_irq(void)
{
zl_poll_delay_tick()
}
复制代码
延时器的用处还有很多,可以灵活。。。
zlib poll delay模块源码.rar
(2.02 KB, 下载次数: 108)
2017-5-23 10:07 上传 点击文件名下载附件
友情提示:
此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
38条回答
airwolf09921
1楼-- · 2019-12-18 11:09
精彩回答 2 元偷偷看……
加载中...
miscell
2楼-- · 2019-12-18 15:47
如果没启动,其计数值也为0,不是返回成功的吗
加载中...
Jmhh247
3楼-- · 2019-12-18 19:39
miscell 发表于 2017-5-25 22:54
如果没启动,其计数值也为0,不是返回成功的吗
是的,就是这样设计的。因为上电后是第一次执行,所以有没有延时,结果都是一样的。
所以,在我写的用例中,都是先查询,超时后再设定延时的
/* 该命令执行间隔不能小于900ms */
if (zl_poll_delay_timeout(DELAY_ID1)) {
zl_poll_delay_set(DELAY_ID1, DELAY_TIME1);
cmd_do_left();
}
复制代码
加载中...
fm007
4楼-- · 2019-12-19 00:28
感谢楼主分享,我目前也使用过这种思路的,但是用的是离散的结构体标志
加载中...
istars2005
5楼-- · 2019-12-19 01:41
本帖最后由 istars2005 于 2017-7-19 21:37 编辑
楼主的方式貌似有点繁琐
vu32 *gTimOut[TM_OUT_CNT] = {0}; // 超时计数变量指针数组
static u8 tm_Out_Cnt = 0; // 实际超时变量个数
复制代码
/**
* 函数功能: 配置超时指针
* 输入参数: *ptout 需要传入的超时变量指针
* 输出参数: 配置结果 0:成功 -1:索引溢出 1:超时指针重复(不影响正常结果)
* 功能说明: 修改原来实现方式的bug,不再使用idx变量
当超过最大允许的超时变量个数时返回-1
*/
s8 TimeOutSet(vu32 *ptout)
{
if(tm_Out_Cnt >= TM_OUT_CNT)
return -1;
for(int i=0;i<tm_Out_Cnt;i++) {
if(ptout == gTimOut[i])
return 1;
}
gTimOut[tm_Out_Cnt] = ptout;
tm_Out_Cnt++;
return 0;
}
复制代码
在系统滴答定时器中调用如下代码
int i=0;
while(i<tm_Out_Cnt) { // 扫描超时变量,并且把不为0的变量进行自减一
*gTimOut[i] ? (*gTimOut[i])-- : 0;
i++;
}
复制代码
使用方法
vu32 _gTimeOut1 = 0; // 全局变量
TimeOutSet(&_gTimeOut1 ); // 超时变量注册,最好注册一次,重复注册也可以使用,但是稍浪费一点时间
//正式使用
if(_gTimeOut1 == 0) {
_gTimeOut1 = 50;
// DoSomeThing();
}
复制代码
加载中...
jssd
6楼-- · 2019-12-19 02:07
精彩回答 2 元偷偷看……
加载中...
上一页
1
2
3
4
5
6
7
下一页
一周热门
更多
>
相关问题
STM32F4上I2C(在PROTEUS中模拟)调试不通的问题
6 个回答
芯片供应紧张,准备换个MCU,MM32L系列替换STM32L系列的怎么样?
7 个回答
STM32同时使用两个串口进行数据收发时数据丢包的问题
5 个回答
STM32F103串口通信死机问题
4 个回答
STM32WLE5CC连接SX1268在LoRa模式下能与 SX1278互通吗?
2 个回答
STM32开发板免费用活动
7 个回答
stm32 处理 DHT11占用太多时间,大家程序是怎么设计的
8 个回答
分享一个STM32单片机做的离线编程器代码
9 个回答
相关文章
ST公司第一款无线低功耗单片机模块有效提高物联网设计生产效率
0个评论
如何实现对单片机寄存器的访问
0个评论
通过USB用STM32片内自带Bootloader下载程序及注意事项
0个评论
欲练此功必先自宫之STM32汇编启动,放慢是为了更好的前行
0个评论
×
关闭
采纳回答
向帮助了您的网友说句感谢的话吧!
非常感谢!
确 认
×
关闭
编辑标签
最多设置5个标签!
STM32
保存
关闭
×
关闭
举报内容
检举类型
检举内容
检举用户
检举原因
广告推广
恶意灌水
回答内容与提问无关
抄袭答案
其他
检举说明(必填)
提交
关闭
×
关闭
您已邀请
15
人回答
查看邀请
擅长该话题的人
回答过该话题的人
我关注的人
是的,就是这样设计的。因为上电后是第一次执行,所以有没有延时,结果都是一样的。
所以,在我写的用例中,都是先查询,超时后再设定延时的
- /* 该命令执行间隔不能小于900ms */
- if (zl_poll_delay_timeout(DELAY_ID1)) {
- zl_poll_delay_set(DELAY_ID1, DELAY_TIME1);
- cmd_do_left();
- }
复制代码楼主的方式貌似有点繁琐
- vu32 *gTimOut[TM_OUT_CNT] = {0}; // 超时计数变量指针数组
- static u8 tm_Out_Cnt = 0; // 实际超时变量个数
复制代码
- /**
- * 函数功能: 配置超时指针
- * 输入参数: *ptout 需要传入的超时变量指针
- * 输出参数: 配置结果 0:成功 -1:索引溢出 1:超时指针重复(不影响正常结果)
- * 功能说明: 修改原来实现方式的bug,不再使用idx变量
- 当超过最大允许的超时变量个数时返回-1
- */
- s8 TimeOutSet(vu32 *ptout)
- {
- if(tm_Out_Cnt >= TM_OUT_CNT)
- return -1;
- for(int i=0;i<tm_Out_Cnt;i++) {
- if(ptout == gTimOut[i])
- return 1;
- }
- gTimOut[tm_Out_Cnt] = ptout;
- tm_Out_Cnt++;
- return 0;
- }
复制代码在系统滴答定时器中调用如下代码
- int i=0;
- while(i<tm_Out_Cnt) { // 扫描超时变量,并且把不为0的变量进行自减一
- *gTimOut[i] ? (*gTimOut[i])-- : 0;
- i++;
- }
复制代码使用方法
- vu32 _gTimeOut1 = 0; // 全局变量
- TimeOutSet(&_gTimeOut1 ); // 超时变量注册,最好注册一次,重复注册也可以使用,但是稍浪费一点时间
- //正式使用
- if(_gTimeOut1 == 0) {
- _gTimeOut1 = 50;
-
- // DoSomeThing();
- }
复制代码一周热门 更多>