我目前正在使用飞思卡尔的9S12,我真的需要一些帮助才能了解如何正确编写ISR。特别是,我正在报告一个练习的文本,他们要求我测量两个方波(在微控制器的输入端)之间的相位差。
总线时钟为16 MHz,我必须使用系统的计时器模块,该模块提供一个自由运行的计数器(TCNT @ 16位)。计数器必须在500 kHz下工作,这是通过从总线时钟开始将预分频器设置为5来实现的。 这两个信号具有相同的频率(给定为25 Hz),但无论如何都要对其进行测量。
我必须使用INTERRUPT过程,使用正确的寄存器(实际上没有必要使用与手册中完全相同的寄存器,我可以使用所需的任何名称,而不必注释代码的每一行)和变量
我解决问题的方法非常理论化,但是我需要C代码。
为了解决该问题,我必须使用输入捕捉模式,以测量信号1的上升沿和信号2的上升沿之间由TCNT(TICKS)计数的单位之差。特别是关于我必须使用的变量,类型(LOCAL,GLOBAL,UNSIGNED,LONG(?)),如何在ISR中正确更新值以及是否应考虑计数器的溢出以及它们各自产生的中断。
我陷入了这个问题,希望有人可以帮助我提供一些代码示例,尤其是有关我必须使用的变量以及如何编写实际ISR的代码示例。 谢谢大家!
答案 0 :(得分:2)
将以下内容作为伪代码处理;您需要仔细阅读数据表以确定如何配置和访问定时器捕获单元-我不熟悉特定部分
通常,给定的计时器计数器为16位:
volatile static uint16_t phase_count = 0 ;
volatile static uint16_t mean_period_count = 0 ;
int phasePercent()
{
(phase_count * 100) / mean_period_count ;
}
int frequencyHz()
{
500000 / mean_period_count ;
}
void TimerCounterISR( void )
{
static uint16_t count1 = 0 ;
static uint16_t count2 = 0 ;
static uint16_t period1 = 0 ;
static uint16_t period2 = 0 ;
uint16_t now = getCaptureCount() ;
if( isSignal1Edge() )
{
period1 = now - count1 ;
count1 = now ;
}
else if( isSignal2Edge() )
{
period2 = now - count2 ;
count2 = now ;
phase_count = period2 - period1 ;
}
mean_period_count = (period1 + period2) >> 1 ;
}
该方法假定有一个递增计数器,并且要求计数器重载运行16位范围0至0xFFFF的完整值-否则,modulo-2 16 算法将不起作用,并且解决方案将很多更复杂。对于递减计数器,请在周期计算中交换操作数。
请注意,phasePercent()
和frequencyHz()
的返回值只有在两个阶段都经历了完整的上升沿到上升沿循环之后才有效。如果这是一个问题,您可以添加一个边沿计数,并在每个信号上都看到两次上升沿后进行验证。
答案 1 :(得分:0)
这是您为S12整理技术部件的方法:
使用适当的预分频器设置ECT定时器。您似乎已经涵盖了这部分?在500kHz时,每个计时器滴答是2us,您需要65536个计时器滴答来覆盖最坏的情况。预分频器的一个完整TCNT周期为131ms。如果〜25Hz是最坏的情况,则大约为40ms,因此在这种情况下应该可以。
选择一个与所使用的引脚相对应的计时器通道TC。该通道需要配置为输入捕捉,在上升/下降沿均触发。将TCNT的当前值作为初始值存储到uint16_t
时间计数器变量中。
在向量表等中注册ISR,这是编写ISR的常用方法。
在中断时,读取TCn通道寄存器的值。计数器变量和存储值之间的差给出了计时器周期中的周期时间。将此乘以1 / 500kHz,即可得到周期时间。在ISR中,始终读取TC而不读取TCNT,因为前者将不受中断等待时间和代码执行开销的影响。用TCn中的值更新您的计数器变量。
采用这种设计,请确保有一些外部方法可以滤除输入中的尖峰和EMI:RC滤波器或类似器件。