I2C I/O expander voor 1602 LCD
Het gebruik van Alfa Numerieke (HD44780 compatible) displays vergt normaal gesproken minimaal 6 I/O poorten van de controller waarop deze is aangesloten. (4x data, RS, EN en eventueel R/W)
Met het gebruik van een I/O expander chip als de PCF8574 (IC2 aangestuurd, 8 I/O poorten) kan dit terug gebracht worden naar 2 poorten. (SCL en SDA)
Een en ander gaat natuurlijk wel ten koste van een stukje extra firmware in de controller, voor een PIC18F25K2x betreft dit ongeveer 1% van de totale capaciteit.
In PICBASIC (Proton) kan men dit realiseren d.m.v. het “Print” commando uit te schakelen en te vervangen door een stuk code die het 1602 display aanstuurt via de 2 I2C poorten.
Op het Protonbasic forum wat code gevonden die dit doet.
De code is bedoeld voor PIC’s die beschikken over hardware I2C (Synchronous Serial Port (SSP) of (MSSP))
Op het bovenstaande Protonbasic forum item is ook een “I2CPrintSoftCommand.inc” include file te vinden waarmee je elke I/O pin op de PIC als SCL en SDA aan kunt sturen.
Hieronder een stukje demo code met als belangrijkste onderdeel de include file “I2CPrintHardCommand.inc”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | Device = 18F25K22 XTAL = 8 OSCCON = %01100000 ;Internal osc on 8Mhz ANSELA = %00000000 ;Digitaal ANSELB = %00000000 ;Digitaal ANSELC = %00000000 ;Digitaal Symbol Led = LATA.5 Symbol Speaker = PORTC.5 Declare Show_System_Variables = On Declare SLOW_BUS Off Declare HBUS_BITRATE 400 Clear Include "I2CPrintHardCommand.inc" ' you may need to select alternate config depending on your backpack ' ----------------------------- test data -------------------------------------------------------- Dim VFloat As Float Dim VDword As DWord Dim VSDword As SDword Dim VSWord As SWord Dim VWord As Word Dim VByte As Byte Dim VSByte As SByte Dim VBit As Bit DelayMS 1000 Main: Sound Speaker, [115,20] DelayMS 100 ' Wait for the LCD to initialise VFloat = 1.56789 VDword = 100 VSDword = 100 VSWord = 100 VWord = 100 VByte = 10 VSByte = 10 VBit = 1 Toggle Led Cls Print $FE, 3 ' backlight on On Next Call To Print Print At 1,1,"VF=",DEC4 VFloat," VD=",Dec VDword Print At 2,1,"VSD=",Dec VSDword," VS=",Dec VSWord DelayMS 2000 Toggle Led Cls Print At 1,1,"VW=",HEX VWord," VB=",HEX VByte Print At 2,1,"VSB=",HEX VSByte," VB=",BIN VBit DelayMS 2000 Toggle Led Cls Print At 1,1,"AA"," ","AAA"," ","AAAA"," ", "AAAAA" Print At 2,1,"AAAAAA"," ","AAAAAAA" DelayMS 2000 Toggle Led Cls Print At 1,1,"Backlight off" DelayMS 250 Toggle Led Print $FE, 4 ' backlight off on next call to PRINT Print " " Low Led Stop ' ----------------------------- test data -------------------------------------------------------- CONFIG_START 'FOSC = HSMP ;external oscillator FOSC = INTIO67 ;Internal oscillator block, port function on RA6 and RA7 FCMEN = Off ;Fail-Safe Clock Monitor disabled IESO = Off ;internal external switchover mode PWRTEN = On ;power-up timer BOREN = On ;brown-out reset BORV = 285 ;brown-out reset value (2,7V) WDTEN = Off ;watchdog timer WDTPS = 128 ;1:128 WDT prescalar PBADEN = Off ;analog port B<4:0> STVREN = On ;;stack overflow reset LVP = Off ;low voltage programming XINST = Off ;Instruction set extension and Indexed Addressing mode disabled (Legacy mode) Debug = Off ;no debug CCP2MX = PORTB3 ;CCP2 input/output is multiplexed with RB3 CONFIG_END |
De incude file : “I2CPrintHardCommand.inc” welke het originele “Print” commando (en aanverwante commado’s als “Cls”) uitschakelt en vervangt door code die hetzelfde doet, maar dan via de I2C bus. De include file moet tijdens compileren van de .bas file in de zelfde directorie staan als de .bas file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | '***************************************************************************************************************** '* Name : I2CPrintHardCommand.inc * '* Purpose : allow Proton Print commands to access the standard 1602 LCD via I2C backpack board * '* Author : George Towler * '* Notice : I claim no copyright but maybe Barak does * '* Date : 18/01/2015 * '* Compiler: 3.5.7.1 * '* Version : 0.9.0 * '* Notes : see http://www.protonbasic.co.uk/showthread.php/62478-%93Print%94-command-for-SPI-Alfa-numeric-LCD * '* : post #6 Barak shows how to replace Proton commands and how to deal with control (FE$) bytes * '***************************************************************************************************************** #Disable Print ;Disable the Proton Print command ;*************************************************************************************************************** ; Configure items to suit your LCD and I2C hardware, I2CPrint_DataOnHighBits remmed if data is on low bits * ; * Symbol I2CPrint_address = %01001110 ' PCF8574 Slave Address 0,1,1,1,A2,A1,A0,RW where W=0 * Symbol I2CPrint_InitForLCDLines = $28 ' $28 for two lines * Symbol I2CPrint_RS = %00000001 ' * Symbol I2CPrint_RW = %00000010 ' * Symbol I2CPrint_E = %00000100 ' * Symbol I2CPrint_BackLight = %00001000 ' * $define I2CPrint_DataOnHighBits ' * ;*************************************************************************************************************** Symbol I2CPrint_RS_E = I2CPrint_RS | I2CPrint_E $ifdef I2CPrint_DataOnHighBits Symbol I2CPrint_Init1 = %00110000 Symbol I2CPrint_Init1_E = %00110000 | I2CPrint_E Symbol I2CPrint_Init2 = %00110000 Symbol I2CPrint_Init2_E = %00110000 | I2CPrint_E Symbol I2CPrint_Init3 = %00100000 Symbol I2CPrint_Init3_E = %00100000 | I2CPrint_E $Else Symbol I2CPrint_Init1 = %00000011 Symbol I2CPrint_Init1_E = %00000011 | I2CPrint_E Symbol I2CPrint_Init2 = %00000011 Symbol I2CPrint_Init2_E = %00000011 | I2CPrint_E Symbol I2CPrint_Init3 = %00000010 Symbol I2CPrint_Init3_E = %00000010 | I2CPrint_E $EndIf Dim BPF As Byte SYSTEM Symbol I2CPrint_tComOrData = BPF.0 Symbol I2CPrint_tInitialised = BPF.1 Dim I2CPrint_PrintStore As Byte Dim I2CPrint_PrintData As Byte Dim I2CPrint_HighData As Byte Dim I2CPrint_LowData As Byte Dim I2CPrint_dummy As Byte Dim I2CPrint_RSFlag As Byte Dim Backlight_State As Byte GoTo I2CPrintCommand_End @Print ; assembler Print redirect Wreg_Byte I2CPrint_PrintStore ; save the W Register If I2CPrint_tInitialised = 0 Then ; Has LCD been inititalised? DelayMS 100 ; Power-on delay for slow display types HBusOut I2CPrint_address, [I2CPrint_Init1_E] ; E hi and send command nibble 0011 (3) HBusOut I2CPrint_address, [I2CPrint_Init1] ; E lo DelayMS 20 HBusOut I2CPrint_address, [I2CPrint_Init2_E] ; E hi and send command nibble 0011 (3) HBusOut I2CPrint_address, [I2CPrint_Init2] ; E lo DelayMS 20 HBusOut I2CPrint_address, [I2CPrint_Init3_E] ; E hi and send command nibble 0010 (2) HBusOut I2CPrint_address, [I2CPrint_Init3] ; E lo DelayMS 20 I2CPrint_PrintData = I2CPrint_InitForLCDLines ; 4 bit mode and n lines GoSub I2CPrint_SendControl I2CPrint_PrintData = $0C ; enable display, cursor and blink off GoSub I2CPrint_SendControl I2CPrint_PrintData = $06 ; move cursor after each write GoSub I2CPrint_SendControl I2CPrint_PrintData = $80 ; goto column 1 line 1 GoSub I2CPrint_SendControl Set I2CPrint_tInitialised ; Indicate that the LCD is initialised EndIf I2CPrint_PrintData = I2CPrint_PrintStore If I2CPrint_PrintData = 0xFE Then ; it is a command header I2CPrint_RSFlag = 0 ; clear a flag so we know the next byte will be a command Else If I2CPrint_RSFlag = 0 Then ; this is a command byte If I2CPrint_PrintData = 03 Then Backlight_State = I2CPrint_BackLight ElseIf I2CPrint_PrintData = 04 Then Backlight_State = 0 Else GoSub I2CPrint_SendControl End If Else GoSub I2CPrint_SendData EndIf I2CPrint_RSFlag = 1 ; set the flag so the next byte will be send as Data EndIf Byte_Wreg I2CPrint_PrintStore ; restore the W register Return ' **************************************************************************** ' ** S U B R O U T I N E S ** ' **************************************************************************** I2CPrint_SendData: $ifdef I2CPrint_DataOnHighBits I2CPrint_HighData = I2CPrint_PrintData & %11110000 ; mask LSBs I2CPrint_LowData = I2CPrint_PrintData << 4 ; shift left $Else I2CPrint_LowData = I2CPrint_PrintData & %00001111 ; mask MSBs I2CPrint_HighData = I2CPrint_PrintData >> 4 ; shift Right $EndIf I2CPrint_dummy = I2CPrint_RS_E | I2CPrint_HighData ; data and e hi I2CPrint_dummy = I2CPrint_dummy | Backlight_State ; data and e hi and bls HBusOut I2CPrint_address, [I2CPrint_dummy] I2CPrint_dummy = I2CPrint_RS | I2CPrint_HighData ; data and e lo I2CPrint_dummy = I2CPrint_dummy | Backlight_State ; data and e lo and bls HBusOut I2CPrint_address, [I2CPrint_dummy] I2CPrint_dummy = I2CPrint_RS | Backlight_State ; data and e hi HBusOut I2CPrint_address, [I2CPrint_dummy] ; Delay, RS on throughout I2CPrint_dummy = I2CPrint_RS_E | I2CPrint_LowData ; data and e hi I2CPrint_dummy = I2CPrint_dummy | Backlight_State ; data and e hi and bls HBusOut I2CPrint_address, [I2CPrint_dummy] I2CPrint_dummy = I2CPrint_RS | I2CPrint_LowData ; data and e lo I2CPrint_dummy = I2CPrint_dummy | Backlight_State ; data and e lo and bls HBusOut I2CPrint_address, [I2CPrint_dummy] Return I2CPrint_SendControl: $ifdef I2CPrint_DataOnHighBits I2CPrint_HighData = I2CPrint_PrintData & %11110000 ; mask LSBs I2CPrint_LowData = I2CPrint_PrintData << 4 ; shift left $Else I2CPrint_LowData = I2CPrint_PrintData & %00001111 ; mask MSBs I2CPrint_HighData = I2CPrint_PrintData >> 4 ; shift Right $EndIf I2CPrint_dummy = I2CPrint_E | I2CPrint_HighData ; data and e hi I2CPrint_dummy = I2CPrint_dummy | Backlight_State ; data and e hi and bls HBusOut I2CPrint_address, [I2CPrint_dummy] I2CPrint_dummy = I2CPrint_HighData | Backlight_State ; data and e lo and bls HBusOut I2CPrint_address, [I2CPrint_dummy] I2CPrint_dummy = Backlight_State ; HBusOut I2CPrint_address, [I2CPrint_dummy] ; Delay I2CPrint_dummy = I2CPrint_E | I2CPrint_LowData ; data and e hi I2CPrint_dummy = I2CPrint_dummy | Backlight_State ; data and e hi and bls HBusOut I2CPrint_address, [I2CPrint_dummy] I2CPrint_dummy = I2CPrint_LowData | Backlight_State ; data and e lo and bls HBusOut I2CPrint_address, [I2CPrint_dummy] Return I2CPrintCommand_End: |