还有一个关于延误的问题。因为我是一名首发球员,所以我对延迟的计算感到头疼。当有人在代码中解释延迟时,我理解延迟。但当谈到我的代码时,我完全一团糟。 (按延迟2天计算)。这是代码;我想在 pic16f676 上的任何端口引脚上每 1 秒闪烁一次 LED:
#include "p16F676.inc"
; CONFIG
; __config 0xFFFC
__CONFIG _FOSC_INTRCIO & _WDTE_ON & _PWRTE_OFF & _MCLRE_ON & _BOREN_ON & _CP_OFF & _CPD_OFF
usec EQU 0x20
sec EQU 0x23
UNKNOWN EQU 0x5F
org H'0000' ;Origem no endereço 00h de memória
goto INIT ;Desvia para a label início
; --- Vetor de Interrupção ---
org H'0004'
isr:
MOVWF 0x5E
; Reinit TMR0 : TMR0 = 8
MOVLW 8
MOVWF TMR0
; CLEAR TMR FLAG T0IF : T0IF=0
BCF INTCON, 2
; increase 1 microsec
; usec++; increase
;-----------------------------------------------------------------------------------------------------
MOVLW 0x1
ADDWF usec, F
MOVLW 0x0F
SUBWF usec, 0
MOVWF 0x51
BTFSS STATUS, 0
GOTO mangata
lalaind:
BCF STATUS, RP0 ; RA0=~RA0; // togle RA0
MOVLW 0x01
(MOVWF PORTA ); XORWF PORTA, F ==> replaced both
MOVLW 0
MOVWF usec
mangata:
BCF STATUS, 0x5
RETFIE
INIT:
BSF STATUS, 5
CLRF TRISA
; TRISA = 0x00;
CLRF TRISC
BCF STATUS, 5
CLRF PORTA
; PORTC = 0;
CLRF PORTC
; GIE = 1;
BSF INTCON, 7
; T0IF = 0;
BCF INTCON, 2
; T0IE = 1;
BSF INTCON, 5
; T0CS = 0;
BSF STATUS, 5
BCF OPTION_REG, 5 ;(INternal instruuction cycle clock) (clkout)
; PSA = 1;
BSF OPTION_REG, 3 ;Prescalar applied to WDT
; TMR0 = 8;
MOVLW 8
BCF STATUS, 0x5
MOVWF TMR0
CLRF usec
; while(1);
loop:
GOTO loop
end
除了延迟外,代码工作正常(在 MPLAB(MPASM) 中)。在正常 255 计数后,定时器 0 调用中断。 usec 减去 15:检查它是否被点燃(我认为当 usec > 15 时状态进位将切换)并在引脚 RA0 上点亮。我假设 DELAY = 255*(15*10) = 38250cycles(抱歉,如果我错了)。
让我们从现有代码的计算开始。
数据表第31页图4-1显示了相关详细信息:
T0CS
(定时器 0 时钟选择)设置为 0,选择 Fosc/4 作为输入频率。正如您在您的其他问题中评论的那样,振荡器频率为 4 MHz,因此 CLKOUT
为 1 MHz。这是每个周期一个时钟周期。PSA
(预分频器分配)设置为 1,将预分频器分配给看门狗。我们可以在原理图中看到,这会将输入时钟不分频路由到计时器。SYNC
块适用于从引脚 T0CKI
为计时器计时的情况。在这种情况下,它不会改变频率,因此定时器的时钟为 1 MHz。根据数据表,唯一“可见”的结果是写入 TMR0
寄存器后启动延迟 2 个周期。T0IF
。您已通过相应设置 T0IE
和 GIE
启用中断。TMR0
,将 0 写入 usec
。TMR0
重置为8。中断延迟为3个周期,3条指令各1个周期,以及提到的2个周期的同步延迟,这总共是8个周期。偶然(还是故意?)这正是您写入 TMR0
的值。CLKOUT
/ 256 = 1,000,000 赫兹 / 256 = = 3906.25 赫兹usec
从 0 计数到 14。PIC 有一种“反转”进位逻辑,如果有借位,则将 C
设置为 0。与您的分析相反,只要 usec
小于 15,进位标志就会被清除。subwf
从变量中减去 W
,并且如果 C
为 15(或更大),则设置 usec
。 现在要实现您的目标,您需要 1 秒的切换时间。为此,您有多种选择。这些是一些:
PS2
:PS0
设置为 111,选择 1:256。定时器的输入频率除以256。结果不完全是 1 秒,但相当接近。人类第一眼不会注意到差异。
备注:
您可能希望推迟启用中断,直到一切准备就绪。否则,根据情况,可能会发生不需要的中断。
由于每次溢出时都会向
TMR0
写入8,因此可以考虑避免这种情况并让计时器运行完毕。它将产生相同的溢出率。
如果您想要精确的时间(在晶体允许的范围内),请更改计时器的重载值,以便它例如每 200 个周期中断一次。然后除以变量再除以 5000 (200 * 5000 = 1000000)。或者使用 1:64 的预分频器,让计时器除以 125。使用另一个 125 的软件分频器,您可以达到相同的目标 (64 * 125 * 125 = 1000000)。秘密在于整数因数乘以 1000000。