favr 发表于 2007-10-31 23:23:43

内部RC震荡器做USART通信到底有多可靠?

以前用M8/M16时一个感觉就是使用内部RC震荡器不能可靠地用于USART通信,因为测试过,使用内部震荡器时经常有误码,所以就一直用晶体了。
最近有个U盘大小的东西要做,2个片子,空间实在太小,再塞一个晶体确实有点难办,程序写好了,烧了几片来测试,使用内部震荡器居然没有一个有错误的,心血来潮拿个热水罐放在片子上,大概有7、8十度,几片工作居然都没问题,通信无误(协议对关键字节及数量都要求精确的),翻数据手册看48/88只有8M的标定字节,在3V 25度时的误差为1%,这对于9600B的通讯肯定是没问题的,而且在我这热水罐下芯片的温度也该有60来度。
现在倒怀疑以前的测试是不是使用了其他频率,不是8M这个标定了的频率,有谁批量用过内部标定的8M RC做USART通信产品的?能不能介绍下。
不是这个晶体价钱的问题,的确是空间太拥挤,不想用,但如果没有前人的用例心里也没底。

xiaoxu191 发表于 2007-11-1 07:27:04

1)误码的主要原因还是内部RC振荡器频率不准。我比较过没有校准和校准以后的通讯,后者做到56000bps都没有问题。在室温下从不出错。

2)Atmel没有保证内部RC振荡器出厂时频率是准确到1%的,而是10%。相反,手册和笔记中反复提到校准。±1%误差是在校准以后的精度,手册上说“校准以后可以保证在任何(许可的)VCC和温度范围内±1%的精度”。Mega48/88/168的手册中Figure 29-40,是关于Vcc、温度和振荡频率的曲线,看起来同一电源电压下,以20度为基准,-5度到+45度振荡频率误差不超过1%,-40度2.25%, +85度3.1%。

3)我没有做过批量板的试验,请有经验的高手指正。

luxinsun 发表于 2007-11-1 07:58:14

不能用

favr 发表于 2007-11-1 09:33:37

谢谢

1楼,我看到手册中有关片内RC振荡器是这样描述的:
(P27)
标定的片内RC振荡器
校准的片内RC 振荡器提供了固定的8.0 MHz 的时钟, 这是在3V、25°C 下的标称数值。器件出厂时CKDIV8 熔丝位已经被编程,请参见P 30 “ 系统时钟预分频器” 。按照Table11 对熔丝位CKSEL 进行编程即可将其作为系统时钟。选择这个时钟之后就无需外部器件了。复位时硬件将标定字节加载到OSCCAL 寄存器,自动完成对RC 振荡器的标定。在3V、25°C 时,这种标定可以提供标称频率 ± 1% 的精度。 通过改变OSCCAL 寄存器,标定可以使振荡器在 7.3 - 8.1 MHz 的范围内的精度达到± 1%。当使用这个振荡器作为系统时钟时,看门狗振荡器继续为看门狗定时器和溢出复位提供时钟。更多的有关标定数据的信息请参见P 259 “ 校准字节” 。

(P28)
振荡器标定寄存器- OSCCAL
将标定数据写入这个地址可以对内部振荡器进行调节以消除由于生产工艺所带来的振荡器频率偏差。这在芯片复位时自动完成。25°C 时振荡器频率为8.0 MHz。应用软件可对该寄存器进行写操作来改变振荡器频率。振荡器频率范围在7.3 - 8.1 MHz 内标定精度可达到±1% 以内,频率超出此范围则无法保证。

(P259)
校准字节
ATmega48/88/168内部RC振荡器的校准值保存于校准字节。这个字节位于标识地址空间0x000 的高位字节。在复位期间,该字节被自动写入OSCCAL 寄存器以确保校准的RC 振荡器频率的正确性。

(P285)
Figure 140. 工作电流和VCC 的关系( 内部 RC 振荡器, 8 MHz)
按我理解,这图并不是说明电压、温度对频率的影响,而是电压和电流的关系,就是说器件工作时电压和电流并不是线性比例关系。不能从这个图反推频率会因为电压和温度的不同会按某曲线进行变化——或许确实有,但这图不是反映这关系的。

从上面P27/28和P259的相关描述我是这样理解的:
ATmega48/88/168出厂时已经对8.0 MHz 的时钟进行了校准,在3V、25°C 时,8M 频率 ± 1% 的精度。校准字节已保存在标识地址空间0x000 的高位字节,在复位期间,该字节被自动写入OSCCAL 寄存器。另一方面,用户通过改变OSCCAL 寄存器,可以改变内部RC的振荡频率,在 7.3 - 8.1 MHz 的范围内的精度达到± 1%。在这个频率范围外就不能保证。
所以说,如果使用内部 RC 振荡器,并且只用8M时钟,使用出厂时的校准字节就可以了,对于其他频率就需要用户自己校准。

