PIC16F877A > MAX7219 > 8x8 Multiplex Communications

Discussion in 'Embedded Systems and Microcontrollers' started by Ben_C, Aug 14, 2015.

  1. Ben_C

    Thread Starter Active Member

    Oct 19, 2010
    Hi, this is my last resort after attempting setting up communications and getting the correct result from my code.

    Basically I need a simple working example program in C to display say:

    Code (Text):
    1. //Digit 1
    3. B01000000
    4. B11000000
    5. B01000000
    6. B01000000
    7. B01000000
    8. B01000000
    9. B11100000
    I have it connected as so:
    (MAX7219 > PIC16F877A)

    DIN.........> RC5
    LOAD/CS.> RC0
    CLK.........> RC3
    ISET........> +VE (through 10K)

    I'm using PIC16F877A, MAX7219CNG and 1088BS Multiplex display. I have tried numerous times looking on data sheet to set the SFR's but I'm getting no where. There is plenty of examples on Google for Arduino but would prefer to use the PIC as it's what I'm used to.

    I've never used a display driver before I've always used PORTS on the Microchip and could do this using them, but I have a big project in mind and would love to use Serial data instead.

    Any help would be massively appreciated!

  2. JohnInTX


    Jun 26, 2012
    Do you have any code so far?
    I haven't used the 7219 but it doesn't look too difficult. I'd start by not worrying about the internal specifics too much - the thing is controlled by shifting 16 bits, MSbit first, to it. Start there.
    I think I'd make a function that accepts 2 chars, the digit data byte and command byte. The function combines these into an unsigned int and shifts that int out bit by bit then strobes the LOAD input on the 7219. After that, its just data.
    With no programming/setup, the 7219 scans one digit at low intensity with no decoding. Test the shift code by calling the output routine with 01xxh where 01 addresses digit 0 and xx is a segment pattern.
    Post what you have and we can take a look at it.

    Good luck.
  3. Ben_C

    Thread Starter Active Member

    Oct 19, 2010
    I have this at the moment, as I said I don't fully understand SPI and never used it before so this is probably a million miles away from what I need. I just need a simple working program on which I can build on.

    Code (Text):
    2. unsigned char i = 0xAA;
    4. void SPI_Init()
    5. {
    6.      SSPEN = 0; //disable SPI for setup
    8.      TRISC5 = 0; //data out
    9.      TRISC4 = 1; //data in
    10.      TRISC3 = 0; //clock
    11.      TRISC1 = 0; //CEpin
    12.      TRISC0 = 0; //ChipSelect
    14.      SSPCON = 0b00000001;
    15.      CKP = 0;
    16.      CKE = 1;
    18.      SSPEN = 1; //enable SPI
    19. }
    21. int main ()
    22. {
    23.     while (1)
    24.     {
    25.     SPI_Init();
    27.     SSPBUF = i;    // send character
    28.     while (SSPSTATbits.BF);    // wait until sent
    30.     }
    31. }
  4. atferrari

    AAC Fanatic!

    Jan 6, 2004
    Microchip published a very simple booklet explaining precisely SPI. Honestly, it is simple.
  5. Ben_C

    Thread Starter Active Member

    Oct 19, 2010
  6. Papabravo


    Feb 24, 2006
    Why is the call to SPIInit() inside your while loop and why do you keep spewing the constant character 0xAA every time the process completes. Can't you come up with a saner test program? What SPI data comes back from the device. How about the chip select, have you made a provision for that? Don't you need to unload that data from the buffer after the transmission is complete? What test equipment are you using? I suggest more reading on your part.
  7. John P

    AAC Fanatic!

    Oct 14, 2008
    I've used the MAX7219 with SPI communication from a PIC, but it was a PIC16F690. However, they're all the same as far as operation of the registers is concerned, so that shouldn't make any difference.

    Here's my code, as written for the CCS compiler; I don't use this any more, but it should be clear how the code functions. [But edited to say--it is a feature of CCS that an "int" is actually a single byte--so any time you see it, remember it's actually "unsigned char".] In my design, I had a 74HC595 shift register in line with two 7219's, so that data passed serially through each component in turn; the clock and strobe lines were in common. The 74HC595 was closest to the processor, so its data went out last. You can just ignore that. Note that the 7219 takes 16 bits on the SPI line, which means the processor must send 2 bytes for every write operation, the first one being an internal address for the 7219, and the other being data. With 2 7219's and the 74HC595, I have to send 5 bytes every time I write anything. The use of the "portc_shadow" register is to get around the PIC processor's annoying feature of read-modify-write on the output pins, where writing one pin can make others change. Just to be safe, I wrote to a dummy register and then loaded it all at once to the port.

    I have to tell you, I do all my programming with an oscilloscope on a shelf above my bench, and I can check all the outputs from the processor. If I couldn't do that, I'd spend endless time trying to figure out if something wasn't working because of software problems or a wiring error. I can't imagine how anyone gets anything done without the ability to see what's happening!

    Code (Text):
    2. void write_to_7219(int addr_l, int data_l, int addr_h, int data_h, int to_local)
    3. {
    5.    bit_clear(sspcon, 7);                      // Clear write collision detect
    7.    sspbuf = addr_h;                           // Send a byte
    8.    while (!bit_test(sspstat, 0)) ;         // Wait for it to complete
    9.    sspbuf = data_h;
    10.    while (!bit_test(sspstat, 0)) ;         // Every write involves 5 SPI bytes
    11.    sspbuf = addr_l;
    12.    while (!bit_test(sspstat, 0)) ;
    13.    sspbuf = data_l;
    14.    while (!bit_test(sspstat, 0));
    15.    sspbuf = to_local;                         // To 74HC595
    16.    while (!bit_test(sspstat, 0)) ;
    18.    bit_set(portc_shadow, 6);
    19.    portc = portc_shadow;                 // Strobe high
    21.    bit_clear(portc_shadow, 6);
    22.    portc = portc_shadow;                 // 7219 strobe low
    23. }
    25. void init_7219 (void)
    26. {
    27.   int i;
    29.    write_to_7219(0xC, 1, 0xC, 1, 0);               // Turn displays on
    30.    write_to_7219(0x9, 0x0, 0x9, 0x0, 0   );     // Decode mode, no decode for all digits
    31.    write_to_7219(0xA, 0x8, 0xA, 0x8, 0);        // Intensity, set for full brightness
    32.    write_to_7219(0xB, 7, 0xB, 7, 0);               // Scan limit, use all digits
    34.    for (i = 0; i < 8; i++)
    35.      write_to_7219(i+1, 0, i+1, 0, 0);              // Blank display, all segments (write 0 to each digit)
    36. }
    39. This part is in main():
    40.    sspstat = 0b01000000;
    41.    sspcon = 0b00100000;                              // Master mode, Fosc/4 (1MHz)
    42.    init_7219();
    43.    //write_to_7219(0xF, 1, 0xF, 1, 0x7F);      // Display test mode on
    44.    write_to_7219(0xF, 0, 0xF, 0, 0);              // Display test mode off
    Last edited: Aug 15, 2015
    JohnInTX likes this.
  8. Ben_C

    Thread Starter Active Member

    Oct 19, 2010
    I have it working! :D Thanks for the help to both Johns, I had a working code it turns out I had the 1088BS opposed to the 1088AS matrix, basically rewired it and got it working. Papabravo it was almost 3AM in the morning, I had been staring at my screen all day my mind was way out! :D

    But yes, I will sure be studying more on this subject. Thanks again.