org 0 ; reset vector JMP main ; jump to the main program org 3 ; external 0 interrupt vector JMP ext0ISR ; jump to the external 0 ISR org 0BH ; timer 0 interrupt vector JMP timer0ISR ; jump to timer 0 ISR org 30H main: SETB IT0 ; set external 0 interrupt as edge-activated SETB EX0 ; enable external 0 interrupt MOV TMOD, #2 ; set timer 0 as 8-bit auto-reload interval timer MOV TH0, #-200 ; | put -200 into timer 0 high-byte - this reload value, ; | with system clock of 12 MHz, will result in a timer 0 overflow every 200 us MOV TL0, #-200 ; | put the same value in the low byte to ensure the timer starts counting from ; | 56 (256 - 200) rather than 0 SETB TR0 ; start timer 0 SETB ET0 ; enable timer 0 interrupt ; initialise the display ; see instruction set for details CLR P1.3 ; clear RS - indicates that instructions are being sent to the module ; function set CLR P1.7 ; | CLR P1.6 ; | SETB P1.5 ; | CLR P1.4 ; | high nibble set SETB P1.2 ; | CLR P1.2 ; | negative edge on E CALL delay ; wait for BF to clear ; function set sent for first time - tells module to go into 4-bit mode ; Why is function set high nibble sent twice? See 4-bit operation on pages 39 and 42 of HD44780.pdf. SETB P1.2 ; | CLR P1.2 ; | negative edge on E ; same function set high nibble sent a second time SETB P1.7 ; low nibble set (only P1.7 needed to be changed) SETB P1.2 ; | CLR P1.2 ; | negative edge on E ; function set low nibble sent CALL delay ; wait for BF to clear ; entry mode set ; set to increment with no shift CLR P1.7 ; | CLR P1.6 ; | CLR P1.5 ; | CLR P1.4 ; | high nibble set SETB P1.2 ; | CLR P1.2 ; | negative edge on E SETB P1.6 ; | SETB P1.5 ; |low nibble set SETB P1.2 ; | CLR P1.2 ; | negative edge on E CALL delay ; wait for BF to clear ; display on/off control ; the display is turned on, the cursor is turned off and blinking is turned off CLR P1.7 ; | CLR P1.6 ; | CLR P1.5 ; | CLR P1.4 ; | high nibble set SETB P1.2 ; | CLR P1.2 ; | negative edge on E SETB P1.7 ; | SETB P1.6 ; | low nibble set SETB P1.2 ; | CLR P1.2 ; | negative edge on E CALL delay ; wait for BF to clear ; set CGRAM address ; set to character 0, row 0 (address 000 000B) - all 8 CGRAM locations will be used to store the bar graph patterns CLR P1.7 ; | SETB P1.6 ; | CLR P1.5 ; | CLR P1.4 ; | high nibble set SETB P1.2 ; | CLR P1.2 ; | negative edge on E CLR P1.6 ; |low nibble set SETB P1.2 ; | CLR P1.2 ; | negative edge on E CALL delay ; wait for BF to clear ; put first bar symbol in RAM MOV 30H, #0 ; | Locations 30H to 37H in RAM will be used to store the bar graph patterns before sending them to CGRAM. MOV 31H, #0 ; | Start by putting 0 into all except the last one (37H). MOV 32H, #0 ; | R0 will be used to point to the last position. Then 11111B will be put into this location (using indirect MOV 33H, #0 ; | addressing via R0). This means the first pattern is all rows 0, except the last row all 1. MOV 34H, #0 ; | R0 will then be incremented, which means the next row (location 36H in RAM) gets 11111B. This results in the MOV 35H, #0 ; | first 6 rows all 0 and the last two all 1. Repeating 8 times results in the last pattern containing 11111B MOV 36H, #0 ; | in all rows. MOV 38H, #0FFH ; end of data - sendBar subroutine checks for FFH to see if all 8 rows have been sent. MOV R0, #37H ; point to highest bar (ie: 11111B) position ; send bar symbols to CGRAM SETB P1.3 ; set RS - indicates that data is being sent to module MOV R2, #8 ; 8 patterns need to be sent again: MOV @R0, #11111B ; R0 points to the next row (row location in RAM) where a bar (11111B) needs to be stored DEC R0 ; decrement R0 to point to next row for next iteration CALL sendPattern ; send the current pattern to CGRAM DJNZ R2, again ; repeat for 8 patterns SETB EA ; set the global interrupt enable bit JMP $ ; do nothing ;------------------------------------------------------------------------------- ; updateBarGraph subroutine updateBarGraph: CLR A ; | The bar graph has a max 16 rows (2 characters, 8 rows in each). MOV C, B.4 ; | Therefore, only the top 4 bits in B (outputs of ADC were transferred to B by ADC ISR) are used. MOV ACC.0, C ; | Of these 4 bits, the bottom 3 are placed in A, while the MSB is left in C. MOV C, B.5 ; | The bottom 3 bits (0 to 7) decide how many bars are displayed (ie; which of the patterns MOV ACC.1, C ; | in CGRAM are displayed), while the MSB decides which position to display it - MSB = 1, display MOV C, B.6 ; | on top line, MSB = 0, display on bottom line. MOV ACC.2, C ; | MOV C, B.7 ; | JC topLine ; if C is set, the voltage to the ADC is greater than 2.5V, therefore display on top line ; do the following if voltage to ADC is less than 2.5V CALL toBottom ; set DDRAM address to bottom line CALL sendCharacter ; the value in A (ranging from 0 to 7) points to the appropriate bar symbol in CGRAM CALL toTop ; set DDRAM address to top line MOV A, #' ' ; since the voltage to the ADC is less than 2.5V, the top line must be cleared (space character is used) CALL sendCharacter ; send space character to top line RET ; do the following if voltage to ADC is greater than 2.5V topLine: CALL toTop ; set DDRAM address to top line CALL sendCharacter ; the value in A (ranging from 0 to 7) points to the appropriate bar symbol in CGRAM CALL toBottom ; set DDRAM address to bottom line MOV A, #7 ; | since the voltage to the ADC is greater than 2.5V, the bottom line must get a full ; | bar graph symbol (location 7 in CGRAM) CALL sendCharacter ; send full bar graph to bottom line RET ; toTop subroutine - point to top row ; set DDRAM address to 0 toTop: CLR P1.3 ; clear RS - indicates that instructions are being sent to the module SETB P1.7 ; | CLR P1.6 ; | CLR P1.5 ; | CLR P1.4 ; | high nibble set SETB P1.2 ; | CLR P1.2 ; | negative edge on E CLR P1.7 ; low nibble set SETB P1.2 ; | CLR P1.2 ; | negative edge on E CALL delay ; wait for BF to clear RET ; toBottom subroutine - point to bottom row ; set DDRAM address to 40H toBottom: CLR P1.3 ; clear RS - indicates that instructions are being sent to the module SETB P1.7 ; | SETB P1.6 ; | CLR P1.5 ; | CLR P1.4 ; | high nibble set SETB P1.2 ; | CLR P1.2 ; | negative edge on E CLR P1.7 ; | CLR P1.6 ; | low nibble set SETB P1.2 ; | CLR P1.2 ; | negative edge on E CALL delay ; wait for BF to clear RET ; sendPattern subroutine - send bar pattern symbol to CGRAM sendPattern: MOV R1, #30H ; pattern is stored in RAM starting at location 30H loop: MOV A, @R1 ; move one row of pattern to A CJNE A, #0FFH, skip ; | check to see if A contains FFH - if yes RET ; | then all rows of pattern have been sent, therefore return skip: CALL sendCharacter ; send the pattern to the lcd module INC R1 ; increment R1 to point at next row in pattern JMP loop ; repeat RET ; sendCharacter subroutine sendCharacter: SETB P1.3 ; set RS - indicates that data is being sent to module MOV C, ACC.7 ; | MOV P1.7, C ; | MOV C, ACC.6 ; | MOV P1.6, C ; | MOV C, ACC.5 ; | MOV P1.5, C ; | MOV C, ACC.4 ; | MOV P1.4, C ; | high nibble set SETB P1.2 ; | CLR P1.2 ; | negative edge on E MOV C, ACC.3 ; | MOV P1.7, C ; | MOV C, ACC.2 ; | MOV P1.6, C ; | MOV C, ACC.1 ; | MOV P1.5, C ; | MOV C, ACC.0 ; | MOV P1.4, C ; | low nibble set SETB P1.2 ; | CLR P1.2 ; | negative edge on E CALL delay ; wait for BF to clear ; delay subroutine - used to allow LCD module carry out internal operation. delay: MOV R3, #50 DJNZ R3, $ RET ; timer 0 ISR - simply starts an ADC conversion timer0ISR: CLR P3.6 ; clear ADC WR line SETB P3.6 ; then set it - this results in the required positive edge to start a conversion RETI ; return from interrupt ; external 0 ISR - responds to the ADC conversion complete interrupt ext0ISR: CLR P3.7 ; clear the ADC RD line - this enables the data lines MOV B, P2 ; move ADC outputs to B SETB P3.7 ; disable the ADC data lines by setting RD CALL updateBarGraph ; update the bar graph using the new reading from the ADC RETI ; return from interrupt