NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » LED array scroll function

November 24, 2009
by Rick_S
Rick_S's Avatar

Well, I've cleaned up and commented my text scrolling function for the LED array. In case anyone is interested. This function will accept a string as input and scroll it from right to left. This may seem like a small task for some of you but it was quite the challenge for me with my limited knowledge of C. Just add this function to the current ledarray.c file above where you call it.

void scroll_display(const char *s) {
  // clear display
  ledarray_blank();
  int8_t offset = 0 , next_offset = 0;
  uint8_t is_started = 0;
  uint8_t i=0;
  char x=' ';

  // begin loop and continue until nul character at end of string
  while(pgm_read_byte(s) != 0x00){

        // have we read a character? 
        if(is_started) {
            // if so, place and shift the character until it is clear of column 24
            while(next_offset>23){
                delay_ms(90);
                // shift the display one place
                ledarray_left_shift(); 
                // check the end of the currently displayed characters if it's greater than zero, decrement 
                // both the offset (character display position), and next_offset(character end position)
                if(next_offset > 0) {
                    offset -= 1;
                    next_offset -= 1;
                }
                // display the character at the new position
                font_display(x, offset); 
            }
        } else {
            // if not, set offset to # of columns -1 (23)
            offset = COLS-1;
        }
        // read the next character in the string
        x = pgm_read_byte(s++);

        // if we have already started, set the current display position to where the last character ended
        if(is_started)
            offset = next_offset;
        // display the character
        font_display(x, offset);
        // create the new character end position
        next_offset = offset + font_width(x)+1;
        // set flag to show we have been through the loop
        is_started = 1;
    }
    // Process the last character.  This is neccessary since the while bails as soon as it reads
    // the null character.  At that point, the last read character has not yet shifted into full
    // view.  The following while loop shifts the final string character into full view.
    while(next_offset>23){
        delay_ms(90);
        ledarray_left_shift(); 
        if(next_offset > 0) {
            offset -= 1;
            next_offset -= 1;
        }
        font_display(x, offset); 
        }

   delay_ms(90);
   // this final loop shifts the display all the way off.
   for(i=0;i<COLS;i++){
        ledarray_left_shift();
        delay_ms(90);
    }

    return;
}

To call the function, simply make a statement such as:

scroll_display(PSTR("HELLO WORLD"));

If you saw my post with this function before, this is a better version in that it no longer requires trailing spaces in your string to shift the characters completely off the display.

Enjoy.

Any comments or suggestions would be appreciated..

Rick

November 24, 2009
by Farmerjoecoledge
Farmerjoecoledge's Avatar

Hi Rick,

Now that's a nice piece of code! So your not interested in the "pipe"? It's kinda cool it'll download a rss feed, sports, news, weather anything you want scrolling across your "super" display. Only one drawback, the feeds i've found are not "clean" meaning all the addresses are in the feed so alot of the time your reading jiberish. You don't need me for this anyhow, all of it is in this forum just "nerd it".

farmerjoe

ps. What's the green thing on your board?

November 25, 2009
by Rick_S
Rick_S's Avatar

Thanks for the offer, my goal with the display is to un-tether it from the pc. I wanted to be able to program it, disconnect it, and let it run. I'm pretty much to that point now. I've made another modification to the scroll_display function. I am now passing an unsigned integer to it so I can change the scrolling speed. To do this, just change the opening line of the function to read:

void scroll_display(const char *s,uint8_t speed) {

Then change all the

delay_ms(90);

lines to

delay_ms(speed);

Then call the function with:

scroll_display(PSTR("HELLO WORLD"),75);

I also modified the ledarray_left_shift function and added ledarray_right_shift, ledarray_shift_up, and ledarray_shift_down. This way you can control the way the text exits the screen.

Here are those functions.

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));
    }
    ledarray_set(i,23,0);
  }
}

void ledarray_right_shift(){
    // shift everything right one position
    uint8_t i, j;
    for(i=0; i<ROWS; i++) {
        for(j=COLS-1; j>0; j--) {
        ledarray_set(i,j, ledarray_get(i, j-1));
        }
        ledarray_set(i,0,0);
    }
}

void ledarray_shift_up(){
    // shift everything up one position
    uint8_t i,j;
    for(i=0;i<ROWS-1;i++){
        for(j=0;j<COLS;j++){
            ledarray_set(i,j,ledarray_get(i+1,j));
        }
    }
    // blank bottom line to prevent 'smearing'
    for(j=0;j<COLS;j++){
        ledarray_set(4,j,0);
    }
}

