PIC 18F4550 and MCP23017


Closed Thread
Results 1 to 13 of 13
  1. #1
    Join Date
    Mar 2008
    Location
    Gerogetown, Texas
    Posts
    94

    Default PIC 18F4550 and MCP23017

    I have seen some questions about using a port expanders, here is a version that works for the MCP23017, I am using MicroChip's USB boot loader. This program simply sets the 23017's PortA as inputs and PortB as outputs (driving LEDs). It also send the PortA value to the PC via USB.

    Code:
    define LOADER_USED 1        ' USB Boot loader
    define RESET_ORG 800h
    define INTERRUPT_ORG 808h
    DEFINE OSC 48
    DEFINE I2C_SCL PORTA,1
    DEFINE I2C_SDA PORTA,0
    Define I2C_SLOW 1     'At this clock speed this needed to be added to make it work.
    
    
    'define SHIFT_PAUSEUS 200
    ADCON1 = $F       'port A digital
    CMCON = 7         'PortA Digital
    
    USBBufferSizeMax   con 16  ' maximum buffer size
    USBBufferSizeTX    con 16  ' input 
    USBBufferSizeRX    con 16  ' output
    
    ' the USB buffer...
    USBBuffer        Var Byte[USBBufferSizeMax] 
    USBBufferOut     Var Byte[USBBufferSizeMax]
    USBBufferCount   Var Byte 
    Addr             var byte
    j                var byte
    i                var byte
    
    '======================================================================================
    ' Port A Registers (8 Bit Mode)
    IODIRA             con   $00          ' Direction Bit Control Reg
    IOBITSA            con	%11111111	' Direction Bit Settings Reg (0 = output, 1 = input)
    IPOLA              con	$01			' Interrupt Polarity Control Reg
    GPINTENA           con	$02			'Interrupt Enable Reg
    DEFVALA            con	$03
    INTCONA	           con	$04
    IOCONA	           con	$05			' I/O Configuration Reg
    IOCONSETA          con	%10111000	' IOCON register setting
    GPPUA	           con	$06			' Pull-Up Control Reg
    INTFA	           con	$07			' Interrupt Flag Register
    INTCAPA	           con	$08
    GPIOA	           con	$09			' General Purpose I/O
    IOLATA	           con	$0A			' Output Latch Reg
    
    'Port B Registers (8 Bit Mode)
    IODIRB	          con	$10			' Port B Direction Bit Control Address
    IOBITSB	          con	%00000000		' Port B Direction Bit Settings (0 = output, 1 = input)
    IPOLB	          con	$11			' Interrupt Polarity Control
    GPINTENB          con	$12			' Interrupt Enable Reg
    DEFVALB	          con	$13
    INTCONB	          con	$14
    IOCONB	          con	$15			' I/O Configuration Reg
    IOCONSETB         con	%10111000		' IOCON register setting
    GPPUB	          con	$16			' Pull-Up Control Reg
    INTFB	          con	$17			' Interrupt Flag Register
    INTPOLB	          con	$18
    GPIOB	          con	$19			' General Purpose I/O Reg
    IOLATB	          con	$1A			' Output Latch Reg
    
    '========================================================================================
    ' Port A Reguisters (16 Bit Mode)
    IODIRA16            con	    $00
    IODIRB16            con	    $01
    IOCONA16            con	    $0A
    IOCONB16            con	    $0B
    GPIOA16             con		$12
    GPIOB16             con		$13
    OLATA16             con		$14
    OLATB16             con		$15
    
    IO_EXP0WR           con	    $4E		' MCP23017  Write
    IO_EXP0RD           con	    $4F		' MCP23017  Read
    IO_DAT              var     byte    ' MCP23017  Data read
    IO_DAT_OLD          var     byte
    Out_Dat             var     byte
        '   Interrupt definition   
        '   ====================
            '   USB interrupt used to keep USB connection alive
    INCLUDE "DT_INTS-18.bas"    ' Base Interrupt System
    INCLUDE "ReEnterPBP-18.bas"     ' Include if using PBP interrupts
    ASM
    INT_LIST  macro    ; IntSource,         Label,  Type, ResetFlag?
            INT_Handler    USB_INT,  _DoUSBService,   ASM,  yes
        endm
        INT_CREATE               ; Creates the interrupt processor
    ENDASM
    usbinit ' initialise USB...
    USBService                                    ' keep connection alive
    UIE = $7F
    UEIE = $9F
    @   INT_ENABLE  USB_INT
    gosub InitMPC23017
    gosub ReInitPortA
    goto Programstart
    ' ************************************************************
    ' * Sub-routines                                             *
    ' ************************************************************
    DoUSBService:    'Keeps USB alive
        usbservice
    @   INT_RETURN
    
    
    ' ************************************************************
    ' * receive data from the USB bus                            *
    ' ************************************************************
    DoUSBIn:
       USBBufferCount = USBBufferSizeRX              ' RX buffer size
       'USBService                                    ' keep connection alive
       USBIn 1, USBBuffer, USBBufferCount, DoUSBIn   ' read data, if available
       return
        
    ' ************************************************************
    ' * wait for USB interface to attach                         *
    ' ************************************************************
    DoUSBOut:
       USBBufferCount = USBBufferSizeTX              ' TX buffer size
       'USBService                                    ' keep connection alive
       USBOut 1, USBBufferout, USBBufferCount, DoUSBOut ' if bus available, transmit data
       return
       
    InitMPC23017:
    Pause 100
    '#############  PORTA
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IOCONA,IOCONSETA]
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IODIRA,$0]          'PortA inputs
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IOLATA,$FF]            'PortA = 0
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IPOLA,0]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[DEFVALA,0]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[GPPUA,$FF]           'pull-ups enabled
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[INTCONA,0]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[GPINTENA,$FF]        'interupt on change
    '##############  PORTB
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IOCONB,IOCONSETB]
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IODIRB,0]
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IOLATB,$FF]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IPOLB,0]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[DEFVALB,0]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[INTCONB,0]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[GPINTENB,0]
    return
    ReInitPortA:
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IOCONA,IOCONSETA]
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IODIRA,$FF] 
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[GPPUA,$FF]           'pull-ups enabled
    
    return
    
    
    ' ************************************************************
    ' * main program loop - remember, you must keep the USB      *
    ' * connection alive with a call to USBService every couple  *
    ' * of milliseconds or so...                                 *
    
    ProgramStart: 
       'gosub DoUSBIn
       'gosub DoUSBOut
    i2cwrite PortA.0,PortA.1,IO_EXP0wr,[gpioa]
    i2cread PortA.0,PortA.1,IO_EXP0rd,[IO_dat] 
    if IO_DAT_OLD != io_dat then
    ''''   usbbufferout(0) = io_dat
       for j = 0 to 15
      usbbufferout(j) = io_dat
       next j
       gosub  dousbout
     out_dat = io_dat
       io_dat_old = io_dat
    
    endif
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[gpioB,out_dat]
    PAUSE 250
    ''i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[gpioB,0]
    ''PAUSE 250   
       
    goto ProgramStart  
    
       end
    Thanks

    Dave

  2. #2
    Join Date
    Nov 2003
    Location
    Wellton, U.S.A.
    Posts
    5,924


    Did you find this post helpful? Yes | No

    Default

    I have not played with USB much.
    This is something I will study from.
    Thanks
    Dave
    Always wear safety glasses while programming.

  3. #3
    Join Date
    Nov 2010
    Posts
    5


    Did you find this post helpful? Yes | No

    Default

    Hey Dave,
    Im trying to use 16f877a with macp23017, but I wasn't successful.
    I define the mcp23017 register, but when I want to compile my program it gives me error.
    I tried to use your program and learn from it but I had no success, I noticed you are using some include file that I dont have them.
    I have 16 led on each port would you please help me?

    Code:
    '*  Notes   :  XT 4Mhz                                          *
    '*          :                                                   *
    '****************************************************************
    'Includes 
    include "modedefs.bas" 
    '****************************************************************
    'Definitions
    DEFINE I2C_SDA PORTc,4 
    DEFINE I2C_SCL PORTc,3   
    '****************************************************************
    'Variables
    a var byte
    chip1 var byte
    chip2 var byte
    chip3 var byte
    chip4 var byte         
    '****************************************************************
    'Alias
    CP VAR PORTc.3
    DP VAR PORTc.4
                             
    '****************************************************************
    'Initialization
    
        'Pic 16f877A
    option_reg.7 = 0 'portb pullups enabled         
    SSPSTAT=%00111101
    'SSPCON1=%00101111
    SSPCON2=%00000001
    
        'MCP 23017
    
    IODIRA Con $00
    IODIRB con $00
    IPOLA con $00
    IPOLB con $00
    GPINTENA con &00
    GPINTENB con $00
    DEFVALA con $00
    DEFVALB con $00
    INTCONA con &00
    INTCONB con &FF
    IOCON con %00001000
    GPPUA con $00
    GPPUB con $00
    INTFA con $00
    INTFB con $00
    INTCAPA con &00
    INTCAPB con &00
    GPIOA con $00
    GPIOB Con $FF
    OLATA con $00
    OLATB con &FF  
    
    '****************************************************************
    'set ports   
         trisa=%00000000             
         trisc=%00000000     
         pause 500                 
         goto start          
    start:
        porta.5 = 1
        portc.7=0
        pause 500
        porta.5 = 1
        portc.7=1
        pause 500
        I2CWRITE dp,cp,$00,chip1,[%00000000] 'one-shot sample
        pause 200
        I2CWRITE dp,cp,$00,chip1,[%11111111] 'one-shot sample 
        pause 200
        I2CWRITE dp,cp,$00,chip1,[%00000000] 'one-shot sample
        pause 200
        I2CWRITE dp,cp,$00,chip1,[%11111111] 'one-shot sample 
        pause 200
         goto start   
    end
    Last edited by ScaleRobotics; - 27th November 2010 at 17:09. Reason: added code tags

  4. #4
    Join Date
    Mar 2008
    Location
    Gerogetown, Texas
    Posts
    94


    Did you find this post helpful? Yes | No

    Default

    What errors are you getting?

    The include files are for USB

    Dave

  5. #5
    Join Date
    Nov 2010
    Posts
    5


    Did you find this post helpful? Yes | No

    Default

    Thanks Dave,

    before i used to define 16f877a register like ( adcon = $82), so i thought it should be same to define mcp registers like (IODIRA = $00 to make my mcp port a as output), I got my first error there ( syntax error, red color on my whole line) then I saw that you define by constant. so i changed my method and followed you and defined the by using "con". but something happens that I dont understand it gives me error when i define GPINTENA con &00, but it accepts GPINTENB con &00 after seeing this I told myself ok im going to use assembly language and i will insert it to my Picbasic as a sub routin. I know that i have to Equate all register and variable like ( eecon1 equ h'08' ) but I think those are for my pic and i dont know how i shoud have access to MCP register to for example turn the pull ups on or off
    I think I'm totally lost. I thought that i define my chip one time (which pin is input and which one output, interrupts, pull ups,..., and then I can use I2CWRITE and read command to send my bytes to the outputs and then read from it.
    how would you do that?

    Thanks for your time, I really appreciate it
    Artha

  6. #6
    Join Date
    Mar 2008
    Location
    Gerogetown, Texas
    Posts
    94


    Did you find this post helpful? Yes | No

    Default

    I think you have a typo error

    GPINTENA con &00 should be GPINTENA con $00

    Try that

    Dave

    You also need to initialize the MCP23017
    Code:
    InitMPC23017:
    Pause 100
    '#############  PORTA
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IOCONA,IOCONSETA]
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IODIRA,$0]          'PortA inputs
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IOLATA,$FF]            'PortA = 0
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IPOLA,0]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[DEFVALA,0]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[GPPUA,$FF]           'pull-ups enabled
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[INTCONA,0]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[GPINTENA,$FF]        'interupt on change
    '##############  PORTB
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IOCONB,IOCONSETB]
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IODIRB,0]
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IOLATB,$FF]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IPOLB,0]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[DEFVALB,0]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[INTCONB,0]
    'i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[GPINTENB,0]
    return
    ReInitPortA:
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IOCONA,IOCONSETA]
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[IODIRA,$FF] 
    i2cwrite  PortA.0,PortA.1,IO_EXP0WR,[GPPUA,$FF]           'pull-ups enabled
    
    return
    Last edited by ScaleRobotics; - 27th November 2010 at 17:11. Reason: changed [code end] typo

  7. #7
    Join Date
    Nov 2010
    Posts
    5


    Did you find this post helpful? Yes | No

    Default you were right

    Hey Dave, thanks man
    you were right i made that mistake and i looked over and i couldn't catch it, you are having good eyes (i fixed it now).
    but still there is no success. even i copy you code and deleted you usb codes line and compile it but i could not get it to work.
    I connect all three address pin for my MCP to ground
    I pulled up mcp reset pin with a 15K R
    I pulled up SDA and SCL pin with two 1k R
    portc.3 is my clock and portc.4 is my data
    portc.7 is connected to an led just for test, so i know where i am in the program
    and this is my codes

    again thanks for your time

    '* Notes : *
    '* : *
    '************************************************* ***************
    'Includes
    include "modedefs.bas"
    '************************************************* ***************
    'Definitions
    DEFINE I2C_SDA PORTc,4
    DEFINE I2C_SCL PORTc,3
    define ADC_BITS 10
    define ADC_CLOCK 3
    define ADC_SAMPLEUS 50

    '************************************************* ***************
    'Variables
    A var byte
    Chip1 var byte
    POT1 var word
    POT2 var word

    '************************************************* ***************
    'Alias
    CP VAR PORTc.3
    DP VAR PORTc.4

    '************************************************* ***************
    'Initialization

    'Pic 16f877A
    adcon1=$02 'left justify A0 and A1
    CCP1CON=0 'disable capture/compare
    CCP2CON=0
    CMCON=7 'disable comparater
    option_reg.7=0 'portb pullups enabled

    'set ports
    trisa=%11111111
    trisb=%00000000
    trisc=%00000000
    trisd=%00000000

    'MCP 23017
    chip1 = $40
    IODIRA con $FF ' port A output
    IODIRB con $FF ' port B output
    IOCON con $3C ' Defining the MCP Bank as 0 and sequential disable

    MCPA con $12
    MCPB con $13
    MCPAL con $14
    MCPBL con $15

    'Initialing MCP

    i2cwrite dp,cp,$0A,chip1,[iocon]
    i2cwrite dp,cp,$0B,chip1,[iocon]
    i2cwrite dp,cp,$00,chip1,[iodira]
    i2cwrite dp,cp,$01,chip1,[iodirb]



    'IODIRA Con $00
    'IODIRB con $00
    'IPOLA con $00
    'IPOLB con $00
    'GPINTENA con $00
    'GPINTENB con $00
    'DEFVALA con $00
    'DEFVALB con $00
    'INTCONA con $00
    'INTCONB con $FF
    'IOCON con %00001000
    'GPPUA con $00
    'GPPUB con $00
    'INTFA con $00
    'INTFB con $00
    'INTCAPA con $00
    'INTCAPB con $00
    'GPIOA con $00
    'GPIOB Con $FF
    'OLATA con $00
    'OLATB con $FF)

    '************************************************* **************
    'Main Program

    start:
    portd =$00
    portc.7=0
    pause 500
    portd = $ff
    portc.7=1
    pause 500
    portc.7=0
    pause 500
    'I2CWRITE DataPin,ClockPin,Control,{Address,}[Value{,Value...}]{,Label}
    I2CWRITE dp,cp,mcpa,chip1,[$FF] 'porta on
    portc.7=1
    pause 200
    I2CWRITE dp,cp,mcpa,chip1,[$00] 'porta off
    portc.7=0
    pause 200
    I2CWRITE dp,cp,mcpal,chip1,[$FF] 'porta on
    portc.7=1
    pause 200
    I2CWRITE dp,cp,mcpal,chip1,[$00] 'porta off
    portc.7=0
    pause 200
    I2CWRITE dp,cp,mcpb,chip1,[$FF] 'portb on
    portc.7=1
    pause 200
    I2CWRITE dp,cp,mcpb,chip1,[$00] 'portb off
    portc.7=0
    pause 200
    I2CWRITE dp,cp,mcpbl,chip1,[$FF] 'portb on
    portc.7=1
    pause 200
    I2CWRITE dp,cp,mcpbl,chip1,[$00] 'portb off
    portc.7=0
    pause 200

    goto start
    end

  8. #8
    Join Date
    Mar 2008
    Location
    Gerogetown, Texas
    Posts
    94


    Did you find this post helpful? Yes | No

    Default

    The smallest resister I have used for I2C is 4.7K, also you need to initialize the MCP23017 correctly.


    Also you have set your port direction to input
    IODIRA con $FF ' port A output
    IODIRB con $FF ' port B output

    to make the port output you need to change the $FF to $00, just like setting a port direction in a PIC.

    Good luck

    Dave

  9. #9
    Join Date
    Nov 2010
    Posts
    5


    Did you find this post helpful? Yes | No

    Default

    Ok I changed it to 4.7k R and correct the port direction.
    could you please tell me what im doing wrong for initializing the chip? I know the default mode chip's port are all input and all the register's bit are %000000000 according to table 1-6 page 11 pf MCP23017 data sheet it means there is no pull up, inverter. am i right?
    i just need to have access to those register address which they are all again at page 11 table 1-6.
    and the way to do that with I2CWRITE command is following the help page of PBP which it says: I2CWRITE DataPin,ClockPin,Control,{Address,}[Value{,Value...}]{,Label}
    indicate the data pin, indicate clock pin, address of specific register that i want to change (IODIRA &00) table 1-6, address of my chip, [ and value in the bracket ]
    is this the correct way?

  10. #10
    Join Date
    Aug 2010
    Location
    Maryland, USA
    Posts
    869


    Did you find this post helpful? Yes | No

    Default

    Table 1.6 pg 11 shows POR/RST value of IODIRA and IODIRB is %11111111. NOT %00000000. Setting the dir to 1 makes the pin an input.

    Maybe you were looking at the next 2 registers? IPOLA and IPOLB?
    -Bert

    The glass is not half full or half empty, Its twice as big as needed for the job!

    http://foamcasualty.com/ - Warbird R/C scratch building with foam!

  11. #11
    Join Date
    Mar 2008
    Location
    Gerogetown, Texas
    Posts
    94


    Did you find this post helpful? Yes | No

    Default

    Take a look at your I2C data format

    The proper way to send data for this chip is

    i2cwrite I2C_SDA, I2C_CLK,control,[Value{..value}]

    In your case it should be:

    I2C_SDA is PORTC.4 or as you have defined DP
    I2C_CLK is PORTC.3 or as you have defined CP

    The control needs to be: (assuming you have the address lines connected to zero volts)
    %01000000 or $40 for write
    %01000001 or $41 for read

    {PicBasic actually changes the control bit.0 for you in the statement I2CWRITE and I2CREAD}

    So to set a register you need two values, the registers address and the value you want it to be.

    To set the IODIRA to be outputs you would send
    Value 1 control code for IODIRA is $00 see table 1-3 in the data sheet
    value 2 you want to make them outputs so would be $00 (just like setting TRIS in a PIC)

    I2CWRITE DP, CP, $40[$00, $00] 'IODIRA is set to output

    You also need to set the IOCON register
    I2CWRITE DP, CP, $40[$05, %10111000] "see data sheet register 1-6 for details


    So to initialize Porta as output you would program this.
    I2CWRITE DP, CP, $40[$05, %10111000] "Set configuration
    I2CWRITE DP, CP, $40[$00, $00] 'Make porta all outputs

    Then to write to the port you would use this:
    I2CWRITE DP, CP, $40[$09,$FF] '$09 is the address for GPIOA, $FF would make the porta pins high, to set them low, send values [$09, $00]

    You only need to set the weak pull-ups if you are making a port(pin) an input.

    Hope this helps
    Dave

  12. #12
    Join Date
    Nov 2010
    Posts
    5


    Did you find this post helpful? Yes | No

    Smile Thanks

    Thanks Dave,
    I really appreciate your time and patient. in I2c command where it asks about the address I thought it asks about chip's physical address, but now thank to you I can fully control this chip and use it. again thanks

    Artha

  13. #13
    Join Date
    Mar 2008
    Location
    Gerogetown, Texas
    Posts
    94


    Did you find this post helpful? Yes | No

    Default

    You are welcome, glad I could help.

    Take care

    Dave

Members who have read this thread : 2

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts