As long as you don’t have to constantly reinvent the
wheel, porting code is fun. So, instead of scratch-writing
a PICBASIC PRO delay routine, we’ll just reach into the
PICBASIC PRO bag of tricks and use the built-in PAUSE
function to port the C __delay_ms function:
;************************************************
cmd VAR BYTE
;************************************************
;* LCD_WriteCommand
;************************************************
LCD_WriteCommand:
regAddr = GPIO_A_ADDRESS
regData = $60
call LCD_WriteIOExpander
regAddr = GPIO_B_ADDRESS
regData = cmd
call LCD_WriteIOExpander
regAddr = GPIO_A_ADDRESS
regData = $20
call LCD_WriteIOExpander
return
void LCD_Initialize(void) {
LCD_WriteIOExpander(IO_DIR_A_ADDRESS, OUTPUT_
DIR);
LCD_WriteIOExpander(IO_DIR_B_ADDRESS, OUTPUT_
DIR);
LCD_WriteIOExpander(GPIO_A_ADDRESS, LCD_VDD_
EN);
__delay_ms(10);
LCD_WriteCommand(LCD_FUNCTION_SET);
__delay_ms(10);
LCD_WriteCommand(LCD_SET_DISPLAY);
__delay_ms(10);
LCD_WriteCommand(LCD_CLEAR);
__delay_ms(10);
LCD_WriteCommand(LCD_SET_DISPLAY);
__delay_ms(130);
LCD_WriteCommand(LCD_SET_DDRAM_ADDRESS);
__delay_ms(1);
}
;************************************************
;* LCD CONSTANTS
;************************************************
LCD_CLEAR CON $01
LCD_VDD_EN CON $20
LCD_FUNCTION_SET CON $3C
LCD_SET_DISPLAY CON $0C
LCD_SET_DDRAM_ADDRESS CON $80
LINE1_START_ADDRESS CON $80
LINE2_START_ADDRESS CON $C0
OUTPUT_DIR CON $00
;************************************************
;* LCD_Initialize
;************************************************
LCD_Initialize:
regAddr = IO_DIR_A_ADDRESS
regData = OUTPUT_DIR
call LCD_WriteIOExpander
regAddr = IO_DIR_B_ADDRESS
regData = OUTPUT_DIR
call LCD_WriteIOExpander
regAddr = GPIO_A_ADDRESS
regData = LCD_VDD_EN
call LCD_WriteIOExpander
pause 10
cmd = LCD_FUNCTION_SET
call LCD_WriteCommand
pause 10
cmd = LCD_SET_DISPLAY
call LCD_WriteCommand
pause 10
cmd = LCD_CLEAR
call LCD_WriteCommand
pause 10
cmd = LCD_SET_DISPLAY
call LCD_WriteCommand
pause 130
cmd = LCD_SET_DDRAM_ADDRESS
call LCD_WriteCommand
pause 1
return
As we continue to add to our base of LCD driver
functions, the easier the porting becomes. The LCD
initialize C function is based on the LCD_WriteIOExpander
and LCD_WriteCommand functions:
#define LCD_CLEAR 0x01
#define LCD_VDD_EN 0x20
#define LCD_FUNCTION_SET 0x3C
#define LCD_SET_DISPLAY 0x0C
#define LCD_SET_DDRAM_ADDRESS 0x80
#define LINE1_START_ADDRESS 0x80
#define LINE2_START_ADDRESS 0xC0
#define OUTPUT_DIR 0x00
The LCD is now under our control. All that’s left to
do is port the C source that writes human-readable stuff
to the display. There are four C functions we need to port.
The first function writes a single byte to the LCD via the
MCP23S17:
void LCD_WriteByte(uint8_t data) {
July/August 2018 81