fkueawuk 发表于 2007-11-1 09:49:07

内部RC震荡器很垃圾,大部分蕊片精度较高,但有部分可不行了,我用过内部8M用9600波特率经常数据出错的M8蕊片

ilikemcu 发表于 2007-11-1 10:01:20

呵呵,如果非常原因必须用内部RC,那么建议楼主在程序里考虑下,看看周边电路上能否提供一个精度较高(1%以内)的时钟基准,用那个基准对内部RC做一个对比校正,否则纯粹用内部RC做波特率通讯,呵呵,会让你死得很难看!因为我碰到过,后来我是用后面的办法解决的,唯一的确点是延长了开机初始化的时间,呵呵,要校正嘛

zijunwuhan 发表于 2007-11-1 11:43:32

好!

xiaoxu191 发表于 2007-11-2 00:00:34

3楼(楼主):
我看的是Mega48/88/168的英文手册,和你的描述有差异,结论也不同。

片内RC振荡器(你的P27,我的P34,第8.6节)
我的翻译如下:默认情况下,片内RC振荡器提供近似8MHz的时钟。这个时钟随电压和温度变化而变动,但是可以非常精确地由用户校准。
我看不到出厂已经校准的说法。

“(P285) Figure 140. 工作电流和VCC 的关系( 内部 RC 振荡器, 8 MHz) ”
我看不懂你引用Figure 140的原因。我在1楼引用的是Mega48/88/168的英文手册的Figure 29-40. Calibrated 8 MHz RC Oscillator Frequency vs. Temperature,已校准的8MHz RC振荡器频率和温度的曲线。

其实就是一个片内RC振荡器加上校准寄存器OSCCAL。一旦校准了,你设成8M/4M/1M都是准的。

我的结论:
1)单个的产品校准以后是非常准确的。这已经得到测试。
2)从手册上看,经过校准以后,即使温度变化,也应该可行。但是,环境温度变化大的情况我没有批量试过。

5楼提出了一个校准的方法,还有用频率计,或者是波特率自适应。

bg9fu 发表于 2007-11-2 08:32:14

没有意义的讨论。

ilikemcu 发表于 2007-11-2 09:03:44

7楼的老兄,强烈建议你提建议时一定要经过实践检验的经验,不要轻易下结论!

我提出的办法是我自己在产品应用中出现问题后的解决方法!

而且我用的是1M的默认内部RC,经过校准,但是我可以负责任地告诉大家,我实际对校准后的芯片运行时钟做过测量(测量固定的PWM频率输出,再计算出内部RC频率),最大的误差达到4%还多!做波特率绝对不行了。

roasn 发表于 2007-11-2 09:15:59

这个要看情况,我以前做一个产品就是用M8内部的RC,9600波特率,与电脑通讯没有问题,但是,如果另外一个通讯端的时序要求稍稍严格,通讯就失败。这次的教训比较大,搞得好一段时间焦头烂额的。
后来,我用示波器看了一下,误差真的很大,具体误差有多少我就不太记得,因为已经有些日子了。
后来我学乖了,凡是要用到通讯的,一律用外部晶振,一了百了。

slyt 发表于 2007-11-2 17:54:55

用内部RC通讯没问题,8M下经校准后可以做到115200,没有误码。但标定值不要用片内给定的,需要自己测量。
不同温度下没试过,在室温下用不同批次的M8使用正常。

walker 发表于 2007-11-3 00:54:17

对于1个起始位8个数据位1个停止位无校验,波特率误差理论上要小于5%,实际波形总有些畸变,并不允许误差这么大,尤其速率高时,对误差要求更严格些。个人认为,为保险起见,在校准的基础上,通讯速率尽可能低些。

xiaoxu191 发表于 2007-11-3 09:30:08

9楼的朋友:
冤枉啊,我没有否定过你的观点和校准方法呀。我也没有对我没做过的事情下结论。相反,我还一直说明我对批量和温度变化没有验证过。我用“我的结论”一词,是想说明经过理论分析和具体校准和测试,我认为校准的片内RC振荡器是可以用的,如果不同批次和温度变化下也支持这个结论,就说明Atmel的芯片和手册没有造假,可以用在产品上。

