我正在尝试在 PIC18F13k22 中使用timer0模块。
我想要做的就是打开 LED,然后在
TMR0IF == 1
时关闭,并在 PROTEUS 中对其进行模拟。这是一场斗争,我确信我只是错过了一些简单的东西。
我已经使用了延迟功能,并成功地打开和关闭了不同的LED。但现在尝试使用定时器,LED 亮起,但保持亮起状态,并且模拟没有其他变化。我尝试过使用
PORTBbits.RB4
并且同样没有发生任何变化。我正在使用 PROTEUS 8 和 MPLAB X IDE。
LED 通过 220R 电阻连接到引脚 RB4/LB4 和 GND。
void main(void)
{
TRISB = 0;
PORTB = 0;
T0CON = 0x07;
T0CONbits.T08BIT = 1;
T0CONbits.T0PS = 0b111;
T0CONbits.PSA = 0;
T0CONbits.T0SE = 1;
INTCONbits.TMR0IE = 1;
T0CONbits.T0CS = 0;
TMR0H = 0xFF;
TMR0L = 0x00;
T0CONbits.TMR0ON = 1;
while (1)
{
LATBbits.LB4 = 1;
if (TMR0IF == 1)
{
LATBbits.LB4 = 0;
TMR0IF = 0;
T0CONbits.TMR0ON = 0;
}
}
}
实际上 LED 发生了变化,但我们看不到,因为变化发生得太快了。让我们先编写
while
循环的逐步文本算法,看看会发生什么。
while
循环从这里开始您在上面的步骤中看到了什么吗?尤其是第4步?
B4实际上设置为低电平,但是经过一些指令后,B4又设置回高电平!
如果我们假设您使用 4 MHz 的振荡器频率,则指令周期时间将为 1/(4000000/4) = 1 微秒。考虑到该指令周期时间,在将 B4 设置为低状态和将 B4 设置回高状态之间只有 2 条指令。也就是说,如果我们计算汇编分支指令,那么只有 2 条可见指令,总共 4 条指令,这样流程就从
while
循环继续进行。 4 条指令使输出状态变化之间有 4 微秒的延迟,使其对我们来说非常不可见。
此外,代码的逻辑对于实现您的目标来说有些问题。如果你想在定时器溢出后关闭LED并直观地看到效果,你不应该无限循环。方法如下:
// Set B4 high once
LATBbits.LB4 = 1;
// Now wait for the Timer to overflow
while(TMR0IF == 0)
;
// If the flow reached here, then timer has overflowed
TMR0IF = 0;
T0CONbits.TMR0ON = 0;
// Set B4 low
LATBbits.LB4 = 0;
// Halt here
while(1)
;
如果您的要求意味着您要循环,那么此代码不完整,无法完成这项工作。如果我们考虑您的评论:
我试图让它关闭,以响应当 TMR0H 溢出到 TMR0L 的值时触发的溢出标志。然后我希望计时器模块也关闭以节省电量以了解此功能。
您可以让处理器进入睡眠状态以节省电量。那么带有循环的代码将完成如下:
while (1)
{
LATBbits.LB4 = 1;
if (TMR0IF == 1)
{
LATBbits.LB4 = 0;
TMR0IF = 0;
T0CONbits.TMR0ON = 0;
// Put the processor to sleep (power saving)
SLEEP();
}
}
但是这一次,当处理器从省电状态唤醒时,LED 会亮起,但不会关闭,因为定时器被禁用。因此计时器应该保持运行。您不必关心定时器,因为当系统通过睡眠指令进入省电状态时,定时器的振荡器电源将自动切断,并且定时器无法继续在睡眠状态下运行。除非另有说明,否则您不会通过 IO 引脚从外部向定时器时钟供电。
在数据表中,第 9.4 节:
由于 Timer0 在休眠模式下关闭,TMR0 中断无法将处理器从休眠状态唤醒
即使不使用中断,定时器关闭也是有效的。因此,我们可以省略禁用计时器以获得所需的行为。最终代码如下:
while (1)
{
LATBbits.LB4 = 1;
if (TMR0IF == 1)
{
LATBbits.LB4 = 0;
TMR0IF = 0;
// Put the processor to sleep (power saving)
SLEEP();
}
}