« PIC Memory Organization & EEPROM ControlIntro to the HD44780 character based LCD »

Accelerate

01/31/09 | by anthony [mail] | Categories: Code, Projects

The project:

This project is a simple but fun one. We are going to be using a tri-axis accelerometer to collect analog data from and then display it on the LCD. Our output on the LCD will look like:

|X||:|| ||Digit1||Digit2||Digit3|
|Y||:|| ||Digit1||Digit2||Digit3|
|Z||:|| ||Digit1||Digit2||Digit3|

The X:, Y:, and Z: are all static and only have to be sent once. (once you update the DDRAM address it stays there until power is cut) The digits however, have to be updated as we get new values, thus it is dynamically updated in our code and sent periodically.

This algorithm is fairly simple and works automatically. The procedure goes:

-Initialize the MCU
-Initialize the LCD
-Draw the static information
-Collect the analog information
-Convert the raw data into digits
-Display the data on the LCD.

The Code:

The Code:  #include p16F690.inc
     __config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF)
org 0              ; Begginning of code
cblock 0x20
	CHARLOCATION
	RESULT
	ONES	
	TENS
	HUNDREDS
	TEMP
	DELAY1
	DELAY2
	COUNT
endc
PORTS:
	bsf       STATUS,RP1     ; Bank 2
	movlw     0x14           ; RA2 & 4 Configured for analog AN2,3
	movwf     ANSEL          ; 
	movlw     0x08           ; RB5 configured for analog (AN11)
	movwf     ANSELH
	bcf       STATUS,RP1
	bsf       STATUS,RP0     ; select Register Page 1
	movlw     0x00           ; Move the hex value of 0 to multi purpose register W
    movwf     TRISC          ; make IO PortC all output
	movlw     0x16           ; Make Ra4,2 and 1 Input
	movwf     TRISA
	movlw     0x20           ;RB5 Input
	movwf     TRISB
	movlw     0x10           ;set A2d Clock 
    movwf     ADCON1
	bcf       STATUS,RP0     ;Exit bank 1
	;initialize 
	clrf      PORTC
	clrf      PORTA
	clrf      PORTB
	clrf      COUNT
	clrf      TEMP
	call      INITIALIZELCD
	call      DRAWLCD
MAIN:                                           ; Our MAIN routine gets the analog value off a port, and updates the LCD with the info
	movlw     0x41                             
	movwf     ADCON0     ;Channel 2
	call      A2D        ;Get A2D value
	movwf     RESULT
	movlw     0x83       ;Char position 03
	call      UPDATELCD  ;Call Update LCD, having the char position in W
	movlw     0x4D  
	movwf     ADCON0     ;Channel 3
	call      A2D
	movwf     RESULT
	movlw     0xC3       ;Char Position 43
	call      UPDATELCD	
	movlw     0x6D  
	movwf     ADCON0     ;Channel 11
	call      A2D
	movwf     RESULT
	movlw     0x97      ;Char position 17
	call      UPDATELCD
	call      DELAY
	goto 	  MAIN      ; Return to main
A2D:
	nop 
	nop
	nop
	nop
	nop                 ; wait 5 uS
	bsf       ADCON0,GO ; Start the conversion
	btfss     ADCON0,GO ; Bit will stay high untill conversion is complete
	goto      $-1       ; Untill then keep going back
    movf      ADRESH,w
	return