void ledarray_shift_down(){
    // shift everything down one position
    uint8_t i,j;
    for(i=4;i>0;i--){
        for(j=0;j<COLS;j++){
            ledarray_set(i,j,ledarray_get(i-1,j));
        }
    }
    // blank top line to prevent 'smearing'
    for(j=0;j<COLS;j++){
        ledarray_set(0,j,0);
    }
}

I hope you get some use out of these! I know I am. :D :D

Rick

November 25, 2009
by Rick_S
Rick_S's Avatar

I forgot to mention the "green thing". That is a 5v breadboard power supply. It contains the 5v regulator, filter caps, power led, and power jack so I can just plug in a wall wart dc supply to power my projects. When finished, they plug right into the top and bottom power rail positions on the breadboard. You can buy them on e-bay in kit form.

November 25, 2009
by mcai8sh4
mcai8sh4's Avatar

Farmerjoecoledge : If you are still using linux for your display, I can help you eliminate the addresses from your pipe is you like (possibly - I can try). In windows I'm not sure if my idea will work, but if you let me know the details (in another thread, rather than hijack this one), we can see what we can do. I'm sure others will have ideas that will help. I currently use mine to get the latest info for the local train station, so I know if there's a delay - it's not much, but I'm happy with it.

Rick_S : Well done! The code looks great. It really does feel nice when you get something working the way you want it to. I'm still playing around with the marquee code, so I may have a play around with yours (code!).

-Steve

November 25, 2009
by Rick_S
Rick_S's Avatar

Steve, go for it. Modify, all you'd like. Just promise me one thing, if you come up with something different, you'll post it in the forum so we all can enjoy it. I'll try to do the same.

Rick

November 27, 2009
by n3ueaEMTP
n3ueaEMTP's Avatar

Rick, the code is awesome!! One question, I changed "Hello World" to "MERRY CHRISTMAS + HAPPY NEW YEAR." When I disconnect the NerdKits programming header, the display hiccups & then completely goes blank. I reconnected the POWER wires (red & black) to the rails, cycled the power and everything works fine. Any idea why this happens? I thought maybe it was waiting for a signal from the UART, but the green/yellow wires are even connected so I don't think that's the cause. The header is also NOT connected to the USB port but the serial to USB converter is attached.

November 27, 2009
by Rick_S
Rick_S's Avatar

Because the default code monitors the serial port on the chip, if any stray signal comes into the port, it will blank the screen to display what may be coming. I had the same problem early on and determined that to be the cause. I 1st copied the original ledarray.c program into another file that I am doing my modifications to (that way I could always revert to where I was). Since I don't plan to send any text to my stand alone program, I simply removed all code related to the UART. That fixed my problem and will most likely fix yours.

The lines you are looking for are:

At the top of the file,

#include "../libnerdkits/uart.h"

