Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

pic port expander

MrDEB

Well-Known Member
While waiting for boards and parts I decided to venture to another project.
Using an 18f43k22 pic I want to drive 4 leds per port. Have used in another project 2 LEDs same color in parallel with one 330 ohm resistor and it works just fine but driving 4 LEDs may be pushing the limits of the pic.
Thus thinking about using a port expander.
ANY suggestions?
I recall Jon used a port expander in one of his projects.
 
Can I assume that using SPI may be the way to go?
Code:
Initialize()
Modified Hardware SPI Module
{
****************************************************************************
*  Name    : SPI.BAS                                                       *
*  Author  : John Barrat                                                   *
*          : David John Barker                                             *
*  Notice  : Copyright (c) 2006 Mecanique                                  *
*          : All Rights Reserved                                           *
*  Date    : 26/05/2006                                                    *
*  Version : 1.1 Changed WriteByte() param to WREG for silicon workaround  *                                           
*          : 1.0 Release                                                   *
*          : ============================================================= *
*  Notes   : This post was made on the Swordfish forum by Steve B on       *
*          : April 8th 2007...                                             *
*          : I was having some trouble with the SPI module as well. I am   *
*          : using an 18F2620, Silicon A4, and was getting some            *
*          : inconsistent reads/writes, especially when doing a lot of     *
*          : TX/RX one after another. After looking at the errata, I       *
*          : changed the ReadByte and WriteByte routines as follows...     *
*          :                                                               *
*          : Public Function ReadByte() As SSPBuffer                       *
*          :    SSPIF = 0                                                  *
*          :    SSPBuffer = 0                                              *
*          :    Repeat                                                     *
*          :       ClrWDT                                                  *
*          :    Until SSPIF = 1                                            *
*          : End Function                                                  *
*          :                                                               *
*          : Public Sub WriteByte(pData As WREG)                           *
*          :    SSPIF = 0                                                  *
*          :    SSPBuffer = pData                                          *
*          :    Repeat                                                     *
*          :       ClrWDT                                                  *
*          :    Until SSPIF = 1                                            *
*          : End Sub                                                       *
*          :                                                               *
*          : Now they use the SSP Interrupt flag instead of the Buffer     *
*          : Full flag (SSPSTAT.0). I also added a subroutine to enable    *
*          : the SPI module                                                *
*          :                                                               *
*          : Public Sub EnableSPI()                                        *
*          :    Dim pDummy As Byte                                         *
*          :    Enabled = true                                             *
*          :    pDummy = SSPBuffer                                         *
*          :    SSPIF = 0                                                  *
*          : End Sub                                                       *
****************************************************************************
}
Module SPI

Include "system.bas"

// map registers to SSP(x)
#if _mssp = 0
   #error _device + " does not support MSSP"

// single SSP...
#elseif _mssp = 1
Dim
   SSPControl1 As SSPCON1,
   SSPStatus   As SSPSTAT,
   SSPBuffer   As SSPBUF,
   SCK As PORTC.3,
   SDI As PORTC.4,
   SDO As PORTC.5, 
   _SS As PORTA.5

// has more than one SSP module...   
#else
Dim                         // -> MSSP2
   SSPControl1 As SSP1CON1, //    as SSP2CON1
   SSPStatus   As SSP1STAT, //    as SSP2STAT
   SSPBuffer   As SSP1BUF,  //    as SSP2BUF
   SCK As PORTC.3,
   SDI As PORTC.4,
   SDO As PORTC.5, 
   _SS As PORTA.5
#endif

// SSPSTAT bitnames
Public Dim
   BF  As SSPStatus.0,            // buffer full (receive and transmit)   
   SMP As SSPStatus.7,            // read sample mode
   CKE As SSPStatus.6             // clock edge control

// SSPCON1 bitnames, master mode only...
Public Dim
   WCOL  As SSPControl1.7,        // write collision Detect
   SSPOV As SSPControl1.6,        // receive overflow
   SSPEN As SSPControl1.5,        // synchronous receive enable
   CKP   As SSPControl1.4,        // clock polarity

   // synchronous mode select bits, %00XX for master mode
   SSPM3 As SSPControl1.3,        // always zero
   SSPM2 As SSPControl1.2,        // slave Mode
   SSPM1 As SSPControl1.1,        // clock Mode (MSB)
   SSPM0 As SSPControl1.0         // clock Mode (LSB)

