前几天学习了一个新的红外线遥控器解码的程序,使用的方法与51下的中断独占方法完全不同,可以说尽量发挥了AVR单片机的功能。程序的思想是,使用定时器的捕捉模式,来完成对红外解调信号的宽度测量。与51下传统的方法相比,优点是明显的,这个代码工作在中断模式,不会独占外部中断(51下的代码为了完成对外部信号宽度较为精确的测量,强制关闭了所有的中断响应)。
这个代码很快调通了,并且也很好用。这是我第1次使用AVR定时器的外部信号捕捉功能。今天突发奇想:如果用来捕捉GPS模块输出的1PPS频标信号会有什么后果呢?后果就是可以精确地测量出,在1PPS外部信号的周期内,MCU时钟走了多少步。这意味着,如果外部1PPS信号是准确的(我查了一下我模块的DS,给出的指标是+-50nS),那么通过计算,就可以得出MCU时钟的准确频率值,而且精度可以达到HZ级别。
也就是说,如果MCU的时钟,是由外部有源晶体、TCXO甚至OCXO提供的,那么这种想法就可以用来测量出外部时钟的准确频率(这似乎对留有调整孔的TCXO更有意义)。当然,限制就是此方法,只能对AVR适用的时钟频率范围的晶体有效了(X-20MHz)。
于是在实验板上写了一个程序,来验证想法。
1、程序首先对GPS进行解码,用来完成GPS是否已定位的检测(后来的结果似乎表明,GPS模块的定位与否,对它输出的1PPS频标似乎没有影响,怀疑GPS模块具备有1PPS信号自校准功能。就是说定位后,它会根据GPS卫星的信号,计算出本身的晶体偏差数值,并且完成对输出的1PPS信号的修正。当然,这纯属猜想)。
2、打开定时器1的捕捉模式,并且开启了溢出中断。在捕捉中断中,程序完成对工作状态的判断(是否在测量状态),并且根据状态的不同,保存时间值到2个分别代表启动和停止的变量中。并且在测量完成时,置位一个数据有效标志。
3、溢出中断相当简单,只是完成溢出次数保存。
3、主程序中,挂接一个LCD驱动。然后检查测量标志是否有效,有效时,立即进行计算,并显示出来,结束后复位标志。
上述算法在我的实验板上经过了检验,测量14.745600MHz的时钟频率为14.745158MHz,粗算了一下,似乎相当于-30ppm的精度。这比较符合普通晶体的性能。
另外同时对AVR的内部RC振荡器进行了测试,发现无论是稳定性,还是准确度,RC都是无法和晶体相比的(废话~)


刚刚测量了BG4UAT送我的TALTRON 20MHZ的OCXO,结果见图。热稳定后,每分钟变化小于HZ…… 真爽,同时也验证了我算法的正确性。(注意:频率已经偏差已经严重超出该晶体的标称误差正负100ppb,估计原因是:晶体的标称供电电压为3.3V,但我当时条件所限,是5V供电的)