In the do_test_pattern() function (there are several occurrences,

if(uart_char_is_waiting()) break;

And in the main function,

// init serial port
uart_init();
FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
stdin = stdout = &uart_stream;

You can either remove them or simply comment them out whichever you prefer.

Hope that helps, I'm glad you are getting use out of the code.

Rick

November 27, 2009
by n3ueaEMTP
n3ueaEMTP's Avatar

Rick, thanks for the help. I have already deleted some of the UART stuff but didn't remove the include file or the serial port initialization in the main function. I did copy the entire folder to another folder so when I mess up this file I have a backup.

I will need it later as I plan on having it display text messages. I work as a paramedic & we get text messages in addition to the voice dispatch. My goal is to have the entire text message displayed so we don't have to pull our phones out if we miss the voice dispatch. I hoping to integrate this into another project that activates lights, a buzzer, and open then closes our garage doors. (definitely going to need a 328 for that project :-) ).

Anyway, the marquee is at home & I'm not. I'll keep you updated on my progress. Thanks again for your code/help.

Chris B. n3ueaEMTP

November 27, 2009
by Rick_S
Rick_S's Avatar

If you want your text to appear on the marquee one character at a time but scroll each character from the top line to bottom to place it on the screen, this function will do that for you.

You can use it anywhere you want to use font_display.

The new function is font_display_down( character to display, offset position)

void font_display_down(char c, uint8_t offset) {
  char buf[7]; 
  font_get(c, buf);

  uint8_t width = buf[1];
  uint8_t i, j, s,n;

  for(i=0; i<ROWS; i++) {
    n=4-i;
    s=0;
        while(s<=i){
            for(j=0; j<width; j++) {
                if((offset + j) < COLS) {
                    if( (buf[2+j] & (1<<n)) != 0) {
                        ledarray_set(s,offset + j,1);
                    } else {
                        ledarray_set(s,offset + j,0);
                    }
                }
            }   
            delay_ms(15);
            n++;
            s++;
        }
    }

 // blank the next column to the right
  for(i=0; i<ROWS; i++) {
    ledarray_set(i, offset+width, 0);
  }
}

You can call this function like this:

font_display_down('H', offset); offset += font_width('H')+1;
font_display_down('E', offset); offset += font_width('E')+1; 
font_display_down('L', offset); offset += font_width('L')+1; 
font_display_down('L', offset); offset += font_width('L')+1; 
font_display_down('O', offset); offset += font_width('O')+1; delay_ms(1500);

Let me know what you think.

Rick

November 27, 2009
by n3ueaEMTP
n3ueaEMTP's Avatar

Rick, I've figured out the problem. I took out all of the UART code and I still had the problem where the display would go blank after a few seconds. When I re-attached the +5V & GND wires from the programming header, it began to work again. The only thing connected to both rails on the programming header was a 0.01uf capacitor. I added a capacitor to the +5V & GND rails on the breadboard and disconnected the programming header. All worked well!!

My next problem is going to take more time. I need to learn Python so I can create a program to check an email address & then pass it on to the UART for display. For some reason, I cannot seem to get Python to work on my windows box. When I try to run a Python program, it flashes on the screen & then disappears. Not sure whats going on there.

Anyway, thanks for all your help.

Chris B. n3ueaEMTP

November 28, 2009
by Rick_S
Rick_S's Avatar

That would be a good subject for a tutorial. Clean power is a must for micro-controllers (and many other electronic devices). Stray signals from transients in power can cause all kinds of weird effects. Most "wall wart" power adapters have little to no filtering on their output. They simply place a bridge rectifier (or 4 diodes making up a bridge) right after the transformer to convert the AC to DC. While that does create DC voltage it is "Pulsed DC" meaning at every change of the AC cycle the voltage drops to zero then back again. Filter capacitors hold the voltage during those drop outs bringing the power more closely to a pure DC.

I'm glad you figured out your problem. Sometimes the odd quirks can be the most challenging of all. I probably never ran into that because I have a breadboard power supply that I run mine off of. These work great for test work. If you look at my post in the "Customer testimonial / Thought for a new component" post, you can see the small green board at the edge of my breadboard. It contains 4 filter caps, a 5v regulator, power indicator LED with resistor, and a diode to protect against reverse polarity on the adapter. These can be bought in kit form on e-bay. (No, I don't sell them nor do I get compensated for talking about them) They just work very well. Keep in mind though, because it does plug directly into the breadboard, a different breadboard with measurements different (width wise) than the one supplied with the NerdKit may not work.

This is the power supply kit I bought:

ebay link

I didn't build the 12v one though, the supplies are identical other than the regulators, so I built both as 5v.

I have not regretted the purchase of these one bit. It also frees up some room on the small NerdKit board because the supply is almost completely off the board.

Rick

November 29, 2009
by Rick_S
Rick_S's Avatar

OK, I just can't leave well enough alone. I have now updated my font_display_down function renaming it to font_display_ud. The function will now display the character either from the top down (down) or from the bottom up (up). This does require another parameter to the function to give it the direction. Below is the function and a sample of how to call it.

/*****************************************************************************
*
*   Function name : font_display_ud
*
*   Returns :       None
*
*   Parameters :    c: character to diplay
*                   offset: column position for beginning of character
*                   up: boolean variable 
*                          =1 character scrolls up
*                          =0 character scrolls down
*
*   Purpose :       Display text on marquee display scrolling the 
*                   character up or down into view
*
******************************************************************************/

void font_display_ud(char c, uint8_t offset, uint8_t up) {

  char buf[7];

  // get font data for the current character and place it into the buffer
  font_get(c, buf);
  uint8_t width = buf[1];
  uint8_t i, j, s,n;

  if(up){
  for(i=0; i<ROWS; i++) {
    n=0;
    s=4-i;
        while(s<ROWS){
            for(j=0; j<width; j++) {
                if((offset + j) < COLS) {
                    if( (buf[2+j] & (1<<n)) != 0) {
                        ledarray_set(s,offset + j,1);
                    } else {
                        ledarray_set(s,offset + j,0);
                    }
                }
            }   
            delay_ms(7);
            n++;
            s++;
        }
    }
    } else{
    for(i=0; i<ROWS; i++) {
    n=4-i;
    s=0;
        while(s<=i){
            for(j=0; j<width; j++) {
                if((offset + j) < COLS) {
                    if( (buf[2+j] & (1<<n)) != 0) {
                        ledarray_set(s,offset + j,1);
                    } else {
                        ledarray_set(s,offset + j,0);
                    }
                }
            }   
            delay_ms(7);
            n++;
            s++;
        }
    }
    }
 // blank the next column to the right
  for(i=0; i<ROWS; i++) {
    ledarray_set(i, offset+width, 0);
  }
}

