我有PIC18F87J11 8 MHz振荡器,我使用timer1作为实时时钟。此刻,我每隔1分钟切换一次LED。我注意到它在前几次确实工作得非常好但是慢慢地它每隔59秒开始切换LED。然后每隔几分钟它就会一直下降到58,57等。我不知道使用内部振荡器或者我需要外部振荡器是否无法获得准确的时钟。我的设置看起来适合timer1,我希望我能用当前的硬件来解决这个问题。
预分频器1:8,TMR1预载= 15536,实际中断时间:200 ms
// Timer 1 Settings
RCONbits.IPEN = 1; // Enable interrupt system priority feature
INTCONbits.GIEL = 1; // Enable low priority interrupts
// 1:8 prescalar
T1CONbits.T1CKPS1 = 1;
T1CONbits.T1CKPS0 = 1;
// Use Internal Clock
T1CONbits.TMR1CS = 0;
// Timer1 overflow interrupt
PIE1bits.TMR1IE = 1;
IPR1bits.TMR1IP = 0; // Timer 1 -> Low priority interrupt group
PIE1bits.TMR1IE = 1; // Enable Timer1 interrupt
// TMR1 Preload = 15536;
TMR1H = 0x3C;
TMR1L = 0xB0;
中断例程
void interrupt low_priority lowISR(void) {
if (PIR1bits.TMR1IF == 1) {
oneSecond++;
if (oneSecond == 5) {
minute_Counter++;
if (minute_Counter >= 60) {
// One minute passed
Printf("\r\n One minute Passed");
ToggleLed();
minute_Counter = 0;
}
oneSecond = 0;
}
// TMR1 Preload = 15536;
TMR1H = 0x3C;
TMR1L = 0xB0;
PIR1bits.TMR1IF = 0;
}}
答案 0 :(得分:3)
在datasheet you linked,“2.5.3内部振荡器输出频率和调整”中有一些内容,在第38页
数据表说明了
INTOSC频率可能会随着V DD 或温度变化而漂移“。
V DD 且温度稳定吗?
它指出了通过调整OSCTUNE寄存器来解决这个问题的三种方法。他们三个需要外部“振荡器”:
答案 1 :(得分:3)
内部振荡器是一个简单的RC振荡器(电阻/电容时间常数决定其频率),这种电路在器件的工作温度范围内可能精确到+/- 10%,并且器件将由于正常工作功耗而自热。
从数据表中:
需要外部晶振或其他精确的外部时钟源才能获得精确的时序。或者,如果您有其他稳定且精确但低频的时钟源,例如具有38768 Hz晶振的RTC输出,您可以使用它来校准内部RC振荡器并使用OSCTUNE寄存器动态调整它 - 使用一个由低频源门控的定时器,你可以确定INTOSC的实际频率并进行相应的调整 - 它不会很完美,但会更好 - 但不会比校准源的精度更好。
某些设备配有芯片温度传感器,也可用于补偿,但您的设备无法使用。
RC错误可能导致串行通信失误,导致您无法使用异步(UART)串行通信与设备通信。
答案 2 :(得分:0)
定时器到期后重新加载定时器,定时器溢出和重新定时之间的延迟会影响总时间。所以这将解决你的问题。
void interrupt low_priority lowISR(void)
{
if (PIR1bits.TMR1IF)
{
PIR1bits.TMR1IF = 0;
TMR1H = 0x3C;
TMR1L = 0xAF;
/* rest of the code here */
. . . .
}
}
还有一个建议是不要加载isr,保持简单。
答案 3 :(得分:-1)
对于所有计时、时间和频率应用,首先要做的也是最重要的事情是校准晶体振荡器!!!振荡器本身及其晶体必须精确运行(优于百万分之一 = 1ppm)其标称频率。直接从工厂生产出来的晶体(除了一些非常专业和昂贵的晶体 = 100 美元)并没有完全以其标称频率运行。如果未完成校准,所有时间和频率相关功能将关闭,因为振荡器频率用作所有 PIC 内部功能的参考。必须通过调整从晶体引脚到地的电容器之一,针对准确的频率计数器进行校准。任何用于频率(和时间)校准的处理器例程都不够准确。