From d0fb4b84f88f52d599d65431e47784a0b97f022a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sude=20=C3=87akmak?= Date: Sun, 30 Apr 2023 16:10:19 +0300 Subject: [PATCH] LCD --- LCD/152120201044.asm | 365 +++++++++++++++++++++++++++++++++++++++++++ LCD/LcdLib.inc | 221 ++++++++++++++++++++++++++ LCD/delay.inc | 120 ++++++++++++++ 3 files changed, 706 insertions(+) create mode 100644 LCD/152120201044.asm create mode 100644 LCD/LcdLib.inc create mode 100644 LCD/delay.inc diff --git a/LCD/152120201044.asm b/LCD/152120201044.asm new file mode 100644 index 0000000..9450faa --- /dev/null +++ b/LCD/152120201044.asm @@ -0,0 +1,365 @@ + LIST P=16F877A + INCLUDE P16F877.INC + __CONFIG _CP_OFF &_WDT_OFF & _BODEN_ON & _PWRTE_ON & _XT_OSC & _WRT_ENABLE_OFF & _LVP_OFF & _DEBUG_OFF & _CPD_OFF + radix dec + + cblock 0x48 + msg + endc + + ; Reset vector + org 0x00 + GOTO MAIN ; Jump to the main function + + #include ; Delay library (Copy the contents here) + #include ; LcdLib.inc (LCD) utility routines + + +MAIN: + BSF STATUS, RP0 + MOVLW 0x0 + MOVWF TRISD + MOVWF TRISE + MOVLW 0x03 ; Choose RA0 analog input and RA3 reference input + MOVWF ADCON1 ; Register to configure PORTA's pins as analog/digital <11> means, all but one are analog + + BCF STATUS, RP0 ; Select Bank0 + CALL LCD_Initialize ; Initialize the LCD + + BSF STATUS, RP0 ; Select Bank1 + CLRF TRISA ; PortA --> Output + CLRF TRISD ; PortD --> Output + BCF STATUS, RP0 ; Select Bank0 + + CLRF PORTD ; PORTD = 0 + CLRF PORTA ; Deselect all SSDs + + + digit0 EQU 0x20 + digit1 EQU 0x21 + no_iteration EQU 0x22 + i EQU 0x23 + NUM EQU 0x24 + + CALL Init_NUM + + MOVLW 0 + MOVWF digit0 + + MOVLW 0 + MOVWF digit1 + + MOVLW 90 + MOVWF no_iteration + + CALL Countingup + +for_loop: + BCF PORTA, 5 + BCF PORTA, 4 + CALL DisplayCounter +loop_begin: + MOVF i, W + SUBWF no_iteration, W + BTFSS STATUS, C + GOTO loop_end +loop_body: + BSF PORTA, 5 + BCF PORTA, 4 + MOVF digit0, W + CALL GetCode ; SSDCodes [digit0] + MOVWF PORTD + CALL Delay5ms + + BSF PORTA, 4 + BCF PORTA, 5 + MOVF digit1, W + CALL GetCode ; SSDCodes [digit1] + MOVWF PORTD + CALL Delay5ms + + INCF i, F ; i++ + GOTO loop_begin +loop_end: + CLRF i + INCF digit0, F + + ; if (digit0 == 10) + MOVLW 10 + SUBWF digit0, W + BTFSS STATUS, Z + GOTO not_equal + + MOVLW 0 + MOVWF digit0 + INCF digit1, F + +not_equal: + + ; if (digit1 == 2 && digit0 == 1) + CALL Countingup ; not 00 + MOVLW 2 + SUBWF digit1, W + BTFSS STATUS, Z + GOTO for_loop + + MOVLW 1 + SUBWF digit0, W + BTFSS STATUS, Z + GOTO for_loop + + CLRF digit0 + CLRF digit1 + CALL Rollingup ; 00 + GOTO for_loop + + +GetCode: + MOVWF FSR ; FSR = number + MOVLW NUM ; WREG = &LUT + ADDWF FSR, F ; FSR += &LUT + MOVF INDF, W ; WREG = LUT[number] + RETURN + + +Delay5ms: + k EQU 0x70 ; Use memory slot 0x70 + l EQU 0x71 ; Use memory slot 0x71 + + MOVLW d'5' ; + MOVWF k ; k = 5 +OuterLoop: + MOVLW d'250' + MOVWF l ; l = 250 +InnerLoop: + NOP + DECFSZ l, F ; --l == 0? + GOTO InnerLoop + + DECFSZ k, F ; --k == 0? + GOTO OuterLoop + RETURN + + +Init_NUM: + MOVLW B'00111111' ; 0 + MOVWF NUM ; NUM[0] = WREG + MOVLW B'00000110' ; 1 + MOVWF NUM+1 + MOVLW B'01011011' ; 2 + MOVWF NUM+2 + MOVLW B'01001111' ; 3 + MOVWF NUM+3 + MOVLW B'01100110' ; 4 + MOVWF NUM+4 + MOVLW B'01101101' ; 5 + MOVWF NUM+5 + MOVLW B'01111101' ; 6 + MOVWF NUM+6 + MOVLW B'00000111' ; 7 + MOVWF NUM+7 + MOVLW B'01111111' ; 8 + MOVWF NUM+8 + MOVLW B'01101111' ; 9 + MOVWF NUM+9 + RETURN + + +DisplayCounter: + call LCD_Clear ; Clear the LCD screen + + ;Write Counter val + MOVLW 'C' + call LCD_Send_Char + + MOVLW 'o' + call LCD_Send_Char + + MOVLW 'u' + call LCD_Send_Char + + MOVLW 'n' + call LCD_Send_Char + + MOVLW 't' + call LCD_Send_Char + + MOVLW 'e' + call LCD_Send_Char + + MOVLW 'r' + call LCD_Send_Char + + MOVLW ' ' + call LCD_Send_Char + + MOVLW 'V' + call LCD_Send_Char + + MOVLW 'a' + call LCD_Send_Char + + MOVLW 'l' + call LCD_Send_Char + + MOVLW ':' + call LCD_Send_Char + + MOVLW ' ' + call LCD_Send_Char + + + ; Print digit1: digits[1] + MOVF digit1, W ; WREG <- digit + ADDLW '0' ; Add '0' to the digit + CALL LCD_Send_Char + + ; Print digit1: LSB + MOVF digit0, W ; WREG <- digit + ADDLW '0' ; Add '0' to the digit + CALL LCD_Send_Char + + + ; The rest of the characters will get displayed on the second line + CALL LCD_MoveCursor2SecondLine ; Move the cursor to the start of the second line + CALL ShowMessage + RETURN + +ShowMessage: + MOVF msg, W + CALL LCD_Send_Char + MOVF msg+1, W + CALL LCD_Send_Char + MOVF msg+2, W + CALL LCD_Send_Char + MOVF msg+3, W + CALL LCD_Send_Char + MOVF msg+4, W + CALL LCD_Send_Char + MOVF msg+5, W + CALL LCD_Send_Char + MOVF msg+6, W + CALL LCD_Send_Char + MOVF msg+7, W + CALL LCD_Send_Char + MOVF msg+8, W + CALL LCD_Send_Char + MOVF msg+9, W + CALL LCD_Send_Char + MOVF msg+10, W + CALL LCD_Send_Char + MOVF msg+11, W + CALL LCD_Send_Char + MOVF msg+12, W + CALL LCD_Send_Char + MOVF msg+13, W + CALL LCD_Send_Char + MOVF msg+14, W + CALL LCD_Send_Char + MOVF msg+15, W + CALL LCD_Send_Char + RETURN + +Clear: + ; Clear messagge in the second line + CLRF msg + CLRF msg+1 + CLRF msg+2 + CLRF msg+3 + CLRF msg+4 + CLRF msg+5 + CLRF msg+6 + CLRF msg+7 + CLRF msg+8 + CLRF msg+9 + CLRF msg+10 + CLRF msg+11 + CLRF msg+12 + CLRF msg+13 + CLRF msg+14 + CLRF msg+15 + RETURN + +Countingup: + CALL Clear + + ;Write counting up + MOVLW 'C' + MOVWF msg + MOVLW 'o' + MOVWF msg + 1 + MOVLW 'u' + MOVWF msg + 2 + MOVLW 'n' + MOVWF msg + 3 + MOVLW 't' + MOVWF msg + 4 + MOVLW 'i' + MOVWF msg + 5 + MOVLW 'n' + MOVWF msg + 6 + MOVLW 'g' + MOVWF msg + 7 + MOVLW ' ' + MOVWF msg + 8 + MOVLW 'u' + MOVWF msg + 9 + MOVLW 'p' + MOVWF msg + 10 + MOVLW '.' + MOVWF msg + 11 + MOVLW '.' + MOVWF msg + 12 + MOVLW '.' + MOVWF msg + 13 + RETURN + +Rollingup: + CALL Clear + + ;Write Rolled over to 0 + MOVLW 'R' + MOVWF msg + MOVLW 'o' + MOVWF msg + 1 + MOVLW 'l' + MOVWF msg + 2 + MOVLW 'l' + MOVWF msg + 3 + MOVLW 'e' + MOVWF msg + 4 + MOVLW 'd' + MOVWF msg + 5 + MOVLW ' ' + MOVWF msg + 6 + MOVLW 'o' + MOVWF msg + 7 + MOVLW 'v' + MOVWF msg + 8 + MOVLW 'e' + MOVWF msg + 9 + MOVLW 'r' + MOVWF msg + 10 + MOVLW ' ' + MOVWF msg + 11 + MOVLW 't' + MOVWF msg + 12 + MOVLW 'o' + MOVWF msg + 13 + MOVLW ' ' + MOVWF msg + 14 + MOVLW '0' + MOVWF msg + 15 + RETURN + + + MOVWF PORTD ; Send the result stored in WREG to PORTD to display it on the LEDs + +LOOP GOTO $ ; Infinite loop + END + + + + + + diff --git a/LCD/LcdLib.inc b/LCD/LcdLib.inc new file mode 100644 index 0000000..67eb2d9 --- /dev/null +++ b/LCD/LcdLib.inc @@ -0,0 +1,221 @@ +; This LCD library assumes that ALL 8 data pins [D7-D0] are connected to pins [7-0] of PORTD. +; Thus the LCD is used in 8-bit mode. +; +; Control pints [RS, R/W, E] are assumed to be connected to pins [0-2] of PORTE in this order +; That is, RS must be connected to pin0 of PORTE +; R/W must be connected to pin1 of PORTE +; E (Enable) must be connected to pin2 PORTE +; + +#define LCD_NO_OF_DATA_BITS 4 +;#define LCD_NO_OF_DATA_BITS 8 + +;------------------------------------------------------------ +; This is how we set up the configuration bits of the LCD +#if 0 +; These are the connections in our experiment board +#define RS PORTE, 0 ; RS is connected to pin 0 of PORTE +#define RW PORTE, 1 ; RW is connected to pin 1 of PORTE +#define EN PORTE, 2 ; E is connected to pin 2 of PORTE + +#else +; These are the connections in PICSIM +#define RS PORTE, 2 ; RS is connected to pin 2 of PORTE +#define RW PORTE, 0 ; RW is connected to pin 0 of PORTE +#define EN PORTE, 1 ; E is connected to pin 1 of PORTE +#endif + +#define D7 PORTD, 7 ; Which pin of the MCU is connected to D7 of the LCD? +#define D6 PORTD, 6 ; Which pin of the MCU is connected to D6 of the LCD? +#define D5 PORTD, 5 ; Which pin of the MCU is connected to D5 of the LCD? +#define D4 PORTD, 4 ; Which pin of the MCU is connected to D4 of the LCD? + +#if LCD_NO_OF_DATA_BITS == 8 +#define D3 PORTD, 3 ; Which pin of the MCU is connected to D3 of the LCD? +#define D2 PORTD, 2 ; Which pin of the MCU is connected to D2 of the LCD? +#define D1 PORTD, 1 ; Which pin of the MCU is connected to D1 of the LCD? +#define D0 PORTD, 0 ; Which pin of the MCU is connected to D0 of the LCD? +#endif + +; The LCD display has two lines of characters, 16 characters per line. +; Each character is composed of matrix of pixels size 5x8. +; The matrix is controlled by Hitachi HD44780 controller, +; which performs all the operations that are required to run the matrix. +; Controller operation is done in accordance with the instructions it receives as described below: +; +; A 2x16 character LCD has 14 pins +; DB0 - DB7, the 8 data bus lines, which perform read/write of data +; Vss, Vdd - Voltage supply pins +; R/W ? Pin writing/reading to/from - LCD +; RS - Pin selects registers between Instruction Register and Data Register +; E - "Enabling" pin; when this pin is set to logical low, the LCD does not care what is happening +; with R/W, RS, and the data bus lines; when this pin is set to logical high, the - LCD is processing the incoming data +; Vo - Pin for LCD contrast +; +; Some of the addresses represent the lines of LCD (0x00-0x0F- first line; 0x40-0x4F second line). +; The rest of the addresses represent the ?non-visible? memory of the DRAM, +; which can be also used as a general memory. The DDRAM address is the position +; of the cursor on the display LCD (the received information will be written +; at the place where the cursor is). +; +; Below be show the meaning of each configuration of bits. +; RS R/W +; 0 0 Sends a command to LCD +; 0 1 Read busy flag (DB7) and address counter (DB0 to DB6) +; 1 0 Sends information to LCD +; 1 1 Reads information from LCD + +;------------------------------------------------------------ +; Before we start using the LCD, we must first initialize certain bits +; +LCD_Initialize + ; During a power reset, LCD takes up to 10ms to reboot and stabilize + ; before a command can be sent to it. Therefore, we wait for 10ms + ; before sending the first command + BCF EN ; Make EN pin 0 + BCF RS ; Make RS bit 0 -- Will send commands + BCF RW ; Make RW bit 0 + CLRF PORTD ; Make all bits of PORTD 0 + CALL Delay_20ms ; Wait for 20ms + + ; Set LCD usage mode: 4-bit/2-lines/5x7 dot chars + IF LCD_NO_OF_DATA_BITS == 4 + BCF D7 ; D7=0 + BCF D6 ; D6=0 + BSF D5 ; D5=1 + BSF D4 ; D4=1 + CALL LCD_Send_Trigger ; Send 0x3 to the LCD: Means Attention + CALL Delay_20ms + + CALL LCD_Send_Trigger ; Send 0x3 to the LCD: Means Attention + CALL Delay_20ms + + CALL LCD_Send_Trigger ; Send 0x3 to the LCD Means Attention + CALL Delay_20ms + + BCF D7 ; D7=0 + BCF D6 ; D6=0 + BSF D5 ; D5=1 + BCF D4 ; D4=0 + CALL LCD_Send_Trigger ; Send 0x2: Puts the LCD in 4-bit mode + CALL Delay_20ms + + ; Now start sending commands + MOVLW 0x28 ; 4-bit, 2-lines, 5x7 dot characters: 0011 1000 + CALL LCD_Send_Command ; Send the command to the LCD + + ELSE + MOVLW 0x30 ; Attention + CALL LCD_Send_Command ; Send the command to the LCD + CALL Delay_20ms + + MOVLW 0x30 ; Attention + CALL LCD_Send_Command ; Send the command to the LCD + CALL Delay_20ms + + MOVLW 0x30 ; Attention + CALL LCD_Send_Command ; Send the command to the LCD + CALL Delay_20ms + + MOVLW 0x38 ; 8-bit, 2-lines, 5x7 dot characters: 0011 1000 + CALL LCD_Send_Command ; Send the command to the LCD + ENDIF + + ; Turn the LCD on and set cursor properties +; MOVLW 0x0F ; LCD open, cursor on, cursor blinking: 0000 1111 +; MOVLW 0x0E ; LCD open, cursor on, cursor off: 0000 1111 + MOVLW 0x0C ; LCD open, cursor off, cursor not blinking: 0000 1100 + CALL LCD_Send_Command ; Send the command to the LCD + + MOVLW 0x06 ; Entry mode: 0000 0110 + CALL LCD_Send_Command ; Send the command to the LCD + + ; Clear the current contents of the LCD and move the cursor to the start of the first line + CALL LCD_Clear + RETURN + +;------------------------------------------------------------ +; Sends one byte stored in WREG to the LCD +; +LCD_Send + MOVWF PORTD ; PORTD <- WREG + CALL LCD_Send_Trigger ; Send the trigger signal to LCD so that the sent command is executed + + IF LCD_NO_OF_DATA_BITS == 4 + SWAPF PORTD ; Swap bits [7-4] with [3-0] + CALL LCD_Send_Trigger ; Send the trigger signal to LCD so that the sent command is executed + ENDIF + + RETURN + +;------------------------------------------------------------ +; Display the character in WREG at the current cursor position +; +LCD_Send_Command + BCF RS ; + BCF RW ; =<0:0> means we are sending a command to the LCD + + CALL LCD_Send ; Send the command + RETURN + +;------------------------------------------------------------ +; Display the character in WREG at the current cursor position +; +LCD_Send_Char + BSF RS ; + BCF RW ; =<1:0> means, we will be sending data + + CALL LCD_Send ; Send the character + RETURN + +;------------------------------------------------------------ +; Clear the LCD +; +LCD_Clear + MOVLW 0x01 ; 0x1 is the clear LCD command + CALL LCD_Send_Command + + CALL Delay_5ms ; Wait for 5 ms for LCD to finish clearing the screen + RETURN + +;------------------------------------------------------------ +; Move the cursor to the start of the second line +; +LCD_MoveCursor2SecondLine + ; Set DD RAM Address: + ; This sets the DD RAM address. + ; and the cursor advances in the direction where the I/D bit was set to. The line settings are as follows: + ; RS R/W D7 D6 D5 D4 D3 D2 D1 D0 + ; 0 0 1 MSB DD RAM ADDRESS LSB + MOVLW 0xC0 ; Address of the first byte of the second line: 0x40 + CALL LCD_Send_Command + RETURN + +;------------------------------------------------------------ +; For LCD to process a given data (from the data bits), we first +; need to enable it, wait for some time (until LCD finishes processing +; the command), and then disable the E pin. This is called sending a trigger signal +; This essentially means that we send the following signal to the E pin of the LCD +; +-----+ +; | | +; | | +; -----+ 1us +-------- +; +; Many flip-flop based devices work this way. After you put the data at the input pins +; of the device, you need to send a trigger signal for the device to process that input +; +LCD_Send_Trigger + BCF EN ; Bring the Enable bit to 0 + NOP + NOP + NOP + NOP ; Wait for 5 microseconds + BSF EN ; Bring the Enable bit to 1 + NOP + NOP + NOP + NOP + NOP ; Wait for 5 microseconds + BCF EN ; Bring the Enable bit back to 0 (processing occurs on this falling edge?) + CALL Delay_125us ; Wait 125 microsecond for LCD to finish processing of the previous command + RETURN \ No newline at end of file diff --git a/LCD/delay.inc b/LCD/delay.inc new file mode 100644 index 0000000..01428ad --- /dev/null +++ b/LCD/delay.inc @@ -0,0 +1,120 @@ +; Keep these variables in the 16 byte memory area shared by all banks +; so that we don't have to worry about bank selection +; The shared ares is in between [0x70-0x7f] +delay_counter1 EQU 0x7c +delay_counter2 EQU 0x7d +delay_counter3 EQU 0x7e +delay_counter4 EQU 0x7f + +;------------------------------------------------------------ +; Assumes that the microprocessor is run with a 4Mhz oscilator +; In a 4Mhz oscilator, one operation takes 1 microsecond +; With this code, 42x3=126 cycles are obtained on the average +;------------------------------------------------------------ +Delay_125us + MOVLW 0x2A ; Decimal 42 + MOVWF delay_counter1 ; +LABEL_125us_DELAY + DECFSZ delay_counter1, F ; + GOTO LABEL_125us_DELAY + RETURN + +;------------------------------------------------------------ +; Simply call Delay_125us 8 times to obtain a 1ms delay +;------------------------------------------------------------ +Delay_1ms + MOVLW .8 ; WREG <- Decimal 8 + MOVWF delay_counter2 ; delay_counter2 <- WREG +LABEL_1ms_DELAY + CALL Delay_125us ; Call 125 microsecond delay + DECFSZ delay_counter2, F ; Do this 8 times. 8x125us = 1ms + GOTO LABEL_1ms_DELAY + RETURN + +;------------------------------------------------------------ +; Simply call Delay_1ms 5 times to obtain a 5ms delay +;------------------------------------------------------------ +Delay_5ms + MOVLW .5 ; WREG <- Decimal 5 + MOVWF delay_counter3 ; delay_counter3 <- WREG +LABEL_5ms_DELAY + CALL Delay_1ms ; Call 1 microsecond delay + DECFSZ delay_counter3, F ; Do this 5 times. 5x1ms = 5ms + GOTO LABEL_5ms_DELAY + RETURN + +;------------------------------------------------------------ +; Simply call Delay_1ms 20 times to obtain a 20ms delay +;------------------------------------------------------------ +Delay_20ms + MOVLW .20 ; WREG <- Decimal 5 + MOVWF delay_counter3 ; delay_counter3 <- WREG +LABEL_20ms_DELAY + CALL Delay_1ms ; Call 1 microsecond delay + DECFSZ delay_counter3, F ; Do this 20 times. 30x1ms = 20ms + GOTO LABEL_20ms_DELAY + RETURN + +;------------------------------------------------------------ +; Simply call Delay_5ms 10 times to obtain a 100ms delay +;------------------------------------------------------------ +Delay_50ms + MOVLW .10 ; WREG <- Decimal 10 + MOVWF delay_counter4 ; delay_counter4 <- WREG +LABEL_50ms_DELAY + CALL Delay_5ms ; Call 5 microsecond delay + DECFSZ delay_counter4, F ; Do this 10 times. 10x5ms = 50ms + GOTO LABEL_50ms_DELAY + RETURN + +;------------------------------------------------------------ +; Simply call Delay_5ms 20 times to obtain a 100ms delay +;------------------------------------------------------------ +Delay_100ms + MOVLW .20 ; WREG <- Decimal 20 + MOVWF delay_counter4 ; delay_counter4 <- WREG +LABEL_100ms_DELAY + CALL Delay_5ms ; Call 5 microsecond delay + DECFSZ delay_counter4, F ; Do this 20 times. 20x5ms = 100ms + GOTO LABEL_100ms_DELAY + RETURN + +;------------------------------------------------------------ +; Simply call Delay_5ms 50 times to obtain a 250ms delay +;------------------------------------------------------------ +Delay_250ms + MOVLW .50 ; WREG <- Decimal 50 + MOVWF delay_counter4 ; delay_counter4 <- WREG +LABEL_250ms_DELAY + CALL Delay_5ms ; Call 5 microsecond delay + DECFSZ delay_counter4, F ; Do this 50 times. 50x5ms = 250ms + GOTO LABEL_250ms_DELAY + RETURN + +;------------------------------------------------------------ +; Simply call Delay_5ms 100 times to obtain a 500ms delay +;------------------------------------------------------------ +Delay_500ms + MOVLW .100 ; WREG <- Decimal 100 + MOVWF delay_counter4 ; delay_counter4 <- WREG +LABEL_500ms_DELAY + CALL Delay_5ms ; Call 5 microsecond delay + DECFSZ delay_counter4, F ; Do this 100 times. 100x5ms = 500ms + GOTO LABEL_500ms_DELAY + RETURN + +;------------------------------------------------------------ +; Simply call Delay_5ms 200 times to obtain a 1sec delay +;------------------------------------------------------------ +Delay_1s + MOVLW .200 ; WREG <- Decimal 200 + MOVWF delay_counter4 ; delay_counter4 <- WREG +LABEL_1s_DELAY + CALL Delay_5ms ; Call 5 microsecond delay + DECFSZ delay_counter4, F ; Do this 200 times. 200x5ms = 1sec + GOTO LABEL_1s_DELAY + RETURN + + + + \ No newline at end of file