; This module services the real time interrupt ; It is also responsible for the "real world" thermometers ; ; CHANGE SINCE THE BOOK TEXT WAS FINALIZED: Idle_Time is used by the Operating System ; to override the report times defined in the Endpoint Descriptor. A device driver ; will modify Idle_Time to change the reporting characteristics of a HID device. ; During initialization the OS sets Idle_Time = 0 which turns reporting OFF unless ; a change is detected; an application that starts to poll a HID device will appear ; to hang. While it is possible to write extra PCHost application code to re-enable ; Idle_Time is it simpler to defeat this mechanism by IGNORRING the Idle_Time value. ; ; Get a Real Time interrupt every One millisecond (using SOF interrupt) ; ; We have one task = Read the thermometers ; We will poll the thermometers at 100msec intervals and store the temperatures ; directly in the EP1InBuffer. This way the PCHost will always get the latest ; temperature readings. ; ; The hardware for this example is shown in Figure 9-7. ; We are using Port A for Output ; CLK is on Bit0, DQ is on Bit1 and the thermometers are selected by Bits[7:2] ; ; The registers used in this routine are: ; A = Value written to Port A ; DPTR = Pointer to EP1InBuffer ; R0 = Pointer to PortA_Out ; R1 = Pointer to PortA_Config then PortA_Pins ; R2 = a save register ; R5 = Data to be sent, or received ; R6 = Thermometer selector ; R7 = Bit counter ; CSEG ServiceTimerRoutine: DJNZ Msec_counter, Done ; Only need to check every 100msec MOV Msec_counter, #100 ; Reinitialize ; MOV DPTR, #EP1InBuffer MOV R0, #Low(PortA_Out) MOV A, #00000100b ; Select pattern Loop: MOV R6, A MOV A, #00000001b ; Port A idle state ORL A, R6 MOVX @R0, A ; Select one of the thermometers MOV R5, #0AAH ; Get temperature command CALL SendByte CALL ReceiveByte MOV A, R6 ; Get select pattern CLR C ; Need to zero fill RLC A ; Rotate pattern JNZ Loop ; Check for ALARMs MOV DPTR, #EP1InBuffer ; Current temperature values MOV R0, #LimitValues ; Low limits MOV R1, #LimitValues+6 ; High limits MOV R5, #0 ; Alarm Value MOV R6, #00000001b ; Alarm mask MOV R7, #6 ; Counter LCLoop: MOVX A, @DPTR CLR C SUBB A, @R0 ; Check low limit JNC Over1 MOV A, R5 ; Need to set this ALARM bit ORL A, R6 MOV R5, A Over1: MOVX A, @DPTR CLR C SUBB A, @R1 ; Check upper limit JC Over2 MOV A, R5 ; Need to set this ALARM bit ORL A, R6 MOV R5, A Over2: MOV A, R6 ; Rotate Alarm mask RL A MOV R6, A INC DPTR ; Update pointers INC R0 INC R1 DJNZ R7, LCLoop MOV A, R5 ; Get Alarm byte MOVX @DPTR, A ; Store in Byte 7 of Report JMP CreateInputReport ; RETurn via CreateInputReport SendByte: ; Transmit a byte to a thermometer MOV R7, #8 SLoop: DEC A MOVX @R0, A ; Set CLK low XCH A, R5 ; Get the data to be sent RRC A ; Put LS bit in Carry XCH A, R5 MOV ACC.1, C ; Put data bit in DQ MOVX @R0, A INC A MOVX @R0, A ; Set CLK high DJNZ R7, SLoop RET ReceiveByte: ; Receive a byte from a thermometer MOV R7, #9 ; Actually we get 9 bits and discard bit0 MOV R2, A ; Save A while we reconfigure MOV R1, #Low(PortA_OE) MOV A, #11111101b MOVX @R1, A ; Set bit 1 as input MOV R1, #Low(PortA_Pins) MOV A, R2 ; Retreive A GLoop: DEC A MOVX @R0, A ; Set CLK low NOP ; Give thermomemter time to respond MOVX A, @R1 ; Read the data bit MOV C, ACC.1 ; Copy DQ into Carry XCH A, R5 RRC A ; Copy DQ into MSB XCH A, R5 INC A MOVX @R0, A ; Set CLK high DJNZ R7, GLoop MOV A, R5 ; Get the received temperature MOVX @DPTR, A ; Save in EPOInBuffer INC DPTR Done: RET