硬汉嵌入式论坛

 找回密码
 立即注册
查看: 4421|回复: 4
收起左侧

[有问必答] 定时器更新中断服务程序中清除UIF位的时机

[复制链接]

20

主题

56

回帖

116

积分

初级会员

积分
116
发表于 2018-11-17 21:46:05 | 显示全部楼层 |阅读模式
本帖最后由 bucker 于 2018-11-17 23:08 编辑

一个定时器作为编码器输入,由于计数值大于65536,使用了定时器的更新中断作为扩展计数。遇到的问题是,由于步进电机传动存在抖动的原因,编码器的计数值也不够稳定,定时器的计数倒是没问题,问题出在中断服务程序中。举个例子,如果在中断服务程序最后清除SR中的UIF位,则一次计数器溢出可能发生6次中断(专门设置一个变量记录中断发生次数),这样根本不能可靠进行扩展计数;而在中断服务程序最前清除SR中的UIF位,则记录发生3次中断,这样一来,说明清除UIF的次序会影响中断的发生次数。这个问题期望大侠解答。
举例
uint8_t n = 0;
void TIM4_IRQHandler(void)
{
        TIM4->SR &= TIM_SR_UIF;  // 清除UIF更新标志
        服务程序
        n++;
}
结果是发生一次tim4溢出,n=3;


如果是
uint8_t n = 0;
void TIM4_IRQHandler(void)
{
        服务程序
        n++;
        TIM4->SR &= TIM_SR_UIF; // 清除UIF更新标志
}


结果是发生一次tim4溢出,n=6;
解释下为何说n=6是不正确的,因为步进电机向前走一步,计数器应该加一,机械系统存在抖动,计数器原值为65535时,导致编码器计数超过65535出现累加过零的情况,发生一次中断,由于抖动的原因计数值又迅速减一使得计数值由0变为65535,再次发生中断,然后又一次进一再发生中断,也就是n的计数为奇数时才是符合机械抖动的特点,n为偶数则是错误的。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106913
QQ
发表于 2018-11-18 10:11:47 | 显示全部楼层
楼主这个问题提的很好,只是我没有研究过。

F1是否支持定时器级联,看看能不能解决扩展问题。
回复

使用道具 举报

20

主题

56

回帖

116

积分

初级会员

积分
116
 楼主| 发表于 2018-11-18 20:45:18 | 显示全部楼层
应该说在计数器单向计数时,级联是个好办法。在我的应用中,由于主计数器只能输出一个溢出信号,而这个溢出信号可能是进位也可能是借位,从计数器无法判别加减的方向,因而不适用级联方式解决此问题。在实测中,还存在编码器65535和0之间的小幅抖动,以至于中断响应可能丢失一次中断信号,使得中断服务程序未能正确捕捉到最终是该高位加一还是减一,实测C中断函数首指令存在的延时是44个时钟周期,大约44/72≈0.61uS,这样的延时无法捕捉到全部的溢出时机,故打算采用汇编中断服务的方式来尝试解决这个问题。
回复

使用道具 举报

20

主题

56

回帖

116

积分

初级会员

积分
116
 楼主| 发表于 2018-11-19 20:35:08 | 显示全部楼层
今天尝试了用汇编写中断服务程序,发现进入中断的延时还是有32/72uS,不知是CPU的原因还是Keil的原因,这样一来,用汇编也没有意义了。
回复

使用道具 举报

1

主题

7

回帖

10

积分

新手上路

积分
10
发表于 2021-2-1 15:31:22 | 显示全部楼层
请问楼主最后解决了吗?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-10 02:56 , Processed in 0.169179 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表