一、时钟设定
系统复位时,默认使用内部振荡器作为系统时钟,出厂前已经将基频定为12MHZ,可以根据需要对其进行分频操作。
分频方法: 寄存器OSCICN 最低两位 D1D0的值决定了分频数,00~11分别为8分频、4分频、2分频、不分频。
此外,D7=1表示内部振荡器使能,反之禁止内部振荡器
D6=1内部振荡器频率准备好标志
D5=1强行挂起内部振荡器
寄存器OSCICL 内部振荡器校准,D4~D0的数值决定了校准后的频率偏差,计算方法由如下公式决定:
第二项的分母为基准频率,第三项为D4~D0,浮动范围0~31,根据这个公式,当基准设置为12M时,能够设置的偏差很小。
△T=0.0025×0.083us×(0~31)=0 ~ 0.0064325 us
以12Mhz为例,12M对应的周期为0.0833us,加上该偏差为0.0897625us,对应频率为11.14M。
也就是说,当基准频率为 12 Mhz时,最多可以调整为11.14M
以此类推。2分频时,6Mhz,最多可以5.57M
4分频时,3Mhz,最多可以2.78M
8分频时,1.5Mhz,最多可以1.39M
二、八段管的一点小收获
偶然发现自己以前写显示程序实在是太老土了,display()铁打不动就是选一个管,送个段码,延时,选下一个管,段码,延时,再选下一个管。。。 这样一来显示程序必定要消耗大量的时间在显示程序上。当系统时序要求高时,这种写法根本就是自杀行为。
正确方法应该是,设置定时器在一个足够小的时间上,比如10ms,利用一个变量保存中断的次数。每次进入中断,根据(变量%4)的值,来驱动一个管显示数字,下一次中断时切换下个管,以此类推。。
三、F320内部定时/计数器的使用
芯片内部有4个定时计数器,其中T0T1与51兼容,T2T3只能定时不能计数,但可以实现16位自动重装计数值。
寄存器TMOD TH0 TL0 TH1 TL1 以及T0T1相应的启停位中断位不变。
新增部分:
1、CKCON 时钟控制器 复位值00H
D7D6控制T3高低位的时钟源,1为选择系统时钟,0为用户设定。
D5D4控制T2高低位的时钟源,1为选择系统时钟,0为用户设定。
*如果设置为单个16位定时器,则D5D7无效
D3D2作用类似,分别控制T1T0的时钟源,1为系统时钟,0为分频时钟,默认为分频时钟。其分频系数由D1D0决定,
00——12分频 01——4分频 10——48分频 11——8分频
2、定时器T2
和T0做个对照:
TH0 —— TMR2H TL0 —— TMR2L
TMOD —— TMR2CN (D4D3决定T2工作方式)
TF0 —— TF2H(16位时,H起作用)/TF2L ET0 —— IE.5 TR0 —— TR2(双8位时,只能控制高八位定时器,低八位永远工作)
TF2LEN =1 低八位时钟中断允许位
TMR2RLH TMR2RLL 专用于高低八位的计数值重载
设为2个八位时钟时,共用一个中断,必须在中断程序中检查对应的标志位才能确定是哪一个时钟计数到,且标志位必须手动清零
另有usb起始帧捕捉模式,暂时不研究
细节: TMR2H 控制字 D7D6 为TF2H 、TF2L ,中断标志
D5 为 TF2LEN,定时器2低字节中断允许位
D4 为T2SOF 没研究那部分,应该给0,表示禁用
D3 为T2SPLIT 1表示双8位,0表示单16位,均可自动重载计数值
D2 为TR2,高八位时钟启动(16位时钟不知道怎么启动。。。。)
D1无用 D0 为T2外部时钟选择,需要与上面的CKCON对应,没研究。
小结:T2可以工作在3种方式下,单个16位时钟,2个8位时钟,USB起始帧捕捉。使用前,必须设置TM2RCN控制字的D4D3决定工作方式。还必须设置时钟源,在CKCON和TMR2H都有涉及。
对于16位时钟,计数值存放在TMR2H和TMR2L,有专门的重载寄存器TMR2RLH和TMR2RLL。启动时可能是用TR2,开中断用IE.5(ET2),计数到标志位叫TF2H,另有TF2L,必须专门在控制字的D5进行设置才能使用。[page]
对于8位时钟,和上面基本差不多,共用一个中断。
T3和T2没啥区别,名字数字改改,中断允许叫ET3,但位置不在IE,无所谓。
四、程序实测
1、T2 单16位,16位中断实测
初始化:
CKCON=0x00; //D1D0定了分频数,就是在系统分频振荡器后,定时器还能分频一次。
//D3D2比较爽,写个0x0c,不分频直接给时钟用,很快。。。
TMR2CN=0x00; //D5不允许低8位中断 D4禁止SOF D3单16位 D2暂不启动 D0使用12分频时钟
TMR2L=0x78;
TMR2H=0xEC;
TMR2RLH =0xEC;
TMR2RLL =0x78;
EA=1;
ET2=1;
启动:TR2=1;
中断号 :5
中断里面必须加 TF2H=0;
结果,成功
2、T2 单16位,允许低八位中断,尝试根据中断标志决定处理或者不处理低八位。
上面的初始化改一句 TMR2CN=0x20; 由于低八位计数到就中断,且低八位中断没清除,分针又跑得飞快了
中断多一句清除指令 TF2L=0; 秒针走很快,合理。因为每255就中断一次
中断最前面多一段 if(TF2L==1){TF2L=0;return;} 忽略低八位时钟中断,秒针正常了
3、T2双8位,实在懒得测试了。 测试一下T3的中断号
悲剧了,T3的寄存器都没有定义!查资料。。。
修正1 : 在头文件里把TMR2CN的位定义复制一份,改成3,成功
修正2 : 在头文件里手动编写EIE1的位定义
/* EIE1 */
sbit ET3 = EIE1 ^ 7;
sbit ECP1 = EIE1 ^ 6;
sbit ECP0 = EIE1 ^ 5;
sbit EPCA0 = EIE1 ^ 4;
sbit EADC0C = EIE1 ^ 3;
sbit EWADC0 = EIE1 ^ 2;
sbit EUSB0 = EIE1 ^ 1;
sbit ESMB0 = EIE1 ^ 0;
失败,提示该地址无效?(invalid base address)
修正3: 直接用 EIE1 |= 0x80; 编译通过
运行后还是不走,估计是中断号有错!!!
直接在main函数中查询T3中断标志位,手动跳转到中断程序,可以运行,但是速度慢得没天理。
可见T3中断确实不是这么用的,待查。。。。
还有一个猜测,是不是keil对interrupt 14不支持??
又多了个疑点,改回T2,同样用查询方式,手动跳转,速度非常正常!看来T3的PDF没有看是个严重错误!
上一篇:基于18B20和单片机89C52的测温程序
下一篇:AD9850(DDS)驱动程序
推荐阅读最新更新时间:2024-03-16 14:26