Hi all,
I'm working on a project where I need to multiplex a matrix of 512 LEDs using a pic16f628. Currently I'm testing with 5 cascaded shift registers (serial in, parallel out). One shift register is used to control which LEDs must be on, in the current column. The other 4 are used for the columns.
Here is a design of the circuit as example. I left out some parts, but I hope you'll get an idea of the project:
After adding the 5th shift register the image started flickering. I've talked to some people telling me its definitely possible to control at least 40 columns. How can I achieve this? Are there any "tricks" to speeds this up?
Here is my code for the pic16f628:
// Define the shift registers pins #define SHIFT_DATA PORTA.F1 #define SHIFT_CLOCK PORTA.F0 #define SHIFT_OE PORTA.F2 // Output enable.
// The a_matrix holds the row values for the 8 columns // in the 8x8 matrix. The keys of the matrix 0-7 are // the columns, the corresponding values the row flags. char a_matrix[8] = { 0b01010101 ,0b01010101 ,0b00100000 ,0b00010000 ,0b00001000 ,0b00000100 ,0b00000010 ,0b00000001 };
char a_columns[32] = { 0b10000000 ,0b01000000 ,0b00100000 ,0b00010000 ,0b00001000 ,0b00000100 ,0b00000010 ,0b00000001 // 8 ,0b00000010 ,0b00000100 ,0b00001000 ,0b00010000 ,0b00100000 ,0b01000000 ,0b10000000 ,0b00000001 // 16 ,0b00000010 ,0b00000100 ,0b00001000 ,0b00010000 ,0b00100000 ,0b01000000 ,0b10000000 ,0b00000001 // 24 ,0b00000010 ,0b00000100 ,0b00001000 ,0b00010000 ,0b00100000 ,0b01000000 ,0b10000000 ,0b00000001 // 32
};
char c_in = 0; // Used for serial input. int f_state = 0; // Used to update the matrix. (update_matrix()) int c_col_in = 0; // update_matrix() int c_row_in = 0; // update_matrix(); int c_called = 0; // update_matrix(), counting the number of times method is called int num_cols = 32; int i = 0; int j = 0; int i_col = 0; char c_column; // main()
// Shift one byte into the shift register. void shift_byte(char pByte) { int i; for (i = 0; i < 8; i++) { // Get bit (1 or 0) at position i of pByte. SHIFT_DATA = (pByte >> i) & 1;
// Make clock pin high and low again, so data is shifted into the registers. SHIFT_CLOCK = 1; SHIFT_CLOCK = 0; } } void shift_bit(int fPin) { SHIFT_DATA = fPin; // 0 or 1 SHIFT_CLOCK = 1; SHIFT_CLOCK = 0; } void put_col_on(int iCol) { // First we shift out several '0' to fill all the registers j = 16 - iCol; for (i_col = 0; i_col < j; i_col++) { shift_bit(0); }
// The first bit is for the column which must be turned on. shift_bit(1);
// All the other columns must be turned off. for (i_col = 0; i_col < (iCol - 1); i_col++) { shift_bit(0); } }
// Make all the columns low. void matrix_off() { SHIFT_OE = 0; shift_byte(0x00); shift_byte(0x00); shift_byte(0x00); shift_byte(0x00); shift_byte(0x00); SHIFT_OE = 1; }
// This function checks if there is data available // on the serial port. And if so, it will update the // matrix table. The data which is received using rs-232 // is in the format (2 bytes): // [column][row_flags] void update_matrix() { // Read data. if (usart_data_ready() == 1) { c_in = usart_read(); if (f_state == 0) { c_col_in = c_in; f_state = 1; } else if (f_state == 1) { c_row_in = c_in; // not really needed, we can use c_in f_state = 0; if (c_col_in