Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

LCD 4 bit PIC asm Help

Status
Not open for further replies.
@wp100. Please look my new code which is attached with Proteus file. You only have to look in the PutSting function. In that I have three different ways for printing strings. They are

2 functions and 1 macro

1 call send_nibbles
2 call LCD_DATA
3 macro LCD_D

Only one of them is used. The problem is in K8LH code I attached the w (Working register) is going to lcd_d function but in my code it is not working and that is causing the problem. See my attached simulation by compiling by selecting any one function call or macro in the PutString function and assembling the code. My LCD_Chr macro works fine but same when a similar macro which is LCD_D is called from PutString w is not going into the macro. My way of LCD is different because it allows to use any pins for LCD control and data. You don't have to use D4-D7 of some PORT but can use any random digital output pins for lcd data and control. My LCD_Chr works fine there is no Problem. Problem is in PutSting function which is called from LCD_Out macro which is used to print strings.

I will explain it little more clearly

In PutString function

movf TABLAT,w puts the current character of the string in w (working register) and then LCD_D macro is called in my version but in K8LH version lcd_d function is called. In K8LH version w is going into lcd_d function and saved temporarily in a file register and then restored back to w (reg) and then assigned to LCD_PORT (D4-D7). In my version w from PutString is not going to LCD_D macro. In LCD_D macro

movwf LCDChr

is used and then

if LCDChr & H'10'... is used to

So, it has to work like this

from movf TABLAT,w the current character of the string will be in w and w has to go to LCDChr and LCDChar compared with hex values will toggle the data pins of LCD like it is doing in my LCD_Chr macro which is printing single characters.

@betwixt. I am waiting for your code.


If I use

#define LCD_PORT LATB

...

banksel LCD_PORT

...

it is working i.e., I have to use D4-D7 of some port but not working for bit i.e., How to select bank which has the following bits. This is actuallly causing the problem.

#define LCD_D4 LATB,4
#define LCD_D5 LATB,5
#define LCD_D6 LATB,6
#define LCD_D7 LATB,7

Edit 2:

I found the problem. I debugged the code in mplab and also mplabX. What I observed is

When I step-into LCD_Out macro call program execution goes directly to Delay500us instead of going to LCD_Out macro or PutString function which is called in the LCD_Out macro. If I comment the Delay500us function and function calls in the code and debug then it executes normally entering the PutString function call. Another thing I observed is in the PutString function send_nibbles function is called. In this none of the if...else...endif function work i.e., it always executes the else conditions. So I used MACROS.ASM with my code and used select...endselect method in the send_nibbles function. Now the execution happened as expected without problem but LCD doesn't display because Delay500us is needed for LCD_STROBE. If I uncomment the Delay500us and debug or run the code the execution just goes into Delay500us call and comes out of it and repeats and it doesn't execute any other code. What might be the problem?

I am attaching the file I used for debugging. I have commented out the Delay500us function and its calls. Without that function it doesn't display but by debugging it can be made sure that it executes as needed. If Delay500us is uncommented then no other code executes.
 

Attachments

  • LCD ASM v1.rar
    56.8 KB · Views: 58
  • LCDXC8ASM.rar
    42.3 KB · Views: 52
  • LCDXC8ASM v1.rar
    82.8 KB · Views: 54
Last edited:

After some cleaning of the file it finally worked. I have removed the code which prints Character. I will try to add the code and check if it works.

91977d1370353425-lcd4bit.png
 

Attachments

  • LCD4bit.rar
    67 KB · Views: 59
  • lcd4bit.png
    lcd4bit.png
    27.9 KB · Views: 118
  • LCD4bitv2.rar
    68.1 KB · Views: 61
Last edited:

Why if...else...endif is working inside macros but not in send_nibbles function? i.e., if I replace the code in the send_nibbles function with if...else...endif code it doesn't work.
 

if...else....endif are assembler directives to decide which code is assembled into the hex file, they are not intended to be used to control program flow. They are not coded into the program, they are only used in the assembly process.

I've been very busy over the past few days and not had an internet connection except by mobile phone so I've not been able to participate as much as usual but I have produced a code example for you. It is completely untested and written from my memory of standard LCD protocols so the chances are it will not work without debugging. It should give you some ideas though and show how over-complicated your macro method is. I have not written anything for the delay routines but you should be able to work those out for yourself.

Code:
; 4-bit LCD routine.
; This is UNTESTED but should serve as an example of assembly language
; interfacing. It assumes the -RW pin is tied low and therefore the BUSY
; signal cannot be read back and delays are necessary to pace the 
; command and data flows.
;
; A better and usually quicker method is to use the BUSY flag to tell
; when the LCD is responsive to new data but to implement this, another
; pin (-RW) has to be driven.
;
; It also assumes the PIC data pins are consecutive to the LCD data pins
; and PORT B is being used as the interface, this can be changed by
; editing the #defines as necessary. Other pins on PORTB are free to
; be used for other purposes.