Sample of how to call it:

font_display_ud('H', offset,1); offset += font_width('H')+1; // up
font_display_ud('E', offset,1); offset += font_width('E')+1; // up
font_display_ud('L', offset,0); offset += font_width('L')+1; // down
font_display_ud('L', offset,0); offset += font_width('L')+1; // down
font_display_ud('O', offset,0); offset += font_width('O')+1; delay_ms(1500); // down

Not sure if any of this is of any help to anyone... I hope so.

Again, enjoy and let me know what you think.

Rick

November 30, 2009
by hevans
(NerdKits Staff)

hevans's Avatar

Hi Rick_S,

That looks great! Thanks for sharing your work.

I might just use your function for future LED Arrays around the office.

Humberto

November 30, 2009
by Rick_S
Rick_S's Avatar

Thanks Humberto,

I must admit I've learned more 'C' programming with this project than anything so far. I figured why not give to the community and share what I've learned. I hope to continue to advance the program - probably after the holidays - with more effects. I received some real good suggestions in one of my other threads.

Rick

February 23, 2010
by Phrank916
Phrank916's Avatar

All of these functions are super cool, Rick. I'm bumping this to the top so I can find it again easier.

Ted

February 23, 2010
by Rick_S
Rick_S's Avatar

Thank you for the compliment!

It'd be nice if the board supported stickys. There are several threads that would be nice to keep at the top. I appreciate you thinking mine is one of those. :)

Rick

July 21, 2010
by jdnewt
jdnewt's Avatar

Rick I am trying to program the LED array kit to display scrolling messages. I have been able to display characters as i type them but not able to store messages to display without being connected to the computer. I have looked through your code and understand what you did. I just don't have enough c knowledge to know where to put the actual code in my program. if anyone has any advice it would help greatly because i am at a standstill right now

July 21, 2010
by Rick_S
Rick_S's Avatar

This is the most recent full program I have. All the text that is displayed is in the function do_testpattern(). You'll notice the last time I used it was to wish my wife (Donna) a happy birthday... :D Anyway, the main function calls do_testpattern() and the while(1) loop keeps it there indefinitely. If you have any other questions please ask. This program was my first major modification and my 1st full learning experiance with C. So there may be some programming methods used that aren't quite right, but it works... I really wish there were a way to attach files in this forum...

// ledarray.c
// for NerdKits with ATmega168
// mrobbins@mit.edu
// Modified by Rick Shear

#define F_CPU 14745600
#include "../libnerdkits/io_328p.h"

#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 "font.h"

// PIN DEFINITIONS:
//
// PB1-5 ROW DRIVERS (0-4)
// PC0-5,PD2-7: COLUMN DRIVERS (0-11)
#define ROWS 5
#define COLS 24

volatile uint8_t la_row, real_row;
volatile uint8_t la_data[COLS];

    inline uint8_t ledarray_get(uint8_t i, uint8_t j) {
  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(i < ROWS && j < COLS) {
    if(onoff) {
      la_data[j] |= (1<<i);
    } else {
      la_data[j] &= ~(1<<i);
    }
  }
}

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)));
    }
  }
}

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) );  
}

ISR(TIMER0_OVF_vect) {
  // 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-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));
  }  
}

void ledarray_init() {
  // Timer0 CK/64 (900Hz)
  TCCR0B = (1<<CS01) | (1<<CS00);
  TIMSK0 = (1<<TOIE0);

  // outputs (set row drivers high 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));
    }
    ledarray_set(i,23,0);
  }
}

void ledarray_right_shift(){
    // shift everything right one position
    uint8_t i, j;
    for(i=0; i<ROWS; i++) {
        for(j=COLS-1; j>0; j--) {
        ledarray_set(i,j, ledarray_get(i, j-1));
        }
        ledarray_set(i,0,0);
    }
}

void ledarray_shift_up(){
    // shift everything up one position
    uint8_t i,j;
    for(i=0;i<ROWS-1;i++){
        for(j=0;j<COLS;j++){
            ledarray_set(i,j,ledarray_get(i+1,j));
        }
    }
    // blank bottom line to prevent 'smearing'
    for(j=0;j<COLS;j++){
        ledarray_set(4,j,0);
    }
}

