PicAXe to Serial Converter

Speddo

New Member
I am trying to have an 08M2 PicAxe send a message to an LCD
A 16x2 LCD module with a serial I2C 'piggyback' interface based on a PCF8574T serial to parallel converter.
Documentation says the slave address is 27h.
The PicAxe simulation will not recognize this address,
Error code as follows
" hi2csetup i2cmaster,%00100111,i2cslow,i2cbyte ; set up i2c master for LCD
^
Syntax error on line 5 at/before position 45
Error: Please use full 8 bit slave address (with bit0 clear)"
I tried $27 and $C6
$C6 produced no error, but did not write to the LCD.
Any help would be appreciated.
 

Attachments

oracacle

Senior Member
27h?
Can you post the data sheet. Hex only goes up to f, so that needs to be double checked.
IIRC with a picaxe, while it needs all 8 bit to compile, bit0 (furthest to the right) always needs to be zero. I think that is the read write bit which the picaxe alter itself.
also $27 and $C6 are wildly different numbers(29 and 198 respectively), I would suggest trying $26, or maybe $4E if you shift the bits one to the left.
 

Speddo

New Member
Hi, thanks for reply.
I tried $C6 earlier and your suggestion of $26 just now, still no display on the LCD
Seems like the slave address of the i2c is an enigma.
The only reason I was playing around with 27h was that this was the slave address used by arduino.
I will chase up the data sheet for the i2c interface
Is there some sort of polling (or ping) that can be done of any slave devices attached to a PicAxe and display results on the monitor?
 

AllyCat

Senior Member
Hi,

Welcome to the forum. $27 is (probably) the "7-bit" I2C address. Picaxe requires an 8-bit address, which will always be an even number (bit0 clear) as the Program Editor has said.

So you probably need to double the value to $4E - why did you try $C6 ? But there are variations in the Slave address for those modules.

Those I2C backpack LCDs are not "easy" to drive with a PICaxe, but there are now numerous threads on the topic, with "Reference" code from hippy (ao). There are also programs that will "scan" the I2C bus for all devices, but I don't have a link to hand.

Cheers, Alan.
 

hippy

Technical Support
Staff member
A 16x2 LCD module with a serial I2C 'piggyback' interface based on a PCF8574T serial to parallel converter.
It would be worth posting a link to the product or its datasheet. I suspect this is a dumb I2C Expander backpack which needs more than "hi2cout 0,("Hello!123",255) " and similar to drive it.

It might be worth trying the following code to see if that works ...

https://picaxeforum.co.uk/attachments/i2c-lcd-txt.11958
 

Speddo

New Member
Hi.
Thank you for your reply.
I loaded the code and it would not pass the simulation and reported a number of errors.
My limited knowledge did not allow me to understand the errors reported.
Thanks for again.
 

Speddo

New Member
Something like this can do that -

https://picaxeforum.co.uk/attachments/identify-003-bas.23690/

But, if the slave address is stated as '27' then it's almost certainly going to be '4E' for a PICAXE.
Thank you for your reply.
I had to modify the program, as below
PowerOnReset:
Pause 2000
'Gosub VoltCheck
PullUp %000110
High PWR
Pause 1000

Commented out the subroutine to stop it running as it did not terminate and it ran excellent in the search for the i2c interface which returned 7E.
I will test this result later today
I suggest to modify the gosub as below
VoltCheck:
Do
CalibAdc10 w0
w0 = 52378 / w0 * 2
BinToAscii w0, b15,b14,b13,b12,b11
SerTxd( "Vpsu = ", b13,".",b12,b11, "V")
Select Case w0
Case < 320 : SerTxd( " : Voltage < 3.2V" ) : Pause 500
Case > 340 : SerTxd( " : Voltage > 3.4V" ) : Pause 500
End Select
serTxd( CR, LF )
Loop Until w0 >= 320 And w0 =< 340 ' suggest this revision, w0 is 498 on first pass in simulation, or make the "and" into "or"?
Return


Many thanks
Speddo
 

kfjl

Member
I tried the program before posting and it just worked, as is, using the address 0x4E.