; first lets give the pins a more maningful name to make it easier to
; read the code.

#define LCD_PORT PORTB
#define LCD_D0 PORTB,0
#define LCD_D1 PORTB,1
#define LCD_D2 PORTB,2
#define LCD_D3 PORTB,3
#define LCD_RS PORTB,4
#define LCD_EN PORTB,5

; some workspace is needed, this line would normally be part of a bigger
; cblock elsewhere in the program.

	cblock 0x20
LCD_Temp
	endc

; we need three routines to communicate with the LCD, one to send commands,
; one to send data and one to initialize it. Sending data and commands is 
; essentially the same except for the state of the RS pin so a common routine
; is used in both cases.

; a routine to write to the LCD. Set the RS pin first then call this
; routine with the value to send in the W register.
LCD_Write
	bsf LCD_EN				; start with EN = 1
	movf LCD_Temp,w			; save the value in W for later
	swapf LCD_Temp,w		; swap the high and low nibbles
	andlw 0x0F				; only keep low nibble
	bcf	LCD_D0				; clear any bits on the LCD data lines
	bcf LCD_D1
	bcf LCD_D2
	bcf LCD_D3
	iorwf LCD_PORT,f		; write high nibble to the data lines
	bcf LCD_EN				; latched on falling edge of EN pin
	movf LCD_Temp,w			; recover the original value
	andlw 0x0F				; only keep low nibble
	bsf LCD_EN				; make EN = 1 again
	bcf	LCD_D0				; clear any bits on the LCD data lines
	bcf LCD_D1
	bcf LCD_D2
	bcf LCD_D3
	iorwf LCD_PORT,f		; write low nibble to the data lines
	bcf LCD_EN				; latched on falling edge of EN pin
	nop						; just in case EN pulse is too short
	bsf LCD_EN				; disable until next time
	return
	
; a routine to send command in W to the LCD	
LCD_Cmd
	bcf	LCD_RS				; RS pin = 0	
	call LCD_Write
	return

; a routine to send command in W to the LCD		
LCD_Data
	bsf LCD_RS
	call LCD_Write
	return
	
LCD_Init
	call Delay_50mS			; in case power was just applied
	movlw 0x30
	call LCD_Cmd			; send command 0x30
	call Delay_10mS
	call LCD_Cmd			; send command 0x30
	call Delay_10mS
	call LCD_Cmd			; send command 0x30
	call Delay_10mS
	movlw 0x20				; for 4-bit mode
	call LCD_Cmd
	call Delay_10mS
	return

It should work with any PIC16 or PIC18 device but for PIC18 it may be worth changing references of PORTB to LATB in the #defines section.

Brian.
 
I will try your code betwixt but it uses Data pins like D0 to D3 or D4 to D7. I have another question. In the code I have attached why it doesn't work if I replace if...else...endif in the LCD_Cmd, LCD_DATA and LCD_Chr macros with the code in the SendNibbles function. The code does the same thing. I just want to replace the repeated codes and tidy up my code.
 

Attachments

  • LCD.rar
    50.4 KB · Views: 61

In the code example you choose which pins in the #define section but if you change to the high rather than low data pins you will have to reverse the order of the nibbles in the code, they are swapped first at the moment so the high bits are sent to the LCD on the lower data pins. You have to mask and send the high bits first then swap them if you use D7:D4.

Please look at the PIC data sheet in the instruction set chapter and see what the 'if', 'else' and 'endif' instructons actually do (if you can!) see what binary code they produce. It will help to explain why your code does not work as expected. Also look at the size of the code your program produces compared to mine.

Brian.
 
But there is no if...else...endif codes in SendNibbles function. I want to replace if...else...endif codes completely with call to SendNibbles function. So that much of the codes in LCD_Chr, LCD_Data and LCD_Cmd macros are replaced with code in SendNibbles function. The code resulted by if...else...endif codes and code in SendNibbles function do the same thing. I want to completely get rid of if...else...endif codes.
 
I agree you should forget the "if endif" constructs. They only work at assembly time, to decide which instructions are actually assembled and they don't get put into the PIC afterwards. They are very valuable directives in certain circumstances but shouldn't be used during program execution.

If you look at the "LCD_Write " subroutine I wrote, you will see it sends both nibbles to the LCD. There is a very useful instruction "swapf" which moves the four lower bits to the top positions and the top four bits to the lower position, for example bits 76543210 become 32107654. I used it to align the upper then lower four bits with the port pins then cleared the bits to zero, a known starting value, then inclusive OR'ed the nibble with the port. The nibbles are swapped in a single instruction! Each call to LCD_write sends both nibbles so all you have to do is load W with the value you want to send then call the routine. I expanded it to send commands or data by wrapping the 'Write' function in routines that set or reset the RS bit before driving the LCD lines.

Brian.
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top