让我补充一下,我是说校准片内RC振荡器的方法有以下几种:
1)用你的方法:用“周边电路上一个精度较高(1%以内)的时钟基准”。
2)还有:用校准过的频率计测量,这是我使用过的办法,就是频率计要准确,我是用HP的,还经常去校准它。我还用过频谱仪。
3)本网站曾有网友提出用波特率自适应的方法校准。这样做的好处是在生产的时候可以用一个专门的软件版本自动去做这件事,比手工做反复逼近快很多,解决生产效率的问题。详细的步骤请搜相关帖子。

我测到出厂的标定值有6%的频偏,这样在9600bps时就有一位的误码,大约有50%的概率。符合楼上(12楼)的结论。

favr 发表于 2007-11-5 15:29:32

忙了几天,今天有空写了一小段程序来验证内部8M RC震荡器是不是出厂时已经校准的,测试结果是:当编程使用内部8M RC震荡器做时钟源时,OSCCAL 寄存器在复位后确实加载了出厂时经过校准的值,而且在最近买的Mega8中这个校准值的时钟误差基本在1%内,而手上一个2年前的片误差在4~5%之间。
下面简单介绍测试过程及给出相关代码,希望有兴趣的能重复这个测试,以得到更多数据。

一、测试方法
用一个标准频率发生器产生恒定频率的脉冲,例如400us周期的脉冲(200us电平变化一次),测试系统采用内部RC为时钟源,使用1us计时器计数,每个电平变化记录一次计数器值,记录一定数量,计算平均值,消除代码运行时间误差后输出该值,该值和200的比率就是误差。
二、测试系统
要测试内部RC震荡器频率是否准确,就要有基准,手上没有准确的频率发生器,使用一个M16的开发系统来做,使用8M 30ppm的晶体做时钟源,被测系统为M8,通过Int0捕捉M16产生的频率变化。
三、同步基准
因为使用代码来发生脉冲和捕捉脉冲,代码运行需要时间,需要用同一标准来测定代码的运行误差,所以在采用内部RC前被测M8系统先接外部8M晶体做时钟源,用实际测量代码来捕捉脉冲,计算出误差,然后在代码中消除该误差。因为使用30ppm的晶体同步,所以2系统合在一起的误差不会超过1/10000,比1%的RC误差要精确2个数量级以上,所以计算出来的代码误差值是可信的。

测试

频率发生部分代码:
' Bascom 代码
$regfile = "m16def.dat"
$crystal = 8000000                '8M频率
$hwstack = 32                                             
$swstack = 32                                             
$framesize = 48                                          

Config Timer0 = Timer , Prescale = 8' 每us计数1次
Config Pina.3 = Output
Config Pina.2 = Output

Enable Interrupts                                           '全局中断允许
Enable Timer0

On Timer0 Tim1_isr Nosave
Porta.2 = 1
Porta.3 = 1
Tcnt0 = 55                     ' 计200次还是201次不要紧了, 反正两边会通过同一标准计算差值
Start Timer0

Do
   nop
Loop

End


Tim1_isr:
PUSH R24
IN r24, SREG
PUSH R24
   Toggle Porta.3   ' 约200us翻转一次电平
   Tcnt0 = 55
POP R24
!Out Sreg , R24
POP R24
Return

=================
被测系统部分代码
$regfile = "m8def.dat"                                    ' 编译参数设置
$crystal = 8000000
$hwstack = 32
$swstack = 32
$framesize = 48
$baud = 9600

Config Timer0 = Timer , Prescale = 8                        ' 计时器0采用8分频, 每us计数一次
Config Int0 = Change                                        ' 电平变化触发外部中断(约每 200us 1次)

Enable Interrupts                                           '全局中断允许
Enable Int0

On Int0 Int_isr                                             '捕捉外部中断0

Dim Mindex As Byte
Dim I As Byte
Dim Sos As Byte
Dim Mword As Word
Dim Bytes(100) As Byte                                    ' 记100个数

Sos = Osccal                                                ' 原来的OSCCAL
Waitms 100
Tcnt0 = 0
Mindex = 0
Start Timer0                                                ' 开始计数

Do
   If Mindex >= 100 Then                                    ' 已经到了100次(约0.2s)
      Mword = 0
      For I = 11 To 100                                     ' 舍弃前10个数, 计算平均数
         Mword = Mword + Bytes(i)
      Next

      Mword = Mword / 90
      Stop Timer0
      Exit Do
   End If
Loop

Mword = Mword - 2                                           ' 2是用晶体同步得到的代码计数误差
Print "osccal:" ; Sos ; ", avg:" ; Mword                  ' 输出到PC

End

Int_isr:                                                    ' 外部中断处理
   Incr Mindex
   Bytes(mindex) = Tcnt0                                    ' 记录当前计数器值
   Tcnt0 = 0                                                ' 计数器清零
Return

