;************************************************************************** ; 87C752 A/D and PWM Demonstration Program ; This program first reads all five A/D channels and outputs the values in ; hexadecimal as RS-232 data. It then programs the PWM output to reflect ; the value on A/D channel 0, and again outputs the A/D value to RS-232. ; Note that the A/D value is inverted before being moved to the PWM ; compare register in order to compensate for the inversion on the PWM ; output pin. This process is repeated continuously. ; Thus, a voltage may be applied to ADC0 (P1.0, pin 13) to vary the PWM ; pulse width. ; A simple test of this function is to measure the voltage on ADC0 and PWM ; with a voltmeter. The meter should integrate the waveform on PWM and ; read a voltage within about 20mV of that on ADC0. ; The RS-232 output appears on Port 1 pin 5, which must be buffered with ; an MC1488 or perhaps a MAX232 chip prior to being connected to a ; terminal. The transmission rate with a 16MHz crystal will be 9600 baud. ;************************************************************************** $Title(87C752 A/D and PWM Test) $Date(07/26/89) $MOD752 ;************************************************************************** BaudVal EQU -139 ;Timer value for 9600 baud @ 16 MHz. ;(one bit cell time) XmtDat DATA 10h ;Data for RS-232 transmit routine. BitCnt DATA 12h ;RS-232 transmit bit count. Flags DATA 20h TxFlag BIT Flags.0 ;Transmit-in-progress flag. ADFlag BIT Flags.1 ;A/D conversion complete flag. TxD BIT P1.5 ;Port bit for RS-232 transmit. ;************************************************************************** ; Interrupt Vectors ORG 0 ;Reset vector. AJMP Reset ORG 0BH ;Timer 0 interrupt. AJMP Timr0 ;Baud rate generator. ORG 2Bh ;A/D conversion complete interrupt. SETB ADFlag ;Tell mainline. RETI ;***************************************************************************** Reset: MOV SP,#30h MOV Flags,#0 ;Clear RS-232 flags. MOV TCON,#00h ;Set up timer controls. MOV IE,#82h ;Enable timer 0 interrupt. MOV DPTR,#Msg1 ;Point to message string. ACALL Mess ;Send message. MOV R1,#0 ;Start with A/D channel 0. Loop1: MOV A,R1 ACALL ADConv ;Start A/D conversion. MOV R2,A MOV DPTR,#Msg2 ;Point to message string. ACALL Mess ;Send message. MOV A,R1 ACALL PrByte ;Print channel #. MOV DPTR,#Msg3 ;Point to message string. ACALL Mess ;Send message. MOV A,R2 ACALL PrByte ;Print A/D value. INC R1 ;Advance R1 value. CJNE R1,#5,Loop1 MOV DPTR,#CRLF ;Point to message string. ACALL Mess ; Now use A/D channel 0 value to control the PWM. MOV IE,#0C2h ;Now enable the A/D interrupt. MOV PWMP,#80h ;Set up PWM prescaler. MOV PWCM,#0 ;Set initial PWM value. MOV PWENA,#01h ;Start PWM. Loop2: MOV A,#0 ;Read A/D channel 0. ACALL ADStart ;Start A/D conversion. JNB ADFlag,$ ;Wait for A/D conversion complete. MOV A,ADAT CPL A ;Complement the value for the PWM. MOV PWCM,A ;Set PWM value. ACALL PrByte ;Print PWM value. MOV DPTR,#Msg4 ;Point to message string. ACALL Mess SJMP Loop2 ; A/D Conversion Routines. ; The following shows two ways to use the A/D. Both routines are used by ; different portions of the sample program. ; Method 1: This version of the routine starts the conversion and then ; returns. The mainline program can detect when the conversion is ; complete by checking the A/D conversion complete flag (ADFlag) which is ; set by the A/D interrupt service routine. A/D data must be read by the ; calling routine. ADStart: CLR ADFlag ;Clear A/D conversion complete flag. ORL A,#28h ;Add control bits to channel #. MOV ADCON,A ;Start conversion. RET ; Method 2: This is an alternative version of the A/D routine which ; starts the conversion and then waits for it to complete before ; returning. A/D data is returned in the ACC. ADConv: ORL A,#28h ;Add control bits to channel #. MOV ADCON,A ;Start conversion. ADC1: MOV A,ADCON JNB ACC.4,ADC1 ;Wait for conversion complete. MOV A,ADAT ;Read A/D. RET ; Send a byte out RS-232 and wait for completion before returning. XmtByte: ACALL RSXmt ;Send ACC to RS-232 output. JB TxFlag,$ ;Wait for transmit complete. RET ; Begin RS-232 transmit. RSXmt: MOV XmtDat,A ;Save data to be transmitted. MOV BitCnt,#10 ;Set bit count. MOV TH,#High BaudVal ;Set timer for baud rate. MOV TL,#Low BaudVal MOV RTH,#High BaudVal ;Also set timer reload value. MOV RTL,#Low BaudVal SETB TR ;Start timer. CLR TxD ;Begin start bit. SETB TxFlag ;Set transmit-in-progress flag. RET ; Timer 0 timeout: RS-232 receive bit or transmit bit. Timr0: PUSH ACC PUSH PSW JB TxFlag,TxBit ;Is this a transmit timer interrupt? T0Ex1: CLR TR ;Stop timer. T0Ex2: POP PSW POP ACC RETI ; RS-232 transmit bit routine. TxBit: DJNZ BitCnt,TxBusy ;Decrement bit count, test for done. CLR TxFlag ;End of stop bit, release timer. SJMP T0Ex1 ;Stop timer and exit. TxBusy: MOV A,BitCnt ;Get bit count. CJNE A,#1,TxNext ;Is this a stop bit? SETB TxD ;Set stop bit. SJMP T0Ex2 ;Exit. TxNext: MOV A,XmtDat ;Get data. RRC A ;Advance to next bit. MOV XmtDat,A MOV TxD,C ;Send data bit. SJMP T0Ex2 ;Exit. ; Print byte routine: print ACC contents as ASCII hexadecimal. PrByte: PUSH ACC SWAP A ACALL HexAsc ACALL XmtByte POP ACC ACALL HexAsc ;Print nibble in ACC as ASCII hex. ACALL XmtByte RET ; Hexadecimal to ASCII conversion routine. HexAsc: ANL A,#0FH ;Convert a nibble to ASCII hex. JNB ACC.3,NoAdj JB ACC.2,Adj JNB ACC.1,NoAdj Adj: ADD A,#07H NoAdj: ADD A,#30H RET ; Message string transmit routine. Mess: PUSH ACC MOV R0,#0 ;R0 is character pointer (string Mesl: MOV A,R0 ; length is limited to 256 bytes). MOVC A,@A+DPTR ;Get byte to send. CJNE A,#0,Send ;End of string is indicated by a 0. POP ACC RET Send: ACALL XmtByte ;Send a character. INC R0 ;Next character. SJMP Mesl Msg1: DB 0Dh, 0Ah, 'This is a test of the 87C752 A/D and PWM.' CRLF: DB 0Dh, 0Ah, 0 Msg2: DB 0Dh, 0Ah, 'A/D Channel ', 0 Msg3: DB ' = ', 0 Msg4: DB ' ', 0 END