void ledarray_shift_down(){
    // shift everything down one position
    uint8_t i,j;
    for(i=4;i>0;i--){
        for(j=0;j<COLS;j++){
            ledarray_set(i,j,ledarray_get(i-1,j));
        }
    }
    // blank top line to prevent 'smearing'
    for(j=0;j<COLS;j++){
        ledarray_set(0,j,0);
    }
}

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, ct;
    ledarray_blank();
    // set initital pattern (every other LED on)
    for(i=0;i<ROWS;i++) {
        for(j=i%2;j<COLS;j += 2) {
        ledarray_set(i,j, 1 - ledarray_get(i,j));
        }
    }
    //wait 50ms
    delay_ms(50);

    // toggle the pattern turning what was on off then back on again 10 times
    for(ct=0;ct<10;ct++){
        for(i=0;i<ROWS;i++) {
            for(j=0;j<COLS;j++) {
                ledarray_set(i,j, 1 - ledarray_get(i,j));
            }
        }
        delay_ms(50);
        for(i=0;i<ROWS;i++) {
            for(j=0;j<COLS;j++){ 
                ledarray_set(i,j, 1 - ledarray_get(i,j));
            }
        }
        delay_ms(50);
    }
}

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) {
        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 font_display_ud(char c, uint8_t offset, uint8_t up) {
  char buf[7]; 
  // get font data for the current character and place it into the buffer

  font_get(c, buf);

  uint8_t width = buf[1];
  uint8_t i, j, s,n;

  if(up){
  for(i=0; i<ROWS; i++) {
    n=0;
    s=4-i;
        while(s<ROWS){
            for(j=0; j<width; j++) {
                if((offset + j) < COLS) {
                    if( (buf[2+j] & (1<<n)) != 0) {
                        ledarray_set(s,offset + j,1);
                    } else {
                        ledarray_set(s,offset + j,0);
                    }
                }
            }   
            delay_ms(7);
            n++;
            s++;
        }
    }
    } else{
    for(i=0; i<ROWS; i++) {
    n=4-i;
    s=0;
        while(s<=i){
            for(j=0; j<width; j++) {
                if((offset + j) < COLS) {
                    if( (buf[2+j] & (1<<n)) != 0) {
                        ledarray_set(s,offset + j,1);
                    } else {
                        ledarray_set(s,offset + j,0);
                    }
                }
            }   
            delay_ms(7);
            n++;
            s++;
        }
    }
    }
 // blank the next column to the right
  for(i=0; i<ROWS; i++) {
    ledarray_set(i, offset+width, 0);
  }
}

void scroll_display(const char *s,uint8_t speed) {
  // clear display
  ledarray_blank();
  int8_t offset = 0 , next_offset = 0;
  uint8_t is_started = 0;
  uint8_t i=0;
      char x=' ';
  if(speed==0)
        speed=90;

  // begin loop and continue until nul character at end of string
  while(pgm_read_byte(s) != 0x00){

        // have we read a character? 
        if(is_started) {
            // if so, place and shift the character until it is clear of column 24
            while(next_offset>23){
                delay_ms(speed);
                // shift the display one place
                ledarray_left_shift(); 
                // check the end of the currently displayed     characters     if it's greater than zero, decrement 
                // both the offset (character display position), and     next_offset(character end position)
                if(next_offset > 0) {
                    offset -= 1;
                    next_offset -= 1;
                }
                // display the character at the new position
                font_display(x, offset); 
            }
        } else {
            // if not, set offset to # of columns -1 (23)
            offset = COLS-1;
        }
        // read the next character in the string
        x = pgm_read_byte(s++);

        // if we have already started, set the current display position to where the last character ended
        if(is_started)
            offset = next_offset;
        // display the character
        font_display(x, offset);
        // create the new character end position
        next_offset = offset + font_width(x)+1;
        // set flag to show we have been through the loop
        is_started = 1;
    }
    // Process the last character.  This is neccessary since the while bails as soon as it reads
    // the null character.  At that point, the last read character has not yet     shifted into full
    // view.  The following while loop shifts the final string character into full view.
    while(next_offset>23){
        delay_ms(speed);
        ledarray_left_shift(); 
        if(next_offset > 0) {
            offset -= 1;
            next_offset -= 1;
        }
        font_display(x, offset); 
        }

   delay_ms(speed);
   // this final loop shifts the display all the way off.
   for(i=0;i<COLS;i++){
        ledarray_left_shift();
        delay_ms(speed);
    }

    return;
}

void do_testpattern() {

  int8_t offset=0;
  int8_t i=0;
  while(1) {

//ledarray_testpattern();

ledarray_blank();
offset=0;
font_display_ud('H', 2,1); delay_ms(100);
font_display_ud('A', 6,0); delay_ms(100);
font_display_ud('P', 10,1); delay_ms(100);
offset=14;
font_display_ud('P', offset,0); offset += font_width('P')+1; delay_ms(100);
font_display_ud('Y', offset,1); offset += font_width('Y')+1; delay_ms(1500);
for(i=0;i<5;i++){
    ledarray_shift_up();
    delay_ms(80);
}
  // for(i=0;i<COLS;i++){
//  ledarray_left_shift();
//  delay_ms(50);
//}

    ledarray_blank();

scroll_display(PSTR("BIRTHDAY"),80);

ledarray_blank();
offset=1;
font_display_ud('D', offset,1); offset += font_width('D')+1; //delay_ms(1000);
font_display_ud('O', offset,1); offset += font_width('O')+1; //delay_ms(1000);
font_display_ud('N', offset,1); offset += font_width('N')+1; //delay_ms(1000);
font_display_ud('N', offset,1); offset += font_width('N')+1; //delay_ms(1000);
font_display_ud('A', offset,1); offset += font_width('A')+1; delay_ms(1500);

for(i=0;i<5;i++){
    ledarray_shift_down();
    delay_ms(80);
}

  }
}

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;
*/

  // mode 1: test pattern
  do_testpattern();

  return 0;
}
July 21, 2010
by Ralphxyz
Ralphxyz's Avatar

Rick, you should get a prize for formatting your code.

That took 1876 spaces your thumb must be tired.

Yes, having a file attachment or upload link would really be nice, but I suppose there are auditing concerns by the Nerdkit guys.

Somebody would have to look at every upload to make sure everything was appropriate I suppose.

Oh nice code thank you.

Ralph

July 22, 2010
by Rick_S
Rick_S's Avatar

Yeah, the thumb definately gets tired after a while.

Even if they didn't have an upload section, having the ability to use common forum escape tags [Code] .. code goes here .. [/Code] or [Quote] .. [/Quote], etc.. would be nice. I'm sure they have people that are regulars that they could get to help moderate if that were the issue. Unfortunately, it seems forum improvements beyond where we are now seem to fall on deaf ears. I'd like to think not but I haven't heard much from them on the subject.

But to get back on subject, you are quite welcome for the code, I hope my little part helps out. Keep in mind, I am a VERY green C programmer still so there may and most likley are better ways to do some of what I did. I also commented out all serial communication to the chip to save space since I wasn't using it anyway.

Rick

July 23, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi Rick,

I assure you your suggestions never fall on deaf ears. Given the way our forum system is currently set up there is no trivial way of giving you the ability to upload files. We would like to find an elegant way to let you easily mark out a code block (without the spaces). We will get there eventually, but we do not have the resources of a huge corporation, and we will not put stuff out there that is not well implemented. Ultimately the educational content we provide, does take priority over web updates.

In order to make code formatting easier though, you can open up the file in Programmers Notepad, highlight the section you want, right click -> Indentation -> Indent. This will add a tab at the beginning of every line. You can then copy that and paste it into the form post box. The tab will be enough to make sure the code is formatted correctly.

For those of you that use vi or vim, you can do

 %s:^:    :g

Those are 4 spaces in between the second and third colons. This will match the beginning of every line and replace it with 4 spaces.

Thanks again, Ralph and Rick, for being so helpful to other members.

Humberto

July 23, 2010
by Rick_S
Rick_S's Avatar

Humberto,

I'm happy to help when I can in the forums. I have been an electronics/computer enthusiast as long as I can remember. I started tearing apart electronic devices as a kid in the 70's and have loved this hobby of mine ever since. So any time I can pass along a bit of what I've learned I enjoy doing it.

I apologize if I came off poorly. I'm sure you do listen to what we say. It just seems that so many of us have made similar statements regarding the awkwardness of the forums that I blew off a little.

Some of the forums that I frequent use UBB.Classic. It makes it easy to post code, quote others, edit posts, etc...