INITIALIZELCD:          ;Initialization Routine for the LCD
	bsf       PORTC,0   ;Put CMD 0 on port C
	call      SEND      ;Call Send routine, Sends command and waits for busy flag
  	movlw     0x38      ; Set Function, 8 Bit, 5X10 Dots, Two line
  	movwf     PORTC
	call      SEND
	movlw     b'00001100' ; Turn on the Display (0x0B
	movwf     PORTC
	call      SEND
        movlw     0x06       ; Set entry mode to: Increment Adress counter, no shift.
	movwf     PORTC
	call      SEND
	return
DRAWLCD:                 ; Routine which draws static display
	movlw     0x80       ; Start with the DDRAM address 0x00
	call      WRITELOC   ; Call Function to write the DDRAM address
	movlw     'X'        ;Move the ASCII value of 'X' to W
	call      WRITECHAR  ; Call function to write the Char to DDRAM address
	movlw     0x3A       
	call      WRITECHAR
	movlw     0xC0       
	call      WRITELOC
	movlw     'Y'
	call      WRITECHAR
	movlw     0x3A
	call      WRITECHAR
	movlw     0x94       
	call      WRITELOC
	movlw     'Z'
	call      WRITECHAR
	movlw     0x3A
	call      WRITECHAR  ; Continue untill all static elements drawm
	return
WRITECHAR:               ; Function to write a characture 
	movwf     TEMP       ; Move value to temp register
	call      BUSYCHK    ; Check Busy flag
	bsf       PORTA,0    ; Turn on Data 
	movfw     TEMP       ; Move from Temp to W
	movwf     PORTC      ; Then to PORTC
	call      SEND       ; Send
	bcf       PORTA,0    ; Turn off Data
	return
WRITELOC:
	movwf     TEMP       ;Move value to temp
	call      BUSYCHK    ;Check busy flag
	movfw     TEMP       ;Temp -> W
	movwf     PORTC      ;W -> Portc
	call      SEND       ;SEND
	return
UPDATELCD:               ; Routine to update the dynamic elements of the LCD
	call      WRITELOC   ; Init the LCD at the proper DDRAM location
	clrf      ONES       ; Clear Vars
	clrf      TENS
	clrf      HUNDREDS
	call      CALCULATE  ; Call calculate routine which takes raw A2D value and separates them into digits
	movfw     HUNDREDS   ; Write the Hundreds digit to the LCD
	call      TABLE1
	call      WRITECHAR
	movfw     TENS       ;Write Tens
	call      TABLE1
	call      WRITECHAR
	movfw     ONES       ;Write Ones
	call      TABLE1
	call      WRITECHAR
	return
CALCULATE:               ; Basic math routine, takes Result from A2D and separates into 1's 10's and 100's
	movlw     0x00
	bcf       STATUS,2
	xorwf     RESULT,w
	btfsc     STATUS,2
	return    
	movlw     0x0A
	bcf       STATUS,2
	subwf     ONES,w
	btfsc     STATUS,2
	goto      UPDATETENS
	decf      RESULT,f
	incf      ONES,f
	goto      CALCULATE
UPDATETENS:
	clrf      ONES
	incf      TENS,f
	movlw     0x09
	bcf       STATUS,2
	subwf     TENS,w
	btfsc     STATUS,2
	call      UPDATEHUNS
	decf      RESULT,f
	goto      CALCULATE
UPDATEHUNS:
	clrf      TENS
	incf      HUNDREDS,f
	movlw     0x09
	bcf       STATUS,2
	subwf     HUNDREDS,w
	btfsc     STATUS,2
	incf      HUNDREDS,f
	return
SEND:                         ;Use this routine to send a command to the LCD. Placement doesnt matter as it does two BSYFLG checks
	;Send
	bsf       PORTB,4         ; Set E line High
	nop       
	nop
	nop
	nop
	bcf       PORTB,4         ;Wait a bit then set it low, sending command to LCD
BUSYCHK:
	bsf       STATUS,RP0      ; Port C, all input
	movlw     0xff	
	movwf     TRISC
	bcf       STATUS,RP0
	bsf       PORTA,5         ;Set Read
	nop
	nop
	bsf       PORTB,4         ;E Line high
	nop       
	nop
	nop
	nop
	bcf       PORTB,4          ;Wait, Now low, Polling busy flag
	btfsc     PORTC,7          ; Wait untill busy flag is clear.     
	goto      $-7
	bcf       PORTA,5          ;Turn off Read
	bsf       STATUS,RP0
	movlw     0x00	
	movwf     TRISC
	bcf       STATUS,RP0       ;Port c all output
	return
TABLE1:                        ;Generic Table: Decimal -> ASCII
	addwf     PCL;	
	retlw     0x30
	retlw     0x31
	retlw     0x32
	retlw     0x33
	retlw     0x34
	retlw     0x35
	retlw     0x36
	retlw     0x37
	retlw     0x38
	retlw     0x39
	return
DELAY:                       ;Generic Delay
	decfsz    DELAY1
	goto      DELAY
	decfsz    DELAY2
	goto      DELAY
	return
 end

The Breakdown:

This code is fairly simple, there are no interrupts to worry about. We set up our variables in available registers as always. Our ports routine is much of the same, we set the appropriate ports for analog function and then set the appropriate I/O

Initialize the LCD:

INITIALIZELCD:          ;Initialization Routine for the LCD
	bsf       PORTC,0   ;Put CMD 0 on port C
	call      SEND      ;Call Send routine, Sends command and waits for busy flag
  	movlw     0x38      ; Set Function, 8 Bit, 5X10 Dots, Two line
  	movwf     PORTC
	call      SEND
	movlw     b'00001100' ; Turn on the Display (0x0B
	movwf     PORTC
	call      SEND
        movlw     0x06       ; Set entry mode to: Increment Adress counter, no shift.
	movwf     PORTC
	call      SEND
	return

Remember all those commands? We have to first tell the LCD what we want it to do before we start writing to the DDRAM. We set our LCD up for how were going to use it. This a fairly common initialization routine. We turn on the display, set 8 bit data control, two line, 5x10 font, and we have the address counter increment on write to DDRAM.

This routine we load the command we want into PORTC and then call our Send routine

The Send Routine:

SEND:                         ;Use this routine to send a command to the LCD. Placement doesnt matter as it does two BSYFLG checks
	;Send
	bsf       PORTB,4         ; Set E line High
	nop       
	nop
	nop
	nop
	bcf       PORTB,4         ;Wait a bit then set it low, sending command to LCD
BUSYCHK:
	bsf       STATUS,RP0      ; Port C, all input
	movlw     0xff	
	movwf     TRISC
	bcf       STATUS,RP0
	bsf       PORTA,5         ;Set Read
	nop
	nop
	bsf       PORTB,4         ;E Line high
	nop       
	nop
	nop
	nop
	bcf       PORTB,4          ;Wait, Now low, Polling busy flag
	btfsc     PORTC,7          ; Wait untill busy flag is clear.     
	goto      $-7
	bcf       PORTA,5          ;Turn off Read
	bsf       STATUS,RP0
	movlw     0x00	
	movwf     TRISC
	bcf       STATUS,RP0       ;Port c all output
	return

To send data the the LCD we have to toggle the E line. We set it high momentarily then we set it low. Once we do that the LCD reads the command and performs an internal operation. As this happens the BSY Flag is set on the LCD and we poll this until it is clear. After which we continue with normal operation by exiting the routine

Drawing the Static Display:

We draw all the static information by first setting the DDRAM address position and then putting the value we wish to send into w and then calling a routine which sends the value to the LCD

WRITELOC:
	movwf     TEMP       ;Move value to temp
	call      BUSYCHK    ;Check busy flag
	movfw     TEMP       ;Temp -> W
	movwf     PORTC      ;W -> Portc
	call      SEND       ;SEND
	return

Basic routine that makes it a little more mechanical to write data to the LCD. The value in W is sent to the LCD

WRITECHAR:               ; Function to write a characture 
	movwf     TEMP       ; Move value to temp register
	call      BUSYCHK    ; Check Busy flag
	bsf       PORTA,0    ; Turn on Data 
	movfw     TEMP       ; Move from Temp to W
	movwf     PORTC      ; Then to PORTC
	call      SEND       ; Send
	bcf       PORTA,0    ; Turn off Data
	return

Another routine specially designed for writing a character to a DDRAM address. This sets our PORTA,0 (Instruction/Data) high as we send Data to the LCD.

The MAIN routine:
The main routine is fairly simple, we generate an A2D result and then call the routine which does the dynamic updating of the LCD (we do this 3 times for each of the 3 axis (xyz)

Updating the LCD:

UPDATELCD:               ; Routine to update the dynamic elements of the LCD
	call      WRITELOC   ; Init the LCD at the proper DDRAM location
	clrf      ONES       ; Clear Vars
	clrf      TENS
	clrf      HUNDREDS
	call      CALCULATE  ; Call calculate routine which takes raw A2D value and separates them into digits
	movfw     HUNDREDS   ; Write the Hundreds digit to the LCD
	call      TABLE1
	call      WRITECHAR
	movfw     TENS       ;Write Tens
	call      TABLE1
	call      WRITECHAR
	movfw     ONES       ;Write Ones
	call      TABLE1
	call      WRITECHAR
	return

This is another simple routine, we take the A2D result, break it down into its individual digits and send it to the LCD. We provide the DDRAM address in w before we call the function, thus this can be used for more than 1 axis making our code much more efficient.

Conclusion:

Overall this is a fairly easy project that goes over the basics of controlling an HD44780 character LCD using a tri axis accelerometer as an analog input.

Ill leave you with a picture of the completed project as well the source and hex. Enjoy!

Whats next: Making it display proper units

Source
Hex

Permalink

Trackback address for this post

This is a captcha-picture. It is used to prevent mass-access by robots.

Please enter the characters from the image above. (case insensitive)

Array

No feedback yet

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
PoorExcellent
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)
This is a captcha-picture. It is used to prevent mass-access by robots.

Please enter the characters from the image above. (case insensitive)

Array
February 2012
Sun Mon Tue Wed Thu Fri Sat
 << <   > >>
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29      

Ads by Google

This blog is dedicated to working with digital circuitry and the use of microcontrollers, small compact computers on a chip. I will be encompassing many techniques to develop projects, tools to use to write and assemble code and i will be sharing any projects i am currently working on. User feedback is a must! I do not know it all, hell im not even that experienced, but without a general place to get all the info needed i find it very hard to get into the world of microcontrollers without pursing a CE degree. So come one come all and enter the world of mystery and creativity!

Search

XML Feeds

powered by b2evolution free blog software