0x27: 010 0111

0x4E: 0100 1110 8-bit address for Picaxe = 0x27 shifted left once.

No capacitors, no pullups, just a 08M2 and the module.
 

kfjl

Member
0x27 is the 7-bit address of a PCF8574T, which is what you said you have in post#1. So you would use 0x4E with a Picaxe.

0x3F is the 7-bit address of a PCF8574A, so you would use 0x7E with a Picaxe.

It would NOT have worked with an Arduino using the address 0x27.
 

Speddo

New Member
I tried the program before posting and it just worked, as is, using the address 0x4E.

0x27: 010 0111

0x4E: 0100 1110 8-bit address for Picaxe = 0x27 shifted left once.

No capacitors, no pullups, just a 08M2 and the module.
Just a note on that "27h" - Adding an "h" at the end is an old-style way of indicating a hexadecimal number, so same as 0x27 or $27.
Hello Hippy.
Thanks for the reply.
I will try the address you have given, will be a few days to do so, been busy this end.
Regards.
Speddo
 

AllyCat

Senior Member
Hi,

Just an update to this thread. It became apparent that the Program Code linked in #7 had been designed for a specific purpose and hardware, so could not be normally used as a generic "I2C Bus Search" routine without some modifications. Therefore, I have revised the program to be more usable "Off the Shelf" and hopefully to trap a few of the classic "gotchas".

Of course there is an enormous number of PICaxe and I2C chip permutations and I have so far tested only a few I2C devices with a 20M2. The program now should be usable with all M2s, perhaps the 20X2 and some of the legacy PICaxes. I'll leave it for somebody else to add the other X2 chips (since I don't have any to test) but I might fix some bugs if any are reported. However, the permutations for "Conditional Compilation" are quite complex, particularly as I have attempted to maintain compatibilty with (Mac)AxePad and PE5.
Code:
; **  Find Devices on I2C Bus  IDENTIFY-003  Revised by AllyCat April 20  **

#define picaxe20    ; Choose from 08,14,18 or 20 pin chips. Check PWR/GND pin outputs if used
#no_data
#terminal 4800

#ifdef picaxe08
#picaxe 08m2
#define ok
Symbol SCL = C.1 : Symbol pinSCL = pinC.1    ; Leg 6
Symbol SDA = C.2 : Symbol pinSDA = pinC.2    ; Leg 5
;Symbol PWR = C.4                                    ; Leg 3
;Symbol GND = C.0                                    ; Leg 7 (SerOut defaults to GND)
Symbol MINVOLTS = 240                            ; Tens of mV (for 08M2)
#endif

#ifdef Picaxe14
#Picaxe 14M2
#define ok
Symbol SCL = B.3 : Symbol pinSCL = pinB.7 ; Leg 10
Symbol SDA = B.4 : Symbol pinSDA = pinB.5    ; Leg 9
;Symbol PWR = B.5                                    ; Leg 8
;Symbol GND = B.2                                    ; Leg 11
Symbol MINVOLTS = 190
#endif

#ifdef Picaxe18
#Picaxe 18M2
#define ok
Symbol SCL = B.4 : Symbol pinSCL = pinB.4    ; Leg 10
Symbol SDA = B.1 : Symbol pinSDA = pinB.1    ; Leg 7
;Symbol PWR = B.0                                    ; Leg 6
;Symbol GND = B.7                                    ; Leg 13
Symbol MINVOLTS = 190
#endif

#ifdef picaxe20
#picaxe 20m2
#define ok
Symbol SCL = B.7 : Symbol pinSCL = pinB.7      ; Leg 11 (Linked to B.4 Leg 14)
Symbol SDA = B.5 : Symbol pinSDA = pinB.5        ; Leg 13
;Symbol PWR = B.6                                        ; Leg 12
;symbol GND = B.2                                        ; Leg 16
Symbol MINVOLTS = 190
#endif

#ifNdef ok
sertxd("Sorry,Pinout not available")
Symbol SCL = 0 : Symbol pinSCL = pin0     ; Dummy values to avoid syntax errors
Symbol SDA = 0 : Symbol pinSDA = pin0
Symbol MINVOLTS = 0
stop
#endif