Just curious, why you don't use something like that... It doesn't seem too expensive (less than $200 unless I'm looking at the wrong thing :D ). You wouldn't have to store files locally, most I use require you to link off site for photo's or files similar to the way your currently do. So I wouldn't think bandwidth would be an issue. I guess I just don't understand why the reluctance to a more feature rich software.

Is there something we members could do to help?

July 25, 2010
by ermias
ermias's Avatar

Hi Rick, I was trying to add some characters in font.h file. Actually i already modified the font.h file to add more characters. My problem is how to display them. can you Please help me out? I am new for c.

To make my question clear: for example in my font.h file i have a character called 'Al' that represent some kind of drawing. The array reads as follow:

const char font_2[ ] PROGMEM = { 'A1', 4, 0x1f, 0x10, 0x10, 0x1f, 0x00 };

so i want to display this drawing in my LED board using your scrolling function as follow:

scroll_display(PSTR("A1 "));

However, i couldn't do that because your scroll_display function takes one character at a time and compare that character with the characters in font.h file. As a result my LED board will display A and 1 instead of the drawing. I think there should be a way to make the font_get() and the font_display() functions to take two characters at a time instead of one. I have tried different ways and did succeed. Can You please give me a hint or help me modify the code.

Thanks,

Ermias

July 26, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi Rick_S,

Most of the reluctance to use other software comes from a very strong DIY spirit that launched NerdKits in the first place. Most forum implementations have large unwieldly code bases. We started out with an implementation that we were personally able to go through and verify that it could do what we wanted in the way we wanted it to. It is fast, relatively light weight, and best of all if something was to go awry with it (updated python versions, or something strange like that) we would probably be able to track down the problem. It is also built on django, which integrates semlessly into our website and user systems. At this point switching completely to a different implementaiton would require merging all the current forum, thread, and user models that work so well in python to a different implementation that might not even really match well. While not impossible, it would certainly not be trivial (easily the work of months of coding).

At the big picture level, I would say the forums have been extremely successful. We originally envisioned it as a place to supplement the material in the guide, but it has growm (much to our joy) into a real communinity where people share their projects and really help each other learn.

We will certainly work to end those little annoyances like having to add 4 spaces to format code, and will always listen to your suggestions about how to improve our site.

Humberto

July 26, 2010
by Rick_S
Rick_S's Avatar

Well, that definitely cleared up a lot of the reasoning behind your thought process. I can understand that line of logic. I'd love to see a stronger forum software, but honestly hadn't thought of the transfer of the existing forums into a new software. Hopefully either the original developers or someone on your team will incorporate some of the additional features that make forums a bit more user friendly.

I don't want to sound ungrateful, I do appreciate the forum you have provided as I have learned quite a bit through it myself and have done my best to continue passing on what I have learned.

Also, I want to thank you personally for being so active in your forums. It's good to see the people who founded things as active and in the middle of things as you and Mike are. Your active participation has kept things alive.

Thanks for taking the time to fill us in,

Rick

July 27, 2010
by Rick_S
Rick_S's Avatar

Humberto,

Along the django/BSD forum line, have you seen LBForum? Here's a snippet from their website.... I will however plead ignorance in forum software... Just giving a little info in case it could help... If nothing else, maybe some of his code could help you with the current forum software you use.

Link to info

Rick

July 28, 2010
by jdnewt
jdnewt's Avatar

Rick

Thanks for helping with the code, the only issue now is when i try to load the program i get an error message. do i need to modify the makefile to get it to load properly on the array? If you could help again i would greatly appreciate it. Thanks in advance

July 28, 2010
by jdnewt
jdnewt's Avatar

Rick

I was also looking at the "twinkle" effect you have on your project, and also was wondering where i can put that in the coding to get it to work inbetween scrolling messages. I tried modifying the test pattern code to change it to the twinkle effect but i cant seem to get anything to work besides just the original test pattern or sending a scrolling message through putty. which when it scrolls through that it does not loop.

July 28, 2010
by Rick_S
Rick_S's Avatar

What error message do you get?

The "Twinkle" effect I had was done by modifying the original ledarray_testpattern() function.

If you look at the tutorial here on the website, the original test pattern, started at the top left and one by one turned on each LED. This was the function as originally written.

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);
    }
  }
}

In my modified function which does the twinkle, I changed it to light every other LED then toggle between them 10 times as shown here.

