+------------------------------------------------------------------------+ | 06 / Timers, UART and interrupts | +------------------------------------------------------------------------+ BASELINE SFR DESK REFERENCE (BYTE ADDRESSES) 80 P0 81 SP 82 DPL 83 DPH 87 PCON 88 TCON 89 TMOD 8A TL0 8B TL1 8C TH0 8D TH1 90 P1 98 SCON 99 SBUF A0 P2 A8 IE B0 P3 B8 IP D0 PSW E0 ACC F0 B Bit-addressable: P0, TCON, P1, SCON, P2, IE, P3, IP, PSW, ACC, B. SP resets to 07 and port latches to FF. Reset is not an instruction to clear all RAM. TIMER 0 AND TIMER 1 TMOD has one four-bit field per timer: Timer 1 in bits 7-4, Timer 0 in bits 3-0. Each field is GATE, C/T, M1, M0. GATE=1 requires the corresponding INT pin high AND TRn set. C/T=0 counts internal machine cycles; C/T=1 counts sampled falling edges on T0/T1. Mode 0 is a 13-bit counter (THn plus the low five bits of TLn); mode 1 is 16-bit; mode 2 is 8-bit auto-reload from THn into TLn. Mode 3 splits Timer 0 into two 8-bit timers: TL0 keeps Timer 0 controls, TH0 borrows TR1/TF1. Timer 1's normal interrupt/control use is consequently restricted; do not treat mode 3 as two independent ordinary 16-bit timers. Timer 1 mode 3 stops its counting. TCON bits: TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0. TRn starts a timer; TFn records overflow. Timer overflow flags are cleared on hardware interrupt vectoring; polling code must clear them itself. Stop the timer before making a coherent multi-byte configuration change. BARE-METAL POLLED TIMER (NOT DOS/51 INITIALIZATION) anl 0x89,#0xF0 ; preserve Timer 1 mode orl 0x89,#0x01 ; Timer 0 mode 1, internal clock clr 0x8C ; TR0 (bit address) mov 0x8C,#0xFC ; TH0 (byte address) mov 0x8A,#0x66 ; TL0: 65536 - 922 clr 0x8D ; TF0 (bit address) setb 0x8C wait0: jnb 0x8D,wait0 clr 0x8C clr 0x8D At 11.0592 MHz, 922 ticks are approximately 1 ms. Polling/setup overhead makes this NOT an exact 1-ms software delay. For periodic precision use a suitable reload strategy and account for interrupt latency. External event counting is sampled, so input edge rate and pulse widths must meet the chip timing requirements. UART: SCON = SM0 SM1 SM2 REN TB8 RB8 TI RI Mode 0: synchronous shift register, normally fosc/12. Mode 1: 8-bit UART with start/stop bits, variable baud. Mode 2: 9-bit UART, fixed fosc/64 or fosc/32 via SMOD. Mode 3: 9-bit UART, variable baud. REN enables reception. Write SBUF to transmit; read SBUF to retrieve the separately buffered received byte. RI and TI share one interrupt vector and are cleared by SOFTWARE, not by reading SBUF or entering the ISR. Mode 1's RB8 reflects the received stop bit when appropriate; modes 2/3 use TB8/RB8 for the ninth data bit and SM2 for multiprocessor filtering. With Timer 1 mode 2, UART modes 1/3 use: baud = (2^SMOD * fosc) / (384 * (256 - TH1)). At 11.0592 MHz: TH1=FD and SMOD=0 gives 9600; TH1=FD and SMOD=1 gives 19200; TH1=FF and SMOD=1 gives 57600. Arbitrary baud rates are not all representable. BARE-METAL 9600-BAUD SETUP (11.0592 MHz) anl 0x87,#0x7F ; clear SMOD, preserve other PCON bits anl 0x89,#0x0F orl 0x89,#0x20 ; Timer 1 mode 2 mov 0x8D,#0xFD ; TH1 reload mov 0x8B,#0xFD ; TL1 initial count mov 0x98,#0x50 ; mode 1, REN=1, RI/TI=0 setb 0x8E ; TR1 Do not run that setup inside DOS/51: its console is already 57600 baud, and Timer 1 belongs to it. To poll reception, wait for RI, read SBUF and clear RI. A polled transmitter writes SBUF, waits for TI and clears TI; ensure TI was not left set by an earlier transmission. At higher throughput handle overrun in software: there is no general-purpose deep hardware FIFO. INTERRUPTS Reset jumps to 0000. Baseline vectors: INT0=0003, Timer0=000B, INT1=0013, Timer1=001B, serial=0023. Each vector is normally a short LJMP stub because adjacent entries are only eight bytes apart. IE.7 (EA) globally enables requests; IE bits 0-4 enable EX0, ET0, EX1, ET1 and ES. IP bits select low/high priority in the baseline core. A high-priority handler can preempt a low-priority handler, not vice versa; equal-priority service is not reentrant. Fixed polling order resolves simultaneous equal-priority requests in the vector order above. IT0/IT1=1 selects falling-edge external interrupts; zero selects active-low level requests. Release a level-triggered request before returning or it can immediately retrigger. Switch bounce requires debouncing. Hardware pushes PC only. Save every clobbered register including PSW as necessary; restore in reverse order and finish with RETI so the interrupt controller releases its in-service state. RET alone is not an interrupt return. Serial ISRs test BOTH RI and TI. A register-bank switch can reduce saves, but each nested priority level needs a nonconflicting bank and RAM allocation. On DOS/51 the lower CODE vectors are in ROM. An application at 8000 cannot patch them just by writing that numerical XDATA address. Use documented firmware facilities or a different ROM build rather than assuming vector ownership. [ DOS/51 FIELD MANUAL | IMANIA.DK | 2026-11-14 ]