// interrupt flag
Public Dim
   SSPIF As PIR1.3



Public Const
   spiOscDiv4              = 0,   // master mode FOSC/4
   spiOscDiv16             = 1,   // master mode FOSC/16
   spiOscDiv64             = 2,   // master mode FOSC/64
   spiOscTimer2            = 3,   // master mode TMR2 provides clock
   spiSlaveSSEnabled       = 4,   // slave mode slave synch enabled
   spiSlaveSSDisabled      = 5,   // slave mode slave synch disabled

   // clock idle and edge settings  (SPI Mode compatible)
   spiRisingEdge           = $40, // data transmitted on rising edge of clock
   spiFallingEdge          = $00, // data transmitted on falling edge of clock
   spiIdleHigh             = $10, // idle state for clock is high
   spiIdleLow              = $00, // idle state for clock is low

   // RX data sampling settings  (SSPStatus.6 - SMP)
   spiSampleEnd            = $80, // input data sampled at end of data output time
   spiSampleMiddle         = $00  // input data sampled at middle of data output time

// local helper aliases...   
Dim
   FBufferIsFull As SSPStatus.Booleans(0)      // BF as boolean

// public aliases...
Public Dim
   Enabled As SSPControl1.Booleans(5),         // SSPEN as boolean
   Overflow As SSPControl1.Booleans(6),        // SSPOV as boolean
   WriteCollision As SSPControl1.Booleans(7)   // WCOL as boolean
{
****************************************************************************
* Name    : SetAsMaster                                                    *
* Purpose : Set SPI to master mode                                         *
*         : spiOscDiv4 (DEFAULT), spiOscDiv16, spiOscDiv64, spiOscTmr2     *
****************************************************************************
}
Public Sub SetAsMaster(pMode As Byte = spiOscDiv4)
   SSPControl1 = SSPControl1 And $F0
   SSPControl1 = SSPControl1 Or pMode
   Output(SDO)
   Output(SCK) 
End Sub
{
****************************************************************************
* Name    : SetAsSlave                                                     *
* Purpose : Set SPI to slave mode                                          *
*         : spiSlaveSSEnabled, spiSlaveSSDisabled (DEFAULT)                *
****************************************************************************
}
Public Sub SetAsSlave(pMode As Byte = spiSlaveSSDisabled)
   SSPControl1 = SSPControl1 And $F0
   SSPControl1 = SSPControl1 Or pMode
   Output(SDO)
   Input(SCK)
   Input(_SS) 
End Sub
{
****************************************************************************
* Name    : SetSample                                                      *
* Purpose : Sets when the SPI input data in sampled                        *
*         : spiSampleEnd, spiSampleMiddle. For slave mode, sample should   *
*         : always be spiSampleMiddle                                      *
****************************************************************************
}
Public Sub SetSample(pSample As Byte)
   SSPStatus = SSPStatus And $7F
   SSPStatus = SSPStatus Or pSample
End Sub
{
****************************************************************************
* Name    : SetClock                                                       *
* Purpose : Set SPI idle state and data transmission clock edge            *
*         : pIdle -> spiIdleHigh, spiIdleLow                               *
*         : pEdge -> spiRisingEdge, spiFallingEdge                         *
****************************************************************************
}
Public Sub SetClock(pIdle As Byte, pEdge As Byte)
   SSPControl1 = SSPControl1 And $EF
   SSPControl1 = SSPControl1 Or pIdle
   If pIdle = spiIdleHigh Then
      pEdge = Not pEdge And $BF
   EndIf
   SSPStatus = SSPStatus And $BF 
   SSPStatus = SSPStatus Or pEdge
End Sub
{
****************************************************************************
* Name    : ReadByte                                                       *
* Purpose : Read a single byte from the SPI bus                            *
****************************************************************************
}         
'Public Function ReadByte() As SSPBuffer
'   SSPBuffer = 0
'   Repeat
'      ClrWDT
'   Until FBufferIsFull
'End Function


