|||
/*
多功能电子表设计 寻找最佳定时值 实现精确时钟
如果MCU晶振为12M,则一个机器周期为1us, 很容易计算时钟误差。
但现在晶振选了11.0592M, 这个值与串行通信密切相关——用波特率计算软件计算常用波特率就知道这是怎么回事了。
所以,对于一个没有用串行通信 又 需要精确定时的电子表来说,选11.0592M是不合适的。
如果硬是选了它,怎么办?
寻找最佳定时值,使时钟误差最小!
怎么找?
最省事的方法是不找,随便先一个,并在某个时刻校准:如让时钟运行一小时,与标准时间的差即为误差。每小时校准一次。
确实是个好办法,呵。
学习就是把简单的问题复杂化,把复杂的问题简单化。所以,我不走此路。
让我们来面对时钟误差这个问题: 你的时钟误差是多少?
晶振fosc
T0方式2,自动装定时初值。中断周期NT不要太小,太小了没等中断返回又进入了,系统没法工作!
机器周期 T=12/fosc
T0中断周期 NT=12N/fosc
设T0中断计数 SNT次时为1s
SNT=1/NT=fosc/(12N)
误差:SNT小数部分/SNT整数部分*100% (SNT整数部分? 计算用浮点型,MCU实际使用的是整数)
数据类型和范围:
T0方式2,所以N为8位,范围0~255
SNT类型uint,16位,范围 0~65535
依SNT=fosc/(12N)设计如下程序,求最佳N,使时钟误差最小
用求得的结果(N=120,SNT=7680)编程时钟模块
实验结果:
1分钟误差4s !? 呵呵,T0中断优先级没设置,总是被用于SEG显示的T1中断影响。
设置T0优先级1,T1优先级0, 运行4小时肉眼没有发现时钟误差。
继续实验中。 明天测量跑表精度,不过现在迫不及待地先发布这个程序~~~~~~~~~
PZ
2009年4月6日
*/
#include <iostream>
using namespace std;
double fosc=11059200; // 11.0592MHz
void main()
{
int n, i;
double aSnt[257];
double err;
fosc/=12;
for(n=256; n>100; n--) // 中断周期不能太小,取大概100us
{
aSnt[n]=fosc/n;
if(aSnt[n]>65535)break;
}
cout<<endl<<"搜索数组,找最佳N,并输出时钟误差"<<endl;
n++;
err=1;
double t;
while(n<=256)
{
if((int)aSnt[n]==0)
system("pause");
t=aSnt[n]-(int)aSnt[n];
t/=(int)aSnt[n];
//cout<<aSnt[n]<<endl;
if(err>t)
{
err=t;
i=n;
}
n++;
}
cout<<"最佳N:"<<i<<endl;
cout<<"此时SNT:"<<scientific<<aSnt<<endl;//
cout<<"误差:"<<err<<endl;
cout<<endl<<"// TH0=TL0="<<256-i<<endl;
/////////////////////////////以下计算跑表的CNT/////////////////////////////////////
// 跑表计时模为1hour,精度优先级低于时钟。根据时钟最高精度要求求得TH0(TL0)、SNT后,求跑表的CNT(C表示centi-second)
cout<<endl<<endl<<"跑表CNT:"<<int(aSnt/100+0.5)<<endl;
}