Symbol GND = 0                    ; Editor will report error if already defined
Symbol PWR = 0                    ; Editor will report error if already defined
Symbol MAXVOLTS = 550        ; Tens of mV
sertxd(cr,lf,"SCL= ",#SCL,"  SDA= ",#SDA,"  V+= ",#PWR,"  GND=",#GND,cr,lf)

;        .-----_-----.          Typical I2C header
; Vdd ---| V+     0V |--- 0V              .-.
;       -| SI    C.0 |--+         +------>|O| PWR
;    +---| C.4   C.1 |--|-- SCL --|-------|O| SCL
;    |  -| C.3   C.2 |--|-- SDA --|-------|O| SDA
;    |   `-----------'  +---------|-------|O| 0V
;    +----------------------------+       `-'
;                   
; Some breakout boards include pull-ups for SDA and SCL
; This program uses internal pull-ups if external pull-ups are missing

; **  Main Program  **

do
PowerOnReset:
  Pause 1000
  Gosub VoltCheck
  b0 = PWR                ; Can't compare constants
  if b0 <> GND then
    High PWR
    Low GND
  endif
  Gosub BusCheck            ; And enable pullups if required
  Pause 100

MainLoop:
; Do
    SerTxd( CR, LF, "Looking for Devices ...", CR, LF )
    Gosub FindDevices
     pullup OFF
    Pause 4000
  Loop

; **  Check PSU Voltage and Bus hardware  **

VoltCheck:
  Do
#ifdef simulating
        w0 = 500
#else
    calibadc10 w0
    w0 = w0 / 2 + 52378 / w0
     calibadc10 w1                    ; Oversample to average and for 10mV resolution
     w0 = 52378 / w1 + w0
#endif
    BinToAscii w0, b13,b13,b13,b12,b11
    SerTxd( cr,lf, "Vpsu = ", b13,".",b12,b11, "Volts")
    Select Case w0
      Case < MINVOLTS : SerTxd( ": Supply too Low", cr, lf )
      Case > MAXVOLTS : SerTxd( ": Supply too High", cr, lf )
    End Select
  Pause 500
  Loop Until w0 >= MINVOLTS and w0 =< MAXVOLTS
  Return

BusCheck:
    pullup OFF
    low SDA                            ; Take Low now to catch a SDA-SCL bridge
    low SCL
    input SCL                        ; Float pin
;    pause 10                            ; Maybe needed for high pullup resistance or bus capacitance
    if pinSCL = 0 then
        gosub pullups                ; PULLUP command cannot use a variable (PE6 can use #define)
        if pinSCL = 0 then
            sertxd(cr,lf,"SCL held Low")
        else
        sertxd(cr,lf,"No SCL Pullup")
    endif
    pullup OFF
    endif
    input SDA
;    pause 10                        ; Maybe needed for high pullup resistance or bus capacitance
    if pinSDA = 0 then
        gosub pullups
        if pinSDA = 0 then
            sertxd(cr,lf,"SDA held Low")
        else
            sertxd(cr,lf,"No SDA Pullup")
        endif
    endif           ; Now fall into pullups in case SCL needs a pullup
pullups:
#ifdef picaxe08
    pullup %110
#endif
#ifdef picaxe14
    pullup %11000
#endif
#ifdef picaxe18
    pullup %10010
#endif
#ifdef picaxe20
    pullup %10100000
#endif
; pause 10                        ; Maybe needed for high pullup resitance or bus capacitance
return

; **  Search For Devices  **

FindDevices:
  SerTxd( CR, LF, " ")
  For b0 = $00 To $1F Step 2
    If b0 = $10 Then
      SerTxd( "    " )
    End If
    SerTxd( "  " ) : Gosub HexLsd
  Next
  b10 = $00             ; Address to try
  b12 = $00             ; Address found
  Do
    b0 = b10 & $1F
    Select Case b0
      Case $00
        SerTxd( CR, LF )
        b0 = b10 / $10 : Gosub HexLsd
      Case $10
        SerTxd( "   " )
        b0 = b10 / $10 : Gosub HexLsd
    End Select
    If b10 < $10 Or b10 >= $F0 Then
      SerTxd( " XX" )
    Else
      Gosub CheckForDevice
    End If
    b10 = b10 + 2
  Loop Until b10 = 0
  SerTxd( CR, LF, CR, LF )
  b0 = b12 and 254
  if b0 = 0 then : SerTxd( "No devices found" )
  else
    if b0 <> b12 then
      SerTxd( "Multiple devices, Last was at " )
    else
      SerTxd( "Device found at " )
    endif
        Gosub Hex
      Select Case b0
          Case $78 : SerTxd ( "  SSD1306 OLED" )
        Case $A0 to $A7 : SerTxd ( "  EEPROM" )
        Case $A4 : SerTxd ( "  Wii Controller" )
        Case $A6 : SerTxd ( "  Wii Motion Plus" )
        Case $D0 : SerTxd ( "  RTC (Maxim)" )
          Case $DE : SerTxd ( "  RTC (MCP7940)" )
      End Select
  endif
  SerTxd( CR, LF )
  Return

CheckForDevice:
; Gosub ResetBus
  Gosub SendStart
  b0 = b10 Or 1                 ; Read bit
  Gosub SendByte
  Gosub ReadAck
; Gosub SendStop
  If b0 = 0 Then
    ; Ack
    If b12 = $00 Then
      b12 = b10
    Else
      b12 = b10 + 1            ; Mark that this is not the first find
    End If
    SerTxd( " " ) : b0 = b10 : Gosub Hex
  Else
    ; Nak
    SerTxd( " --" )
  End If
  Gosub ReadByte
  Gosub SendNack
  Gosub SendStop   
  Return

; **  Low-Level I2C Routines  **

SendStart:
  Input SCL ; SCL = 1
  Gosub Stretch
  Input SDA ; SDA = 1
  Low   SDA ; SDA = 0
  Low   SCL ; SCL = 0
  Return

ResetBus:
  Input SDA ; SDA = 1
  Low   SCL ; SCL = 0
  For b1 = 0 To 8
    Input SCL ; SCL = 1
    Low   SCL ; SCL = 0
  Next

SendStop:
  Low   SDA ; SDA = 0
  Low   SCL ; SCL = 0
  Input SCL ; SCL = 1
  Gosub Stretch
  Input SDA ; SDA = 1
  Return

SendByte:
  For b1 = 0 To 7
    If bit7 = 0 Then
      Low   SDA ; SDA = 0
    Else
      Input SDA ; SDA = 1
    End If
    Input   SCL ; SCL = 1
    Gosub   Stretch
    Low     SCL ; SCL = 0
    b0 = b0 + b0
  Next
  Return

ReadByte:
  Low   SCL ; SCL = 0
  Input SDA ; SDA = 1
  For b1 = 0 To 7
    Input   SCL ; SCL = 1
    Gosub   Stretch
    b0 = b0 + b0 + pinSDA
    Low     SCL ; SCL = 0
  Next
  Return

ReadAck:
  Input SDA ; SDA = 1
  Input SCL ; SCL = 1
  Gosub Stretch
  b0  = pinSDA
  Low   SCL ; SCL = 0
  Return

SendAck:
  Low   SDA ; SDA = 0
  Input SCL ; SCL = 1
  Gosub Stretch
  Low   SCL ; SCL = 0
  Return

SendNack:
  Input SDA ; SDA = 1
  Input SCL ; SCL = 1
  Gosub Stretch
  Low   SCL ; SCL = 0
  Return

Stretch:
  Do : Loop While pinSCL = 0
  Return

; **  Display Output Routines  **

Hex:
  b1 = b0 / $10 : Gosub Nibble
HexLsd:
  b1 = b0
Nibble:
  b1 = b1 & $0F + "0"
  If b1 > "9" Then : b1 = b1 + 7 : End If
  SerTxd( b1 )
  Return

; **  End Of Program  **
Cheers, Alan.
 
Last edited:
Top