测试几片的结果:
osbc`l:175, avf:208
orcbal:165, avg:208
osbc`l:174, avg:208
orccal:174, avg:209 (这4个是同1片,当208左右时数据已经出现"错位")

osccal:185, avg:202
osccal:181, avg:201
osccal:179, avg:199 (这是不同的片, 误差大致为1%)

平均值Mword大多在198-202之间,频率误差基本在1%内,但一片2年前买的Mword为208-209, 误差在4%,PC接收到的字符有时是错误的(例如175有时会变成075), 手上就几片PI的片子, 只能做几个测试, 谁有片的再做测试看看情况如何?

AWEN2000 发表于 2007-11-5 15:53:01

M8/M88内部rc波动范围1%,而出厂时校准精确度3%-10%。

只要校准了,就可以用,1%误差还是可以忍受的。如果波动10%就不可接受了

xk2yx 发表于 2007-11-5 16:48:18

真的要搞通讯的话肯定不能用内部RC的,用串口来调试用RC肯定没问题的。

favr 发表于 2007-11-5 17:38:21

这是精确度和稳定性的问题,如果精确度足够,稳定性足够,怎么就不能用来做通信呢?经验当然很重要,但做事情应该有足够的数据支撑,如果有足够多的测试数据表明精度/稳定性是足够的使用起来就应该没有问题——使用不良晶体也有振不起来的嘛。
所以我的想法是有尽量多的人重复这个测试,如果在一定时间内,不同批次的片被证明精确度和稳定性能达到要求,不但可以省个晶体,还可以省空间嘛,当然1%的精度不足以作为时钟,但某些应用还是可以的。

futter 发表于 2007-11-5 19:04:20

我用的取中值的方法来做rc校准的,校准完后通信还不错,但不知道校准完后,对温度的抗性有多大,是不是真如7楼说的,校准完后,“这个时钟随电压和温度变化而变动,但是可以非常精确地由用户校准。 ”,还是她随温度的飘移很大,希望有人给个明确的结果!!

wzxavr 发表于 2009-9-25 11:08:23

mark

xukaiming 发表于 2009-9-25 22:48:02

只要稳定,可以用波特率自适应来搞定它

WOTASOM 发表于 2009-9-26 21:47:04

使用内部RC不能调太高,4M就可以了,高的话...呵呵

ilikemcu 发表于 2009-9-26 22:48:09

【13楼】 xiaoxu191
积分:216
派别:
等级:------
来自:


抱歉,我看的不仔细。

这个问题,我现在的方法是:

只要板子上存在一个周期相对电压,温度都比较稳定的器件,即使这个器件的实际周期离散性比较大,20%的上下误差,都是可以的。出厂前对板子输入一个已知频率并且比较精准的低频的方波,利用内部计数器对这个方波的计数,同时在对板子上这个周期相对稳定的器件的周期做计数,就可以计算出芯片的频率,保存好这些数据到EEPROM,以后实际应用时,只要对那个相对稳定的周期不停计数,如果芯片频率发生变化,那么这个计数相应同步变化,利用保存的数据就很容易算出当前频率,用这个参数去反过来调节芯片的参数,就可以实现频率误差的自动纠正。

已经用这个方法在STC的1T芯片上,实现了无晶振可靠进行RS232通信的实验,用电烙铁烫芯片,STC的内部RC时钟从5MHz一直降低到4MHz,此时串口以9600速率仍然和上位机保持持续稳定的通讯。所以这个方法用到AVR上相信效果应该更好。

shangxf 发表于 2009-9-26 22:57:33

用个超小型圆柱晶体应该不会加太多空间吧,

ldhavr 发表于 2013-3-29 10:23:10

favr 发表于 2007-11-5 15:29 static/image/common/back.gif
忙了几天,今天有空写了一小段程序来验证内部8M RC震荡器是不是出厂时已经校准的,测试结果是:当编程使用 ...

看数据手册可以从CLKO输出震荡频率,直接测量这个管脚的频率岂不是更方便和准确?
熔丝位编程后,系统时钟将从CLKO 输出。这种模式适用于芯片时钟用来驱动系
统内其它电路。即使芯片处于复位状态,此时钟还会被输出。对CKOUT 熔丝位编程后
I/O口的正常操作被切换为时钟输出。当CLKO作为时钟输出时,系统时钟可以为包括片内
RC 振荡器在内的所有时钟源。如果使用系统时钟预分频,输出的是被分频后的系统时钟
频率。

ldhavr 发表于 2013-3-29 11:23:32

经测试是可以自动装载校准值的,但是装载后的值误差依然很大,采用增加补偿的方法才能达到1%的准确度。
页: [1]
查看完整版本: 内部RC震荡器做USART通信到底有多可靠?