October 11, 2010
by bpenglase
|
Ok, So I decided to buy a ton of LEDs on EBay, one purpose for building an LED Array, and just to have LEDs around. Anywho, I spent pretty much all afternoon Sunday making, IMHO, a really nice looking board.
Fast forward to after work today, I connect everything up, and realize I looked at the diagram wrong, and looking at the LEDs, R0/C0 was on the upper Right, instead of the Upper Left. I then realized the diagram was actually already looking at the LEDs, allwell.
So, I rewired some stuff, however everything is one column off. i.e. R0/C2 lights, then R0/C1, then R0/C4, then R0/C3, repeat during the test pattern.
What I would like to know is if there is a way to switch the polarity, in order to correct the switch in the columns?
It would be nice if I can do it in software, but I know sometimes there just isn't anything you can fix in software, and you have to fix it on the hardware.
Sorry for the crappy shot from my cellphone, but I figure it was worth including :) |
October 12, 2010
by Rick_S
|
I haven't played around with the software for the LED Array project in quite a while but you should definiately be able to 'fix' that in software.
The section you will want to focus on is in the interrupt function (SIGNAL(SIG_OVERFLOW0))
This would be the section of code.
// set column drivers appropriately
uint8_t j;
if(la_row%2 == 0) {
// even la_row number: fill even columns
real_row = la_row / 2;
for(j=0; j<COLS/2; j++) {
ledarray_set_columndriver(j, ledarray_get(real_row, 2*j), 1);
}
// activate row driver SINK
PORTB &= ~(1 << (PB1 + real_row));
DDRB |= (1 << (PB1 + real_row));
} else {
// odd la_row number: fill odd columns
real_row = (la_row-1)/2;
for(j=0; j<COLS/2; j++) {
ledarray_set_columndriver(j, 1 - ledarray_get(real_row, 2*j + 1), 0);
}
// activate row driver SOURCE
PORTB |= (1 << (PB1 + real_row));
DDRB |= (1 << (PB1 + real_row));
}
I haven't tried it but if you swap the activate row driver SOURCE and activate row driver SINK sections like this below, it may work. It's early though so you may have to do some more tweaking.
// set column drivers appropriately
uint8_t j;
if(la_row%2 == 0) {
// even la_row number: fill even columns
real_row = la_row / 2;
for(j=0; j<COLS/2; j++) {
ledarray_set_columndriver(j, ledarray_get(real_row, 2*j), 1);
}
// activate row driver SOURCE
PORTB |= (1 << (PB1 + real_row));
DDRB |= (1 << (PB1 + real_row));
} else {
// odd la_row number: fill odd columns
real_row = (la_row-1)/2;
for(j=0; j<COLS/2; j++) {
ledarray_set_columndriver(j, 1 - ledarray_get(real_row, 2*j + 1), 0);
}
// activate row driver SINK
PORTB &= ~(1 << (PB1 + real_row));
DDRB |= (1 << (PB1 + real_row));
}
Hope that works,
Rick |
October 16, 2010
by bpenglase
|
Sorry I didn't reply sooner, been swamped at work, and having to study for an upcoming certification exam.
Anywho, I did get it working combing what you both said. Changing what Rick said, and instead of putting 0's in, I just switched the functions from OR to AND NOT, or vice-versa in the columndriver() section. However, when I did this on the PORTx lines throughout the function, it worked, but the LEDs that were suppose to be off, still were lit slightly dim --
So while I played with that block, I either got it to how it was, nothing was lighting, some were lighting very dim, or the odd-rows were lit, and were turn off during the init (reversed, and only half working).
Then I had a thought, and on the if sense==onoff block, under the else, to match PORT and DDR, as it was originally. Soon as I did that it worked.
So here is the final code:
ColumnDriver():
inline void ledarray_set_columndriver(uint8_t j, uint8_t onoff, uint8_t sense) {
// cols 0-5: PC0-5
// cols 6-11: PD2-7
if(j < 6) {
if(onoff) {
PORTC |= (1 << (PC0 + j));
} else {
PORTC &= ~(1<< (PC0 + j));
}
if(sense == onoff) {
DDRC |= (1 << (PC0 + j));
} else {
DDRC &= ~(1 << (PC0 + j));
PORTC &= ~(1 << (PC0 + j));
}
} else {
if(onoff) {
PORTD |= (1 << (PD2 + (j-6)));
} else {
PORTD &= ~(1<< (PD2 + (j-6)));
}
if(sense == onoff) {
DDRD |= (1 << (PD2 + (j-6)));
} else {
DDRD &= ~(1 << (PD2 + (j-6)));
PORTD &= ~(1 << (PD2 + (j-6)));
}
}
}
And the rows:
// set column drivers appropriately
uint8_t j;
if(la_row%2 == 0) {
// even la_row number: fill even columns
real_row = la_row / 2;
for(j=0; j<COLS/2; j++) {
ledarray_set_columndriver(j, ledarray_get(real_row, 2*j), 1);
}
// activate row driver SOURCE
PORTB |= (1 << (PB1 + real_row));
DDRB |= (1 << (PB1 + real_row));
} else {
// odd la_row number: fill odd columns
real_row = (la_row-1)/2;
for(j=0; j<COLS/2; j++) {
ledarray_set_columndriver(j, 1 - ledarray_get(real_row, 2*j + 1), 0);
}
// activate row driver SINK
PORTB &= ~(1 << (PB1 + real_row));
DDRB |= (1 << (PB1 + real_row));
}
Thanks for the help on this one! Before when I tried changing stuff, I just figured I had to flip all of the bits, but I see thats wrong. And of course as I've been working with the code, I've understood it more.
And a picture of the final product:
The "light" on the bottom is just Lens flare on on the camera, as you can see, there are no lights down there, and the ones which are suppose to be off, are off :) |
January 02, 2011
by TonyPat
|
Hello,
I am new in LED project, following is my code then I cannot compile, MAKE complains as the following then I do not know how to correct in 2 lines: line 112 and line 332 which are: SIGNAL(SIG_OVERFLOW0) {
and the last line of main function which is only the closing bracket }.
Could any body help.
Thank you very much.
Hong
C:\Users\Hong\Documents\Learning\Nerdkit\Code\Code\ledarray_educational>make
make -C ../libnerdkits
make[1]: Entering directory `C:/Users/Hong/Documents/Learning/Nerdkit/Code/Code/
libnerdkits'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `C:/Users/Hong/Documents/Learning/Nerdkit/Code/Code/l
ibnerdkits'
avr-gcc -g -Os -Wall -mmcu=atmega168 -Wl,-u,vfprintf -lprintf_flt -Wl,-u,vfscan
f -lscanf_flt -lm -o ledarray.o ledarray.c ../libnerdkits/delay.o ../libnerdkits
/lcd.o ../libnerdkits/uart.o
ledarray.c: In function 'ledarray_set_columndriver':
ledarray.c:112: error: static declaration of '__vector_16' follows non-static de
claration
ledarray.c:112: error: previous declaration of '__vector_16' was here
ledarray.c:317: warning: 'main' is normally a non-static function
ledarray.c:332: error: expected declaration or statement at end of input
make: *** [ledarray.hex] Error 1
====================
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include "../libnerdkits/delay.h"
#include "../libnerdkits/uart.h"
// #include "../libnerdkits/io_328p.h"
#include "font.h"
// PIN DEFINITIONS:
//
// PB1-5 ROW DRIVERS (0-4)
// PC0-5,PD2-7: COLUMN DRIVERS (0-11)
#define F_CPU 14745600
#define ROWS 5
#define COLS 24
volatile uint8_t la_row, real_row;
volatile uint8_t la_data[COLS];
// in array la_data[COLS], each data is one 8 bit integer, represent one column, we need only 5 bit to represent 5 rows, example:
// la_data[2] = 00001000 meaning led at section row 3 column 2 is on ( 1 at row 3, we have only 5 rows: row0 to row4)
inline uint8_t ledarray_get(uint8_t i, uint8_t j) {
//01-02-11 Hong return (la_data[j] ~ (1<<i)) >> i; //read column then mask bit i, 1 data in la_data array is 1 column, we use only 5 bits then waist 3 bits
// shift right data to i bit to get the data bit we want to bit 0 so when we read we have only 2 states 0 or 1 at bit 0
if(i < ROWS && j < COLS) {
if((la_data[j] & (1<<i)) != 0) {
return 1;}
else {
return 0;} }
else {
return 0;}
}
inline void ledarray_set(uint8_t i, uint8_t j, uint8_t onoff) {
/*
if (onoff = 1){
la_data[j] |= 1 << i;
}else {la_data[j] & = ~(1 << i);
}
*/
if(i < ROWS && j < COLS) {
if(onoff) {
la_data[j] |= (1<<i);}
else {
la_data[j] &= ~(1<<i);}
}
}
//sense variable indicates direction of LED: sense == 1 indicates COL wire must be
//hight for LED to turn on. sense == 0, COL wire must be low to turn LED on
inline void ledarray_set_columndriver(uint8_t j, uint8_t onoff, uint8_t sense) {
// cols 0-5: PC0-5
// cols 6-11: PD2-7
if(j < 6) {
if(onoff){ //led on
DDRC |= (1 << (PC0 + j));
if(sense) {
PORTC |= (1 << (PC0 + j));
} else {
PORTC &= ~(1<< (PC0 + j));
}
} else { // led off, pins to high impedance
DDRC &= ~(1 << (PC0 + j));
PORTC &= ~(1 << (PC0 + j));
}
} else {
if(onoff){ //led on
DDRD |= (1 << (PD2 + (j-6)));
if(sense) {
PORTD |= (1 << (PD2 + (j-6)));
} else {
PORTD &= ~(1<< (PD2 + (j-6)));
}
} else { // led off, pins to high impedance
DDRD &= ~(1 << (PD2 + (j-6)));
PORTD &= ~(1 << (PD2 + (j-6)));
}
}
inline void ledarray_all_off() {
// turn off all row drivers
DDRB &= ~( (1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5) );
PORTB &= ~( (1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5) );
// turn off all column drivers
DDRC &= ~( (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4) | (1<<PC5) );
PORTC &= ~( (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4) | (1<<PC5) );
DDRD &= ~( (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7) );
PORTD &= ~( (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7) );
}
SIGNAL(SIG_OVERFLOW0) {
// turn off old row driver
DDRB &= ~(1 << (PB1 + real_row));
PORTB &= ~(1 << (PB1 + real_row));
ledarray_all_off();
// increment row number
if(++la_row == 2*ROWS)
la_row = 0;
// set column drivers appropriately
uint8_t j;
if(la_row%2 == 0) {
// even la_row number: fill even columns
real_row = la_row / 2;
for(j=0; j<COLS/2; j++) {
ledarray_set_columndriver(j, ledarray_get(real_row, 2*j), 1);
}
// activate row driver SINK
PORTB &= ~(1 << (PB1 + real_row));
DDRB |= (1 << (PB1 + real_row));
} else {
// odd la_row number: fill odd columns
real_row = la_row / 2;
for(j=0; j<COLS/2; j++) {
ledarray_set_columndriver(j, ledarray_get(real_row, (2*j) +1), 0);
}
// activate row driver SOURCE
PORTB |= (1 << (PB1 + real_row));
DDRB |= (1 << (PB1 + real_row));
}
}
void ledarray_init() {
// Timer0 CK/64 (900Hz)
TCCR0B = (1<<CS01) | (1<<CS00);
TIMSK0 = (1<<TOIE0);
// outputs (set row drivers low for off)
DDRC &= ~( (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4) | (1<<PC5) );
DDRD &= ~( (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7) );
DDRB &= ~( (1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5) );
}
void ledarray_left_shift() {
// shift everything one position left
uint8_t i, j;
for(i=0; i<ROWS; i++) {
for(j=0; j<COLS-1; j++) {
ledarray_set(i,j, ledarray_get(i, j+1));
}
}
}
void ledarray_blank() {
uint8_t i, j;
for(i=0; i<ROWS; i++) {
for(j=0; j<COLS; j++) {
ledarray_set(i,j,0);
}
}
}
void ledarray_testpattern() {
uint8_t i, j;
ledarray_blank();
for(i=0;i<ROWS;i++) {
for(j=0;j<COLS;j++) {
ledarray_set(i,j, 1 - ledarray_get(i,j));
delay_ms(30);
}
}
for(i=0;i<ROWS;i++) {
for(j=0;j<COLS;j++) {
ledarray_set(i,j, 1 - ledarray_get(i,j));
delay_ms(30);
}
}
}
void font_get(char match, char *buf) {
// copies the character "match" into the buffer
uint8_t i;
PGM_P p;
for(i=0; i<FONT_SIZE; i++) {
memcpy_P(&p, &font[i], sizeof(PGM_P));
if(memcmp_P(&match, p,1)==0) {
memcpy_P(buf, p, 7);
return;
}
}
// NO MATCH?
font_get('?', buf);
}
uint8_t font_width(char c) {
char buf[7];
buf[1] = 0;
font_get(c, buf);
return buf[1];
}
void font_display(char c, uint8_t offset) {
char buf[7];
font_get(c, buf);
uint8_t width = buf[1];
uint8_t i, j;
for(i=0; i<ROWS; i++) {
for(j=0; j<width; j++) {
if((offset + j) < COLS) {
// set the row of led_array at the right offset.
if( (buf[2+j] & (1<<i)) != 0) {
ledarray_set(i,offset + j,1);
} else {
ledarray_set(i,offset + j,0);
}
}
}
}
// blank the next column to the right
for(i=0; i<ROWS; i++) {
ledarray_set(i, offset+width, 0);
}
}
void do_scrolling_display() {
ledarray_blank();
int8_t offset = 0, next_offset = 0;
uint8_t is_started = 0;
char x=' ';
while(1) {
if(is_started) {
delay_ms(125);
ledarray_left_shift();
if(next_offset > 0) {
offset -= 1;
next_offset -= 1;
} else {
is_started = 0;
}
font_display(x, offset);
} else {
offset = COLS-1;
}
// if we can now accept a new character, tell the computer
if(next_offset == COLS)
uart_write('n');
while(uart_char_is_waiting()) {
if(is_started)
offset = next_offset;
x = uart_read();
if(x=='a') {
ledarray_blank();
return;
}
font_display(x, offset);
next_offset = offset + font_width(x)+1;
is_started = 1;
// if we can now accept a new character, tell the computer
if(next_offset <= COLS)
uart_write('n');
}
}
}
void do_simple_display() {
ledarray_blank();
uint8_t offset = 0;
char x = ' ';
while(1){
x = uart_read();
if(x == 'z'){
ledarray_blank();
offset = 0;
} else {
//fill in code to render character here
font_display(x, 2); delay_ms(100);
}
}
}
int main() {
ledarray_init();
// activate interrupts
sei();
// init serial port
uart_init();
FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
stdin = stdout = &uart_stream;
while(1){
do_simple_display();
//do_scrollint_display();
}
}
|