【问题标题】:Why is Timer1 not counting up on PIC18?为什么 Timer1 不计算 PIC18?
【发布时间】:2026-02-10 01:00:01
【问题描述】:

最初我让 Timer0 在运行模式下工作正常。唯一的问题是当设备进入睡眠模式时,Timer0 停止计数直到唤醒。在数据表中,它说使用 Timer1 能够在睡眠模式下监控时间。 我将 timer0 现有代码修改为 timer1 新配置,其他代码几乎相同。但是,我可能错过了一些关于 timer1 与 timer0 的不同之处,因为 timer1 根本没有计数。我使用的 PIC 是带有 MPLAB C18 的 PIC18F87J11

我将分享看起来相关的代码,并根据需要添加更多代码。

Timer0 片段代码(来自头文件)

#define TMR_IF          INTCONbits.TMR0IF
#define TMR_IE          INTCONbits.TMR0IE
#define TMR_IP          INTCON2bits.TMR0IP
#define TMR_ON          T0CONbits.TMR0ON
#define TMR_CON         T0CON
#define TMR_L           TMR0L
#define TMR_H           TMR0H 

Timer0(来自 C 文件)

TMR_CON = 0b00000000 | CLOCK_DIVIDER_SETTING;
TMR_IP = 1;
TMR_IF = 0;
TMR_IE = 1;
TMR_ON = 1;

Timer0(我在其中增加时间)

if(TMR_IF)
        {
        printf("\r\n Passed here");
        timer_counter_high++; 
        }

输出:通过这里


Timer1 片段代码(来自头文件)

#define TMR_IF          PIR1bits.TMR1IF
#define TMR_IE          PIE1bits.TMR1IE
#define TMR_IP          IPR1bits.TMR1IP
#define TMR_ON          T1CONbits.TMR1ON
#define TMR_CON         T1CON
#define TMR_L           TMR1L
#define TMR_H           TMR1H

Timer1(来自 C 文件)

TMR_CON = 0b11101101 | CLOCK_DIVIDER_SETTING;
TMR_IP = 1;
TMR_IF = 0;
TMR_IE = 1;
TMR_ON = 1;

Timer1(我在其中增加时间)

   if(TMR_IF)
        {
        printf("\r\n Passed here");
        timer_counter_high++; 
        }
        else
        {
        printf("\r\n Did not come through");
        }

输出:没有通过

编辑:按要求添加了 CLOCK_DIVIDER_SETTING 代码。这被用于 timer0 和 timer1

#elif(CLOCK_FREQ <= 8000000)
        #define CLOCK_DIVIDER 32
        #define CLOCK_DIVIDER_SETTING 0x04
        #define SYMBOL_TO_TICK_RATE 8000000

我仍然没有将设备置于睡眠模式以在这种情况下测试 timer1,首先我必须弄清楚为什么 timer1 在运行模式下不计数。我将不胜感激与我的问题相关的任何帮助或想法,谢谢!

编辑 2:我喜欢回答的一些问题

Q1:Timer1 还能像 timer0 一样与内部振荡器一起使用吗?

Q2:您如何计算 T1CON 的正确 CLOCK_DIVIDER_SETTING ? (如果设置了 T1SYNC 和预分频器,我需要它吗?)

【问题讨论】:

  • 我需要外部晶体来让 timer1 工作还是发生了什么?
  • 属于electronics.stackexchange.com
  • CLOCK_DIVIDER_SETTING 在每种情况下都使用什么?
  • @SimonJenkins,我更新了帖子。
  • 我还是希望能得到一些答案,我需要朝着正确的方向前进。我迷路了!

标签: c embedded microcontroller pic microchip


【解决方案1】:

根据PIC18F87J11 FAMILY datashet,如果您要设置来自 Timer1 振荡器的 Timer1 时钟(通过设置 T1CON 寄存器中的 T1RUN 位来实现),则需要在 T1OSO 和 T1OSI 引脚上添加外部晶振。

另外请注意,虽然将 CLOCK_DIVIDER_SETTING 分配给 T0CON 寄存器可以正确设置时钟预分频器,但由于位位置不同,将相同的 CLOCK_DIVIDER_SETTING 分配给 T1CON 寄存器是错误的(在这种情况下,您实际上是在设置您已经设置的位 T1SYNC)和不同大小的预分频器。

我还希望您在启用定时器之前在代码中的某处设置寄存器 TMR1H、TMR1L、TMR0L 和 TMR0H。

编辑添加了其他问题的答案。

1:是的,Timer1 有两个时钟源——外部振荡器和内部时钟(Fosc/4)。要启用内部时钟,您必须清除 T1CON 寄存器中的 TMR1CS 位。

请注意,在睡眠期间,除了 Timer1 振荡器和 INTRC(31 kHz 时钟,Timer1 不能使用)之外,所有时钟都被禁用,因此只有当 Timer1 由外部振荡器提供时钟时,您才能在睡眠期间使用 Timer1 测量时间。

2: T1CKPS 位是 T1CON 寄存器中的第 4 位和第 5 位,因此只需将时钟分频器设置移动 4 位就可以了。请记住,Timer1 时钟预分频器只有 2 位宽,它可以将时钟除以最大因子 8。

如果使用内部时钟,则忽略 T1SYNC 位。如果您计划在睡眠模式下将外部振荡器与 Timer1 一起使用,则应设置 T1SYNC 以禁用外部时钟输入的同步(在睡眠期间外部时钟无法同步,因为没有要同步的内部时钟,并且 Timer1 不会计数)。

Timer1 的配置应该是这样的

#define CLOCK_DIVIDER_SETTING_T1 0x03 // divide clock by 8 (T1_clock/8)

// RD16 cleared
// T1OSCEN set - Timer1 oscillator is enabled
// T1SYNC set - Does not synchronize external clock input
// TMR1CS set - External clock from the RC0/T1OSO/T13CKI pin (on the rising edge)
// TMR1ON cleared - wait with enabling Timer1 until everything is configured
TMR_CON = 0b00001110 | (CLOCK_DIVIDER_SETTING_T1<<4);
TMR_IP = 1;
TMR_IF = 0;
TMR_IE = 1;
TMR_ON = 1;

如果要使用内部时钟,则 T1_clock = Fosc/4。

如果使用内部振荡器作为系统时钟,则可以通过写入 OSCCON 寄存器中的 IRCF 位来更改系统时钟的后分频器,但这会影响整个微控制器的速度。

默认设置为 4 MHz,因此 T1_clock 为 1 MHz,经过 T1 预分频器后为 125 kHz。

【讨论】:

  • 看起来你对上面提到的一切都是正确的。我添加了一些问题,请在我将您的答案标记为解决方案之前帮我回答。谢谢!