void ledarray_testpattern() {
    uint8_t i, j, ct;
    ledarray_blank();
    // set initital pattern (every other LED on)
    for(i=0;i<ROWS;i++) {
        for(j=i%2;j<COLS;j += 2) {
        ledarray_set(i,j, 1 - ledarray_get(i,j));
        }
    }
    //wait 50ms
    delay_ms(50);

    // toggle the pattern turning what was on off then back on again 10 times
    for(ct=0;ct<10;ct++){
        for(i=0;i<ROWS;i++) {
            for(j=0;j<COLS;j++) {
                ledarray_set(i,j, 1 - ledarray_get(i,j));
            }
        }
        delay_ms(50);
        for(i=0;i<ROWS;i++) {
            for(j=0;j<COLS;j++){ 
                ledarray_set(i,j, 1 - ledarray_get(i,j));
            }
        }
        delay_ms(50);
    }
}

All you should need to do to make the twinkle happen is call that function

ledarray_testpattern();

And it should work.

Rick

PS, THANK YOU Humberto or whomever at NK Headquarters for the code button below!!!

July 28, 2010
by jdnewt
jdnewt's Avatar

Rick

Thanks alot for your help. I actually just got back on here to tell you that I finally got it up and running correctly and modified it to say what I wanted. I even added in the twinkle effect after different messages. Now im just looking to find a way to create my own effects. if you figure out any new effects let me know, as for now i will be just messing around with the test pattern to see if i can create something incredible.

October 17, 2010
by Ralphxyz
Ralphxyz's Avatar

One effect I'd like to see is to turn off the letter/symbol leds and turn all of the rest of them on, sort of a negative display.

Yes this is something I am looking for in a future project that I am laying out in my mind.

Ralph

December 20, 2010
by Farmerjoecoledge
Farmerjoecoledge's Avatar

Hello again Rick, Merry Christmas to you, and yours.

It's been a while since I've been around all's ok now but I caught a nasty bug from clicking on a picture. Left me no choice but to reinstall the os. In the process I lost most everything from here including the code you made from the pieces above. It read Merry Christmas and Happy New Year. If I'm not mistaken you emailed it to me, hence no record of it here. Would you be so kind as to post it or send it again to grant8of8@shaw.ca if it's not too much trouble.

To make matters worce, when I added grant8of8 to windows live mail I had 800 something unopened emails transfered which I didn't want on my hdd so I deleted them. F**k I didn't have the "keep a copy on server" box checked and it deleted everything from the server. By the time I realized what happened they were no longer in the deleted folder either. Gone! everything from here, everything from when I first signed up 4yrs ago. It's like losing the left side of my brain, all of my memories gone. Your email (code) was in there.

Thanks, and if you ever need anything just ask, ok.

Grant

December 21, 2010
by Rick_S
Rick_S's Avatar

Hey Grant!!

Long time no hear :)

I have my full code posted here on one of the threads... HERE

About half way down you'll find a post from July 21st of this year. That is the most recent code I have.

How've things been up there in Edmonton? Pretty cold and snowy this time of year I'd imagine. It had been so long since you were around I was afraid you'd given up on us and the projects. It's good to see you're still at it. Sorry to hear about the data loss. If there's anything else I can get you, let me know.

It's good to hear from you again... Don't be a stranger... And Merry Christmas to you and your family as well!

Rick

December 21, 2010
by Farmerjoecoledge
Farmerjoecoledge's Avatar

Thanks for the quick reply.

Yeah it's cold and snowing here, fairly normal for this part of the world. It's those poor people in the UK that are really getting nailed. The travellers are one thing but the oil prices the skyrocketing too. eight years ago it was 17cents per liter now some are charging as much as 99cents per/liter and that's if you can get it delivered. That storm is supposed to last another week. It's winter, but I'm glad I'm here.

It's still blurry but you posted this video http://www.youtube.com/watch?v=5GDMhi3ob7w and it's that code you sent me. I remember just adding my own text which I still have loaded and functioning but I lost the code. Your's and mine. If that makes sence to you then good. Other wise, I realize it's all above and i'll try to put it together.

Thanks again,

Grant

December 22, 2010
by Rick_S
Rick_S's Avatar

Grant,

Sorry for that, I forgot you'd need all the code, not just the program itself. I've sent you a zip of the whole folder. That should get you up and running.

If you have any other questions, feel free to ask.

Again, it's good to hear from you again. We had many the in depth conversations in days gone by.

Rick

December 04, 2011
by SirHobbes3
SirHobbes3's Avatar

THANK YOU SO MUCH FOR YOUR WORK RICK!!!!! This code is awesome and it even made me understand this stuff a little better!

December 04, 2011
by Rick_S
Rick_S's Avatar

No problem, glad it was of help.

Rick

Post a Reply

Please log in to post a reply.

Did you know that you can build a circuit to convert the "dit" and "dah" of Morse code back into letters automatically? Learn more...