Notice for characters it is sending the data out to LCDD (LCD Data Register) whereas commands are being sent out to LCDI (LCD Instruction Register). This is using 8-bit parallel mode on a Hitachi display, however the point is how the main code handles things, which I forgot to include. If you notice, the HL register pair is the address reference, so before I call PRINT I do something like this:
KNIGHT LD HL,KDATA
CALL PRINT
RET
KDATA .BYTE $0C,"PROGRAMMING COPYRIGHT 1994 CHRIS SAVAGE",$07,$00
KDATA is a label and .byte is the equivalent of the BS2 DATA statement. The $00 is a null terminator. The $0C clears the screen, while the $07 beeps a piezo speaker. When I call (GOSUB) to KNIGHT, it loads the HL register pair with the address of the data at KDATA and then starts printing one character at a time until it hits the $00.
You can make a subroutine to handle all this in PBASIC so that for a string you need only pass the address of the DATA block to it and the subroutine will send all the characters until it hits the NULL (0). With planning it could handle special characters as my routine did.
One more thing - will I be able to send "Hello world" as a single string when using I2COUT or do I have to brake it and send char after character instead?
You can send a single string like "Hello world" using the string formatter. See page 232 of the "BASIC Stamp Syntax and Reference Manual Version 2.2"
Actually in this case that won't work. If you create a subroutine to handle to individual writes, you can also create a string subroutine to take a zero-delimited string and send it one character at a time calling the data subroutine.
Ah yes, forgot that this was going through the I2C to parallel interface to get to the LCD.
Thanks for catching my mistake.
Here is a sample code I cobbled together that puts the I2C transfer operation into a subroutine. This code is by no means complete but you should be able to utilize some of it for your project. The compiler says the syntax is good, however, there may be a flaw in the logic which may crop up when uploading to your stamp. You may have to add some delay after the RETURN if the datasheet for the LCD requires it, such as after a clear display operation.
' PCF8574 I2C LCD test
' {$STAMP BS2p}
' {$PBASIC 2.5}
sda PIN 0
slave CON $27 ' or whatever your device address is
char VAR Byte ' holds what you want to send
upper VAR char.HIGHNIB
lower VAR char.LOWNIB
buffer VAR Byte
val VAR buffer.HIGHNIB
brs VAR buffer.BIT0
brw VAR buffer.BIT1
bcs VAR buffer.BIT2
bbl VAR buffer.BIT3
rs VAR Bit ' you set these three
rw VAR Bit '
bl VAR Bit '
' Your main program will need to place into variable 'char' the byte
' you want to transfer to the LCD. You also need to set up 3 additional
' bit variables as follows:
' rs = 0 for an instruction ( clear the display, cursor movement, etc)
' rs = 1 for data transfer (stuff to display)
' rw = 0 for writing to LCD
' rw = 1 for reading from LCD
' bl = 0 for backlight OFF
' bl = 1 for backlight ON
'Once these four variables have been set up then call the transfer
' subroutine to transfer the byte to the LCD. The subroutine will
' return to the following instruction after the call.
main:
' do your thing here like the following...
char = $31
rs = 1
rw = 0
bl = 1
GOSUB send2
'
' do more of your thing here
'
'
GOTO main
send2:
val = upper
brs = rs
brw = rw
bcs = 0 ' number 0
bbl = bl
I2COUT sda, slave, [buffer]
bcs = 1
I2COUT sda, slave, [buffer]
val = lower
bcs = 0
I2COUT sda, slave, [buffer]
bcs = 1
I2COUT sda, slave, [buffer] ' LCD now has received the value you placed in 'char'
RETURN
I find a regal one BS2px and I will use with TWI LCD (PCF8574T and 20*4 LCD).
I have read all, what write here, but do't work. The I2C LCD with Arduino work fine.
The address for PCF it set to $20.
Can someone modify this prog for me to working?
' {$STAMP BS2px}
' {$PBASIC 2.5}
#IF ($STAMP < BS2P) #THEN
#ERROR "Program requires BS2p, BS2pe, or BS2px."
#ENDIF
SDA PIN 8 ' SDA DATA line is connected TO BS2P PIN8; pullup 1k
SCL PIN 9 ' SCL clock line is connected to BS2p PIN9; pullup 1k
addr CON $20 ' unique SlaveID address; 0x27 for PCF8574T, 0x37 for PCF8574AT
' HD44780 control characters
' use Shift Left operator (<<) when in 4-bit mode
'
ClrLCD CON $01 ' clear display
Cur_Hm CON $02 ' move cursor to Home position
Set_8b CON $03 ' set 8-bit mode
Cur_Lf CON $10 ' move cursor left
Cur_Rt CON $14 ' move cursor right
DispLf CON $18 ' shift displayed chars left
DispRt CON $1C ' shift displayed chars right
DDRam CON $80 ' Display Data RAM control
' --- [Main] ---
PAUSE 1000
I2COUT SDA, addr, [$03<<4] ' set mode
PAUSE 100
I2COUT SDA, addr, [$03<<4] ' set mode
PAUSE 100
I2COUT SDA, addr, [$03<<4] ' set mode
PAUSE 100
I2COUT SDA, addr, [$02<<4] ' initial 4-bit interface
PAUSE 100
I2COUT SDA, addr, [$02<<4] ' 'Function Set'
I2COUT SDA, addr, [$10<<4] ' I=1, N=1 (2-line display), F=0 (5x8 font)
PAUSE 100
I2COUT SDA, addr, [$00] ' ...no delay needed between sending 2 groups
I2COUT SDA, addr, [$08<<4] ' display ON/OFF control; D=0, C=0, B=0
PAUSE 100
I2COUT SDA, addr, [$00] ' ...no delay between sending 2 groups
I2COUT SDA, addr, [$01<<4] ' Clear Display
PAUSE 100
I2COUT SDA, addr, [$00] ' ...no delay between sending 2 groups
I2COUT SDA, addr, [$06<<4] ' Entry Mode Set (I/D=1, S=1)
'I2COUT SDA, addr, [0 1 I/D S] ' Entry Mode Set (I/D and S as required)
PAUSE 100
' *** Initialization END ****
I2COUT SDA, addr, [$00] ' ...no delay between sending 2 groups
I2COUT SDA, addr, [$FF<<4] ' display ON, cursor ON and blinking, D=1, C=1, B=1
PAUSE 100
I2COUT SDA, addr, ["Test"]
For a Basic Stamp the address of the PCF8574 is an 8 bit address, $40. Arduino uses a 7 bit address, requiring $40 to be shifted right once for 0x20. Is this PCF8574 interface of your making or did you get it from Amazon or eBay? The ones you normally buy usually have pins 1, 2, & 3 of the PCF8574 tied to VCC or +5, which would make the address $4E.
Also, please look over this thread and try to understand that once the LCD has been placed in 4-bit mode, each character you send to the LCD has to be sent in two parts, the upper nibble (4 bits) and the lower nibble. AND each nibble has to be sent twice - the first time with E low and the second time with E high - in other words toggling the E bit. So, each 8 bit character you wish to send to the LCD has to be sent in four transmissions over the I2C bus. The first four init characters are sent in 8-bit mode, but the LCD ignores the upper nibble. Each of the first four characters has to be sent twice to toggle the E bit.
BTW, I have a BS2px I2C - LCD demo program I put together about a year ago, if you want it I will post it here. It displays three lines of text on a 4x20 LCD and on the 4th line it counts up to 65, 535.
BTW, I have a BS2px I2C - LCD demo program I put together about a year ago, if you want it I will post it here. It displays three lines of text on a 4x20 LCD and on the 4th line it counts up to 65, 535.
Thanks for You answer.
If can You post Yours demo prog, It would be great, I would learn from it.
Here you go, make sure the connections are the same as indicated in the comments at the top.
' PCF8574 I2C LCD Demo with 32x2 LCD 4-bit
' {$STAMP BS2px}
' {$PBASIC 2.5}
' A small demonstration on using an I2c interfaced LCD with a BS2px
' series Basic Stamp.
' This is for a 20x4 LCD using an interface which uses a PCF8574 I2C
' Port expander chip and has A0, A1, & A2 tied to Vcc for a device
' address of $4E. If your interface has the PCF8574A chip then the
' address would be $7E. PBasic uses 8-bit addresses but it still
' controls the RW bit, bit 0. These 20x4 display modules have a
' backlight controlled by the bl bit defined below. Seems to work
' best by setting bl hi and then lo in the I2C_Send function for
' lowered intensity. Setting bl hi both times will yield a very bright
' backlight, drawing an additional 4 mA from the power source.
' Your main program will need to place into variable 'char' the byte
' you want to transfer to the LCD. You also need to set up 2 additional
' bit variables as follows:
' rs = 0 for an instruction
' rs = 1 for data transfer
' rw = 0 for writing to LCD, usually always 0
' rw = 1 for reading from LCD
' Once these two variables have been set up then call the transfer
' subroutine "send_byte" to transfer the byte to the LCD and takes care
' of sending the correct nibbles and toggling the E bit.
' CONNECTIONS:
' BS2Px Board PCF8574T LCD
' +5 - - - - - 1, 2, 3, 16 - - - - 2
' Gnd - - - - - - - 8 - - - - - - - 1
' P0 - - - SDA - - 15
' P1 - - - SCL - - 14
' 4 - - E - - 6
' 5 - - RS - - 4
' 6 - - RW - - 5
' 7 - - BL - - BL driver
' 9 - - DB4 - - 11
' 10 - - DB5 - - 12
' 11 - - DB6 - - 13
' 12 - - DB7 - - 14
' NOTE!
' At init time the E, RS, & R/W signals are established LOW per datasheet with
' an initial I2C transfer of $00 to the PCF8574. With E low changes can be
' made to the RS, R/W, and data lines. Then the E bit is set to HI and the
' entire byte is sent to the PCF8574, then E is brought LOW and the byte is
' again sent to the PCF8574. This procedure "toggles" the E bit.
' Instead of shifting nibbles around I took advantage of a PBasic feature that
' lets me re-define bits and nibbles of variables.
' DELAYS:
' The first 4 init operations use two I2C operations, all other data transfers
' to the LCD uses 4 I2COUT operations per character which slows things down to
' where operational delays required for Clear Screen or Home cursor are not
' needed.
' Let the show begin...
'-------------------------------------------------------------------------------
DATA $30, $30, $30, $20, $28, $08, $01, $06, $0C, 0 ' init sequence opcodes
Msg1 DATA " BS2px-->I2C-->LCD ", 0
Msg2 DATA " Demonstration ", 0
Msg3 DATA " Counting to 65,535 ", 0
Msg4 DATA " ", 0
SDA PIN 0 ' can be P0, P1, P8, or P9
LCD CON $4E ' For PCF8574T, (pins 1, 2, & 3 tied to +5)
hi CON 1
lo CON 0
dat CON 1 ' RS data mode
cmd CON 0 ' RS command mode
' LCD Line addresses
L1 CON $80 ' LCD top line
L2 CON $C0 ' LCD line 2
L3 CON $94 ' LCD line 3
L4 CON $D4 ' LCD line 4
L4C CON L4 + 7 ' location of count on display
EndCnt CON $FFFF ' that's 65535
TenK CON 10000 ' factor Digit 5
OneK CON 1000 ' factor Digit 4
OneH CON 100 ' factor Digit 3
Ten CON 10 ' factor Digit 2
char VAR Byte ' byte to send over bus
upper VAR char.HIGHNIB ' upper nibble of char
lower VAR char.LOWNIB ' lower nibble of char
buff VAR Byte ' sent to the PCF8574
val VAR buff.HIGHNIB ' upper nibble of buff
rs VAR buff.BIT0 ' 0 = command, 1 = data
rw VAR buff.BIT1 ' 0 = write to LCD, 1 = read from LCD
E VAR buff.BIT2 ' handled by I2C_send subroutine
bl VAR buff.BIT3 ' backlight, 1 = on
strAddr VAR Byte ' EEPROM string char address
idx VAR Byte ' FOR...NEXT index
cnt VAR Word ' counter
temp VAR Word ' for cacalations
factor VAR Word ' " "
'-------------------------------------------------------------------------------
MAIN:
GOSUB LCDINIT ' Sort of speaks for itself, no?
GOSUB String_Out ' display EEPROM strings
GOSUB counting ' do the count on line 4
END ' Go to sleep, little Stamp
'--------------------- send upper then lower nibble ----------------------------
send_byte:
val = upper ' val is buff high, upper is char high
GOSUB I2C_send ' send buff down the line to PCF8574
val = lower ' lower is the low nibble of char
GOSUB I2C_send ' send buff again to PCF8574
RETURN ' go back to where you came from
'-------------------- toggle the E and bl line ---------------------------------
' NOTE! RS, RW, & data must be properly set up before calling this sub
I2C_send: ' send buff to PCF8574 & toggles E
E = hi
bl = hi ' backlight on
I2COUT SDA, LCD, [buff] ' now raise the E line
E = lo
bl = lo ' backlight off for half intensity
I2COUT SDA, LCD, [buff] ' now E is back to lo
RETURN
'------------------ Display stored strings -------------------------------------
String_Out:
strAddr = Msg1 ' point to message 1
char = L1 ' top line
GOSUB send_msg ' display first msg
strAddr = Msg2 ' point to message 2
char = L2 ' 2nd line
GOSUB send_msg ' display 2nd msg
strAddr = Msg3 ' point to message 3
char = L3 ' 3rd line
GOSUB send_msg ' display 3rd msg
strAddr = Msg4 ' point to message 4
char = L4 ' 4th line
GOSUB send_msg ' erase 4th line
RETURN
'------------------ send out selected string -----------------------------------
' pointers to msg to send and to which line was set up in sub String_Out:
send_msg:
rs = cmd ' set RS to command
GOSUB send_byte ' position cursor at selected location
rs = dat ' set RS to DATA
DO
READ strAddr, char ' read next byte from string in EEPROM
strAddr = strAddr + hi ' increment string pointer
IF char = lo THEN EXIT ' if done with this string, EXIT
GOSUB send_byte ' NO! Display char on LCD
LOOP ' repeat the do-While loop
RETURN
'------------------ count and display counter ----------------------------------
counting:
FOR cnt = hi TO EndCnt ' a massive undertaking
rs = cmd ' set RS to command
char = L4C ' position cursor at line 4 col 7
GOSUB send_byte ' execute the command
rs = dat ' set RS to DATA
temp = cnt ' temp will be our work space & preserves cnt
factor = TenK ' start with leftmost digit
DO ' start a 'do' loop
IF cnt < factor THEN ' suppress leading 0 at factor location
char = " " ' send a space instead of "0"
ELSEIF factor = OneH AND cnt >= OneK THEN ' do we need a comma?
char = "," ' place a comma between hundreds and thousands
GOSUB send_byte ' and send it to the LCD
GOTO Skip_one ' skip the next statement
ELSE
Skip_one:
char = temp / factor + "0" ' get digit and ASCII-fy
ENDIF
GOSUB send_byte ' and display it
temp = temp // factor ' modulus division to remove msd
factor = factor / Ten ' point to next lower digit
LOOP UNTIL factor = lo ' our end condition
NEXT
RETURN
'-------------------- Initialize the display -----------------------------------
LCDINIT:
PAUSE(15) ' power up pause
buff = $00 ' set all LCD pins low
I2COUT SDA, LCD, [buff] ' ensure RS, RW, E & BL are now low
' 44780 starts in 8 bit mode but ignores hi nibble for first 4 init instructions
' We now pull bytes from the first DATA stream defined at the beginning and
' send them to the LCD for initialization.
FOR idx = 0 TO 3 ' 1st 4 ops are in 8-bit mode
READ idx, char ' fetch init byte from list in EEPROM
val = upper ' val = buff high nib , upper = char high nib
GOSUB I2C_send ' transfer buff to LCD
NEXT ' do this four times
' Now in 4 bit mode, finish init operation
FOR idx = 4 TO 8 ' five more init steps
READ idx, char ' fetch next init byte from list in EEPROM
GOSUB send_byte ' transfer cmd to LCD
NEXT ' do this five times
RETURN ' init is finished
'-------------------------------------------------------------------------------
Comments
KDATA is a label and .byte is the equivalent of the BS2 DATA statement. The $00 is a null terminator. The $0C clears the screen, while the $07 beeps a piezo speaker. When I call (GOSUB) to KNIGHT, it loads the HL register pair with the address of the data at KDATA and then starts printing one character at a time until it hits the $00.
You can make a subroutine to handle all this in PBASIC so that for a string you need only pass the address of the DATA block to it and the subroutine will send all the characters until it hits the NULL (0). With planning it could handle special characters as my routine did.
Ah yes, forgot that this was going through the I2C to parallel interface to get to the LCD.
Thanks for catching my mistake.
I find a regal one BS2px and I will use with TWI LCD (PCF8574T and 20*4 LCD).
I have read all, what write here, but do't work. The I2C LCD with Arduino work fine.
The address for PCF it set to $20.
Can someone modify this prog for me to working?
Also, please look over this thread and try to understand that once the LCD has been placed in 4-bit mode, each character you send to the LCD has to be sent in two parts, the upper nibble (4 bits) and the lower nibble. AND each nibble has to be sent twice - the first time with E low and the second time with E high - in other words toggling the E bit. So, each 8 bit character you wish to send to the LCD has to be sent in four transmissions over the I2C bus. The first four init characters are sent in 8-bit mode, but the LCD ignores the upper nibble. Each of the first four characters has to be sent twice to toggle the E bit.
BTW, I have a BS2px I2C - LCD demo program I put together about a year ago, if you want it I will post it here. It displays three lines of text on a 4x20 LCD and on the 4th line it counts up to 65, 535.
Thanks for You answer.
If can You post Yours demo prog, It would be great, I would learn from it.
With PCF 8583, PCF 8591 and 24C02 can I do all.
Thanks again!