Simple LCD

Go To Last Post
10 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey Everyone!

I'm on a mission to make a simple LCD loop thingy.

this is what I have so far:

/*
 * lcd.asm
 *
 *  Created: 2012/04/20 11:23:01 AM
 *   Author: little_grim
 */ 


 .include "m328Pdef.inc"

 .equ RS = 1
 .equ E = 0
 .def temp = R16

 .org 0x0000

 cbi PortB, RS
 setup:
	ldi temp, 0xFF
	out DDRB, temp ;portB is output
	ldi temp, 0xFF
	out DDRD, temp ;portD is output

	ldi temp, 0x20
	out PortD, temp
	sbi PortB, E ; setting to 4bit mode
	nop
	cbi portB, E
		
	ldi temp, 0x01 ;reset display
	rcall command
		
	ldi temp, 0x28 ;2line mode
	rcall command
		
	ldi temp, 0x0E ;display on, cursor options
	rcall command
	
	ldi temp, 0x06 ;display shift
	rcall command

 start:
	
	ldi temp, 'C'
	rcall character

	ldi temp, 'h'
	rcall character
		
	ldi temp, 'e'
	rcall character
		
	ldi temp, 'r'
	rcall character
		
	ldi temp, 'i'
	rcall character
		
	ldi temp, '!'
	rcall character

	here: rjmp here

 character:
	sbi PortB, RS ;tells lcd ascii characters are 
	rcall command      ;comming
	cbi PortB, RS
	ret

 command:
	rcall delay
	out PortD, temp ;outputs data
	sbi PortB, E 
	nop            ;strobes enable
	cbi PortB, E
	nop
	swap temp ;brings the low nibble up
	out PortD, temp  displays the low nibble
	sbi PortB, E
	nop
	cbi PortB, E
	nop
	ret

 delay:
	ldi ZH,HIGH(40000)		
	ldi ZL,LOW(40000)		
	Count:
		sbiw ZL,1		
		brne Count

	ret

It prints out my name, but it's not very effective.
So my question is this, how do I get it to print a whole string.

anyhelp anybody

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Assuming a 0-terminated string, point to the first char of the string and do the following - if 0, return, else write that char and increment pointer to next char.

You will also want some form of goto(x,y) to locate where each message will go on the screen.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kk6gm wrote:
Assuming a 0-terminated string, point to the first char of the string and do the following - if 0, return, else write that char and increment pointer to next char.

You will also want some form of goto(x,y) to locate where each message will go on the screen.

That makes sense in a way, but I don't know how to implement it. I only just managed to get the LCD to print my name today.

I tried looking at examples on the web, but everyone has such complicated methods of working that I can't make heads or tales of their code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You'll need a pointer using a register pair (X, Y or Z, see the AVR ASM reference). Reference the characters through that pointer, and add 1 to the register pair to advance the pointer (adiw instruction).

For goto(x,y) you start with a base offset based on y (e.g. 0 for y==0, 0x40 for y==1) and add x, and that value is the memory location value you send to the LCD before writing the characters.

Here's some C code for you to examine. You'll see it's not complicated at all (the constants, etc should be obvious from the LCD datasheet).

