晨昏 发表于 2013-1-5 22:13:14

tiny13 用CTC输出100Hz 不准确

写了几行代码设置了一下寄存器要输出个100Hz的 方波

用CTC方式
DDRB=0XFF;
TCCR0A=0X42;
TCCR0B=0X03;
OCR0A=374;

内部4.8M64分频 按公式算出来是100HZ测出来是280多Hz。请问为什么。?

mingxin 发表于 2013-1-6 13:03:09

能把程序贴出来吗

晨昏 发表于 2013-1-6 13:16:53

mingxin 发表于 2013-1-6 13:03 static/image/common/back.gif
能把程序贴出来吗


#include <tiny13.h>

void main(void)
{

CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

PORTB=0x00;
DDRB=0x00;

TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

GIMSK=0x00;
MCUCR=0x00;

TIMSK0=0x00;

ACSR=0x80;
ADCSRB=0x00;

DDRB=0XFF;
TCCR0A=0X42;
TCCR0B=0X03;
OCR0A=374;
while (1)
      {

      };
}

mingxin 发表于 2013-1-6 20:47:19

在CTC 模式(WGM01:0 = 2) 适用于产生占空比为1:1的方波。通过改变分频系数N和OCR0的值改变频率,其频率计算公式为:% z[7 Q' l4 d' \/ d( M; a
    fOC0= fclk/(2*N*(1+OCR0))/ n7 `6 N$ r7 ?- X
范例程序:
- m6 w7 @& W+ ~* ?/ R3 ]2 }. _/*///////////////////////////////////////////////
/ Z, d5 I1 d/ `( V7 k5 X' D/////////定时器TO的使用例程——CTC模式///////////( a( `' S0 I* n5 l/ r0 V1 q
//作者:宝山* h& a6 J: ^7 J3 G
//时间:2008.06.02* a" T6 P; X0 P
//编译环境:ICCV7 for AVR
0 o8 t$ U2 i. u1 O6 Z* _//晶体: 11.0592Mhz
. C# @) S( e2 r3 K$ I///////////////////////////////////////////////*/5 {1 N8 v6 A/ U$ ~/ T
#include <iom16v.h>% }, z5 j) x. q: d. b! R
#include <macros.h>
" H% m; }- e9 e2 w2 z7 h$ nvoid port_init(void)7 F- V2 E/ r3 S. Z
{
% f. T* N, N( x7 x# ?$ r% Y4 o6 CPORTA = 0x00;
+ P4 _7 [- f/ K" vDDRA= 0x00;( _3 L8 @6 W2 C
PORTB = 0x00; + q, r9 Q6 t8 b/ }3 Q; P
DDRB= 0x08; //PB3为PWM输出7 `$ yq" r( K: [6 T* a4 r
PORTC = 0x00; //m103 output only' x- F% \5 ?$ d0 A$ x% a
DDRC= 0x00;
- R+ r& L! S2 P8 n: L5 zPORTD = 0x00;
+ x% s" I# \$ ^% I. RDDRD= 0x00;
8 q& Y9 {) O7 T0 ^4 n5 jD8 I6 {}
3 P! j$ e& r. ?void timer0_init(void)* P/ K' gw/ a$ |, Q
{
# }. T" C, j% _# qTCCR0 = 0x00; //stop
8 J" |6 A/ h( X, B7 CTCNT0 = 0x01; // TCNT0要小于OCR0
3 r1 h. k. a7 W5 JOCR0= 0x14;//改变此值可改变频率% _4 z3 Z, }6 }' \: v2 ?
TCCR0 = 0x1C; //设置为CTC模式,匹配时OC0取反,分频系数256- H# V! H9 C2 s' w. d
}% O7 k& _+ Q9 |! l( M
// 频率计算公式:fOCn= fclk/(2*N*(1+OCRN))
& f8 ?/ ?( Z; [+ \C3 C) W// N=256,OCR0=0x14=20) ~: @/ c: c& {. J
// fOC0=11059200/(2*256*(1+20))=1.028KHz
& J4 ?% f1 }# A7 f& o1 m// 在PB3管脚输出占空比为1:1,频率为1.028KHz的方波信号- j3 \* \) n. PN1 S2 A3 V
// 通过改变分频系数N和OCR0的值改变频率0 T7 |, Q7 Q' j7 W# k5 F+ E2 D
#pragma interrupt_handler timer0_comp_isr:iv_TIM0_COMP
) L* k3 F3 e" d& @void timer0_comp_isr(void)
6 M~6 n6 u# r- p{
# I# r1 b3 q3 h* h2 go2 Y0 L) S//compare occured TCNT0=OCR0: B3 D; O; d|
}" N! u$ {2 ~6 \: o% S% Q3 ~; b) z
#pragma interrupt_handler timer0_ovf_isr:iv_TIM0_OVF4 a, ^! \8 z6 S# |* M
void timer0_ovf_isr(void)6 e, UR. R( A9 [2 l, `: g
{5 `2 Z0 j- C, E/ S
TCNT0 = 0x01; //reload counter value
% o" j+ r+ [; q# G5 `}3 x" }! i+ T. k
void init_devices(void)
) ]1 Z$ M- V& K{! Y, E# u% ?l& j. ?$ N! d
CLI(); //disable all interrupts! m" V( s3 _/ g* z( s2 x, `
port_init();2 U5 E; B7 Z7 `- W! U1 \4 K
timer0_init();! p8 h6 X7 bX?2 d3 M' z4 {
MCUCR = 0x00;
+ E) e! a& T( p" N- I; L# Z9 J# {GICR= 0x00;
. ~! Y+ M$ f* o$ q# \2 ^' w6 iTIMSK = 0x03; //timer interrupt sources
# s5 r9 P+ y) d! _0 TSEI(); //re-enable interrupts' g1 K; Z' i/ n) D, y7 U
//all peripherals are now initialized* }1 b# F/ h# D- W
}Y+ V, P" \+ H
void main(void)
. G( d1 J0 }, |{
( R8 c' n0 Z2 u, p- J* z! Winit_devices();8 V6 d0 Q* T* U5 w4 ?
while(1);) o" O3 b" L' k. D5 K( V
}
4 W2 H3 i! M/ q' o! U4 ?4 P完整程序文件:
/ G# \2 l# T* j1 D( d$ ^* S: c' y# V# S

mingxin 发表于 2013-1-6 20:50:07

请参考连接http://www.52eas.com/forum.php?mod=viewthread&tid=1130
重点看 OCR0A=374;

eblc1388 发表于 2013-1-6 21:14:16

楼上把 374 放入 OCR0A 可能要使用点劲,不然放不入。

t3486784401 发表于 2013-1-7 16:51:40

表示 TINY 内部是 RC 振荡器,这个本身就不太准了

想要准的话,需要用 OSCCAL 寄存器进行时钟微调,

当然这个过程中需要更准一级的时间基准,例如晶振,例如串口波特率

jlhgold 发表于 2013-1-7 18:22:35

t3486784401 发表于 2013-1-7 16:51 static/image/common/back.gif
表示 TINY 内部是 RC 振荡器,这个本身就不太准了

想要准的话,需要用 OSCCAL 寄存器进行时钟微调,


酱油的飘过!其实rc也还行,就看要求是啥,其实楼主没说差多少,是不是可以认为99.9hz也是不准?

晨昏 发表于 2013-1-7 19:03:02

jlhgold 发表于 2013-1-7 18:22 static/image/common/back.gif
酱油的飘过!其实rc也还行,就看要求是啥,其实楼主没说差多少,是不是可以认为99.9hz也是不准? ...

谢谢提醒,刚用CTC都有点犯傻了,下午才意识到TINY13的TO 是8位不是16位,我写OCR0A=374超255   应该是溢出了。。改用内部128KHZ.8分频,算出来OCR0A=79。用示波器量实际90Hz,少了10Hz,这应该是内部RC的误差了。

晨昏 发表于 2013-1-7 19:05:24

t3486784401 发表于 2013-1-7 16:51 static/image/common/back.gif
表示 TINY 内部是 RC 振荡器,这个本身就不太准了

想要准的话,需要用 OSCCAL 寄存器进行时钟微调,


请问如何微调,没试过呢我开内部RC 128Khz   CTC 算出来配置好寄存器 理论100Hz实测90Hz。 应该是RC振荡器的误差了。

晨昏 发表于 2013-1-7 19:09:20

eblc1388 发表于 2013-1-6 21:14 static/image/common/back.gif
楼上把 374 放入 OCR0A 可能要使用点劲,不然放不入。

点劲?我写OCRA=374超255了。。T/C0 是8位寄存器,我没注意到,重新配置了分频就好了。虽然有误差但好很多,不会像一开始那样出来个288Hz,现在出来90Hz,差10Hz应该是误差了。

t3486784401 发表于 2013-1-8 14:22:20

晨昏 发表于 2013-1-7 19:05 static/image/common/back.gif
请问如何微调,没试过呢我开内部RC 128Khz   CTC 算出来配置好寄存器 理论100Hz实测90Hz。 应该是RC ...

OSCCAL就是一个寄存器,程序里可读可写。这个寄存器写入的值越高,RC震荡的就越快,见下表:



实际校准的时候,需要外部输入一系列标准时钟(例如1kHz方波),单片机去测量方波周期与自身机器周期关系,
借此判定当前RC震荡是否为准确值,不准确了再调整OSCCAL再测,直到准确为止。

晨昏 发表于 2013-1-8 23:40:45

t3486784401 发表于 2013-1-8 14:22 static/image/common/back.gif
OSCCAL就是一个寄存器,程序里可读可写。这个寄存器写入的值越高,RC震荡的就越快,见下表:




嗯。谢谢。我能否也用这个方法呢。OSCCAL 写数据,然后看我OCR0A 是否已经由90Hz往100Hz靠,通过不停试去确认最后OSCCAL用大多。。。

t3486784401 发表于 2013-1-9 16:23:53

晨昏 发表于 2013-1-8 23:40 static/image/common/back.gif
嗯。谢谢。我能否也用这个方法呢。OSCCAL 写数据,然后看我OCR0A 是否已经由90Hz往100Hz靠,通过不停试去 ...

一次实验可以的,但是RC的振荡频率随温度会变(比如冬天调好的程序,夏天跑的速度就不一样了)。

总是手动调节会比较不爽啊。附上 ATMEL 官网的RC校准资料,希望有用!

晨昏 发表于 2013-1-14 08:47:03

t3486784401 发表于 2013-1-9 16:23 static/image/common/back.gif
一次实验可以的,但是RC的振荡频率随温度会变(比如冬天调好的程序,夏天跑的速度就不一样了)。

总是手 ...

嗯啊,谢谢,这星期试试。

rainbow 发表于 2013-1-14 09:29:33

374,写到OCR0是118,实际出来应该约为317.8Hz,测到288,约为90.2%,调整一下OSCCAL的值,可以到1%以内的误差,当然环境温度变了也会有一定的变化。
页: [1]
查看完整版本: tiny13 用CTC输出100Hz 不准确