Public Function ReadByte() As  SSPBuffer
      SSPIF = 0
      SSPBuffer = $FF
      Repeat
         ClrWDT
      Until SSPIF = 1
      ReadByte = SSPBuffer
End Function

Public Sub WriteByte(pData As Byte)
      SSPIF = 0
      SSPBuffer = pData
      Repeat
         ClrWDT
      Until SSPIF = 1
End Sub

{
****************************************************************************
* Name    : WriteByte                                                      *
* Purpose : Write a single byte to the SPI bus                             *
****************************************************************************
}         
'Public Sub WriteByte(pData As WREG)
'   SSPBuffer = pData
'   Repeat
'      ClrWDT   
'   Until FBufferIsFull
'End Sub

Public Sub EnableSPI()                                     
    Dim pDummy As Byte                                         
    Enabled = true                                             
    pDummy = SSPBuffer                                         
    SSPIF = 0                                                 
End Sub
 
I am going to be brutally blunt here. You DO NOT have the skills to creating a successful circuit using MAX7219 LED Drivers. There are simply too many moving parts that you don't understand, and you've worn out the few people willing to expend the tremendous effort and experience the hair-pulling frustration required to help you.

You started this thread with the idea of driving 4 LEDs per port pin. That's far different than controlling 128 LEDs individually. Go with that original idea, using ULN2803s as augustinetez suggested.


If you wish to continue along the MAX7219 path, STOP LAYING OUT BOARDS. See if you can get one of the modules working first. Print out the MAX7219 datasheet and read it until ALL THE PIECES make sense.

Sorry, this is it for me. After however many years I have spent trying to help and educate you, I can't do this anymore. The literal thousands of hours I have spent have taken too large a toll on my sanity.

The ONLY reason I replied this last time is that I felt bad for you hanging in the wind. Your 5,899 messages posted here all asking for help have done me in.


Schematic_MRDEBCRAP_2024-05-16.png
 
I have to agree with you thus I got the idea to rethink this project and use a KISS method.
Anything wrong with handling the LED arrays as 2- 8x8 arrays where two 8 bit ports drive the anodes and have one 8 bit port control the cathodes with proper components to sink the current of both "arrays"
Basically the 18f43k22 will control 2 -8 x 8 LED arrays with 1 8 bt port not connected.
Have transistors or mosfets connected to the 8 cathodes connections.
 
I suggest you use TM1637 (Max 48 LEDs) or TM1638 (Max 80 LEDs). TM1637 requires just 2 I/O's & TM1638 requires 3 I/O's. If you require, switches to be interfaced, that too can be done with the same device,
 
I should perhaps clarify that I do not intend to display text or graphics, only multiplex all the LEDs.
THis revised schematic should clarify the final result.
I might change out the MOSFETs for a simple NPN transistor, but I wanted the lower resistance the MOSFET has.
The resistor arrays plan to use 330 ohm.
 
You started this thread with the idea of driving 4 LEDs per port pin. That's far different than controlling 128 LEDs individually. Go with that original idea, using ULN2803s as @augustinetez suggested.
 
I made numerous revisions after rethinking what I was doing.
Here is my latest revision.
I am assembling a prototype on a perf board to see if this revision works.
 

Attachments

  • seahawk.png
    seahawk.png
    240.2 KB · Views: 48
The resistor arrays plan to use 330 ohm
Depending on the type (and color) of the LED that may be too high a value since you'll be multiplexing the LEDs with a 1/8 duty cycle.

Also, I'd suggest adding a bulk cap at the 5V input, at least 10uF or more.
 
Note: the maximum current supplied by ALL ports is 185mA. Each LED appears to get(assumed Vf of 2V and 100Ω resistors) (5-2)/100=30mA for ⅛ of the time (but times 8 for each matrix). Adding that up gives 16*30mA which is a lot more than 185mA (~500mA). If resistor arrays are 300Ω then each LED gets 3/330=10mA times 16 is 160mA so will be within specification but the LEDs will be getting an average of 0.8mA (10mA for ⅛ of the time) which might be a bit dull.

You may want to consider some ULN chips for the columns (you've labeled the columns as rows so figured the rows must be columns).

Mike.
 
Back
Top