void lcd_put_line(u8 line, u8 col, char * p_text)
{
    u8 addr = (line == 0) ? 0 : 0x40;
    addr += col;
    put_lcd_8(LCD_CMD, 0x80 | addr); // locate cursor
    
    while (*p_text)
    {
        put_lcd_8(LCD_DATA, *p_text++);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
   ldi temp, 0x20
   out PortD, temp
   sbi PortB, E ; setting to 4bit mode
   nop
   cbi portB, E
      
   ldi temp, 0x01 ;reset display
   rcall command
      
   ldi temp, 0x28 ;2line mode
   rcall command
      
   ldi temp, 0x0E ;display on, cursor options
   rcall command
   
   ldi temp, 0x06 ;display shift
   rcall command 

Do you mind explaining how you came up with this sequence?

Don

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Use the LMP instruction with a 0 termination

Search the academy. HTere is a boatload of projects that do this.

Keep in mind that you will need the z register to do this, so move your delay to the x register.

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is a basic idea:

ldi		ZH,high(alldone*2)	;
		ldi		ZL,low(alldone*2)
		rcall	messsend
messsend:;rcall	delay45
uout:
		lpm		r22,Z+	;load the register with charachter 
		tst		r22		;and check if it is the end 
		brne	output	
;		rcall	delay45
	
		ret				;if done return
;output*********************************************************************
output:	 
ulpb:	lds		temp,ucsr0a
		sbrs	temp,5
		rjmp	ulpb
		sts		udr0,r22
		rcall	delay45
		rjmp	uout	;go get the next charachter


;***********************************Messages
Messages:
alldone:	.db "Configuration done.  Please disconnect Configuration",0x0d,0

This snippet of code sends the charachters to the usart, but you should be able to incorporate it into your code.

The TST instruction checks for the ,0 termination and returns from the routine when it sees it.
The 0x0D in the message tells the receiving terminal to carriage return, and can be ommited.

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another example

.nolist   
.include 
.list   
.listmac

;--------------------
;macros
.macro lcd_sf ;display string saved in Flash
      ldi   zl, low (@0 * 2)  ;adr. of string to reg. Z 
      ldi   zh, high(@0 * 2)  
      
L1:   lpm   temp, Z+   
      cpi   temp, 0
      breq  L2
      rcall lcd_c ;display character saved in "temp"
      rjmp  L1
L2: 
.endm


;--------------------
;register naming
.def temp = r16


;--------------------

.CSEG  ;code segment (Flash)
.ORG 0
      rjmp main

;strings in flash 
string1: .db "Hello"  ,0        
string2: .db "Cheri!" ,0     
      
;====================
main: 
      ;init stack
      ldi   temp, HIGH(RAMEND)
      out   SPH,  temp
      ldi   temp, LOW(RAMEND) 
      out   SPL,  temp

      rcall lcd_init
      
      lcd_sf string2  ;call macro

;-----------------------------------------------------
mainloop:

rjmp  mainloop

;-----------------------------------------------------

;subroutines

;--------------------
lcd_init: ;initialize Lcd
;;; code
ret

;--------------------
lcd_c:  ;display char in "temp"
;;; code
ret

Last Edited: Fri. Apr 20, 2012 - 09:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I tried looking at examples on the web, but everyone has such complicated methods of working that I can't make heads or tales of their code.
Try this:

; ------head-------------------------------------------
lcd_write_string:
; This subroutine displays a string of characters on the LCD module.
; The string must end with a nul (0)
; Enter with:  ZH and ZL pointing to the start of the string
;              The desired DDRAM address at which to display the information in (temp)

; fix up the pointers for use with the 'lpm' instruction
    lsl     ZL                              ; shift the pointer one bit left for the lpm instruction
    rol     ZH

; set up the initial DDRAM address
    ori     temp, 0b10000000                ; convert the plain address to an address instruction   
    rcall   lcd_write_instruction           ; set up the first DDRAM address

; write the string of characters
lcd_write_string_01:
    lpm     temp, Z+                        ; get a character
    cpi     temp,  0                        ; check for end of string
    breq    lcd_write_string_02             ; done
 
; arrive here if this is a valid character
    call    lcd_write_character             ; display the character
    rjmp    lcd_write_string_01             ; not done, send another character

; arrive here when all characters in the message have been sent to the LCD module
lcd_write_string_02:
    ret
; ------tail-------------------------------------------

Don

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank everyone for all your help!
I really appreciate it. I ended up taking Visovian's code.

/*
 * lcd.asm
 *
 *  Created: 2012/04/20 11:23:01 AM
 *   Author: little_grim
 */ 


.nolist   
.include "m328Pdef.inc"
.list   
.listmac 

;--------------------
;macros
.macro lcd_sf ;display string saved in Flash
      ldi   zl, low (@0 * 2)  ;adr. of string to reg. Z
      ldi   zh, high(@0 * 2) 
     
L1:   lpm   temp, Z+   
      cpi   temp, 0
      breq  L2
      rcall character ;display character saved in "temp"
      rjmp  L1
L2:
.endm

 .equ RS = 1
 .equ E = 0
 .def temp = R16

 .CSEG  ;code segment (Flash) 
 .org 0x0000
 rjmp setup

 ;strings in flash
 string2: .db "Thanx Visovian"  ,0       
 
 setup:
	ldi   temp, HIGH(RAMEND)
    out   SPH,  temp
    ldi   temp, LOW(RAMEND)
    out   SPL,  temp
 
 rcall init
 rjmp start
 
 init:
	ldi temp, 0xFF
	out DDRB, temp
	ldi temp, 0xFF
	out DDRD, temp

	cbi PortB, RS

	ldi temp, 0x20
	out PortD, temp
	sbi PortB, E
	nop
	cbi portB, E
	clr temp

	ldi temp, 0x28
	rcall command
		
	ldi temp, 0x0E
	rcall command
	
	ldi temp, 0x06
	rcall command

	ldi temp, 0x01
	rcall command
		
	ret

start:
	lcd_sf string2  ;call macro 

	here: rjmp here

 character:
	sbi PortB, RS
	rcall command
	cbi PortB, RS
	ret

 command:
	rcall delay
	out PortD, temp
	sbi PortB, E
	nop
	cbi PortB, E
	nop
	swap temp
	out PortD, temp
	sbi PortB, E
	nop
	cbi PortB, E
	clr temp
	nop
	ret

 delay:
	ldi R20, 5 
	out TCCR0B, R20

	ldi R20, 99
	out TCNT0, R20

	pause:
		in R20, TIFR0
		andi R20, 1
		breq pause
		ldi R20, 1
		out TIFR0, R20
	ret

So this is how my code looks and it works...
For future reference.