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 » Populating an Array

July 04, 2011
by Ralphxyz
Ralphxyz's Avatar

I am trying to populate line_display[] with 255 elements holding 0 - 255.

            ON = 100;
            OFF = 25;

        int8_t i=0; 
        int8_t line_display[255];
        for ( i = 0; i < 255 ;i++ ) 
            {
                line_display[i] = i;
            }

        int8_t x = 0;
        for ( x = 0; x < 255 ;x++ ) 
            {
                PORTD |= (line_display[x]);      
                delay_ms(ON);
                PORTD &= ~(line_display[x]);
                delay_ms(OFF);
            }
        return 0;

This code compiles but nothing happens with my LEDs connected to PORTD.

Of course since I am using PORTD I have no Terminal or LCD for output testing.

I have to figure out how to use a AVR-gcc debugger but until then I need help from my friends :-)

Ralph

July 04, 2011
by Ralphxyz
Ralphxyz's Avatar

In conjunction with my above question about populating the line_display[] array why doesn't this program count correctly?

    ON = 500;
    OFF = 1500;

    int8_t i=0; 
    int8_t line_display[255];

    int8_t x = 0;

    for ( x = 0; x < 255 ;x++ ) 
        {
        PORTD |= (line_display[x]);      
        delay_ms(ON);
        PORTD &= ~(line_display[x]);
        delay_ms(OFF);      
        }

This counts to 15 correctly and then jumps all over the place. I would "think" it would just keep incrementing by 1.

Not using an array increments correctly:

    int8_t x = 0;

    for ( x = 0; x < 255 ;x++ ) 
        {
        PORTD |= (x);        
        delay_ms(ON);
        PORTD &= ~(x);
        delay_ms(OFF);      
        }

Ralph

July 04, 2011
by esoderberg
esoderberg's Avatar

Ralph,

I think I can see what you're trying to do. Try this code; I verified that it runs and lights up LEDs on PORTD in sequence counting in binary up to 1 byte.

#define F_CPU 16000000
#include "../utility/io_328p.h"
#include <avr/io.h>
#include <inttypes.h>

#include "../utility/delay.h"
#include "../utility/lcd.h"

uint8_t i=0;

int main() {

UCSR0B = 0;

  // LED as output
  DDRC |= 0xFF;

  // loop keeps looking forever
  while(1) {
  for (i=0; i<256; i++) {

    // turn on LED
    PORTD = i;

    //delay for 200 milliseconds to let the light stay on
    delay_ms(200);

    // turn off LED
    PORTD = 0;

    //delay for 200 milliseconds to let the light stay off
    delay_ms(200);

  }
  }

  return 0;
}
July 04, 2011
by Ralphxyz
Ralphxyz's Avatar

Thanks esoderberg, that works but I need to use an array. This is for my Water Curtain project and so far the best way I can see to do it is using an array.

I need to be able to reference the different array elements to build my letters and symbols.

I even tried populating the array elements individually:

uint16_t line_display[255];
    line_display[0] = 0;
    line_display[1] = 1;
    line_display[2] = 2;
    line_display[3] = 3;

But that doesn't work either.

So I guess my question is how does one initialize and populate an array?

Ralph

July 04, 2011
by Noter
Noter's Avatar

Ralph,

0 to 255 is 256 elements so start by defining your array as [256]. Then use a 16 bit integer to index the array so it can be > 255. Otherwise the code looks ok but check for warnings and fix any that you find. If it still doesn't work, post the whole program and I'll give it a go to see if it works for me. Otherwise we have to assume things like you configured PORTD for output, etc.

ON = 500;
OFF = 1500;

int16_t i; 
int8_t line_display[256];

int16_t x;

for ( x = 0; x < 256 ;x++ ) 
    {
    PORTD |= (line_display[x]);      
    delay_ms(ON);
    PORTD &= ~(line_display[x]);
    delay_ms(OFF);      
    }
July 04, 2011
by esoderberg
esoderberg's Avatar

Ralph,

An oddity I noticed in my posted code, I set PORTC as output, with DDRC |= 0xFF;, when I was intending to set PORTD. What is odd is that ran just fine with LEDs attached to PORTD. As to your real question IRT arrays, I'm sure with Noter on it you'll be set.

Eric

July 04, 2011
by Ralphxyz
Ralphxyz's Avatar

Thanks Paul I thought I would need the 16 bit integer.

With that fix and initializing the array I have it working!!

Here is the working code in case anyone would like 8 blinking leds using PORTD.

// led7a.c
// for NerdKits with ATmega328p
// rhulslandergmail.com

#define F_CPU 14745600
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "../libnerdkits/io_328p.h"
#include "../libnerdkits/delay.h"

int main (void)
{
    UCSR0B = 0;                 // turn off the UART call from the bootloader

    /*  set PORTD for output  
        DDRD means Data Direction for PORTD
        DDRx is DataDirection Register Sets PD0, PD1, PD2, PD3, PD4, PD5, PD6 and PD7 high  11111111
    */

    DDRD = 0xFF;                    
    int16_t ON, OFF = 0, i;

    while (1) 
        {
            ON = 500;
            OFF = 500;

        uint16_t line_display[256] = {0};                  // initialize array
    //* 
         for ( i = 0; i < 255 ;i++ ) 
         {
         line_display[i] = i;                                      // populate the array
         }

     int8_t x = 0;
         for ( x = 0; x < 255 ;x++ ) 
         {
            PORTD |= (line_display[x]);      // light the LEDs on PORTD
            delay_ms(ON);
            PORTD &= ~(line_display[x]);
            delay_ms(OFF);
         }
    }
    return 0;
}

I even have all of my warnings fixed!!

Thanks Noter and esoderberg,

Ralph

July 04, 2011
by Ralphxyz
Ralphxyz's Avatar

Well that code almost works.

I left it running for 10 minutes and all of a sudden the leds went blank for 30 seconds and then came back on with random displays.

It is no longer incrementing correctly, darn.

So I still need help.

It worked for 10 minutes correctly counting up to all eight leds lit and then starting over at 1 now it is completely random.

HELP

Ralph

July 04, 2011
by Ralphxyz
Ralphxyz's Avatar

I moved the array population code out of the while(1) loop.

I can see where that would cause a problem but it still counts to 255 and then goes to random displays.

Here is the corrected code segment but it still does not work!

int main (void)
{
    UCSR0B = 0;                 // turn off the UART call from the bootloader

    /*  set PORTD for output  
     DDRD means Data Direction for PORTD
     DDRx is DataDirection Register Sets PD0, PD1, PD2, PD3, PD4, PD5, PD6 and PD7 high  11111111
     */

    DDRD = 0xFF;                    
    int16_t ON, OFF = 0, i;

    uint16_t line_display[256] = {0};                  // initialize array
                                                       //*  
    for ( i = 0; i < 255 ;i++ ) 
        {
        line_display[i] = i;                                      // populate the array
        }
    while (1)

Ralph

July 04, 2011
by Noter
Noter's Avatar

Here it is with a couple of minor changes. No need to OR the data since every pin on PORTD is set everytime. Likewise to turn them off just set PORTD to zero. I reduced the delay counts to make it fast so I could see the whole array in a shorter time. Then I let it run for a while and it was still fine. If you still get random looking patterns with this code then I suspect you have a wire or two misplaced.

// led7a.c
// for NerdKits with ATmega328p
// rhulslandergmail.com

//#define F_CPU 14745600
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "../libnerdkits/io_328p.h"
#include "../libnerdkits/delay.h"

int main (void)
{
    UCSR0B = 0;                                 // make sure USART is disabled

    DDRD = 0xFF;                                // set all PORTD output
    int16_t ON, OFF = 0, i;
    uint16_t line_display[256];                 // allocate array

    for ( i = 0; i < 256 ; i++ ){
        line_display[i] = i;                    // initialize array
    }
    ON = 20;                                    // initialize delays
    OFF = 20;

    while (1){
        for ( i = 0; i < 256 ; i++ ){
            PORTD = (line_display[i]);          // light the LEDs on PORTD
            delay_ms(ON);
            PORTD = 0;                          // turn'em off
            delay_ms(OFF);
        }
    }
}
July 05, 2011
by Ralphxyz
Ralphxyz's Avatar

[quote] "If you still get random looking patterns with this code then I suspect you have a wire or two misplaced." [/quote]

Huh who me.

Actually it is running fine, thank you once again.

At the moment I am planning on being able to generate my letters and symbols for my Water Curtain from the array instead of hardcoding each letter and symbol in a lookup table.

Ralph

July 05, 2011
by Ralphxyz
Ralphxyz's Avatar

Paul your code prompts more questions:

//#define F_CPU 14745600
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "../libnerdkits/io_328p.h"
#include "../libnerdkits/delay.h"

I think I am hijacking my own thread but

You have #define F_CPU 14745600 commented out!

Why, what does this mean to my program?

Am I using a internal oscillator?

Ralph

July 05, 2011
by Noter
Noter's Avatar

I just forgot to put it back before posting. I set the F_CPU in my makefile and pass it via the compile command line so to avoid a warning when I build I comment out the line in the source file.

No, it doesn't change anything as far as which clock source is being used and probably makes no difference at all with the nerdkit delay code. Mostly it only makes a difference if you use F_CPU to calculate values to setup timers or bit rates.

The only way to use the internal clock is to set the fuses appropriately.

July 16, 2011
by BobaMosfet
BobaMosfet's Avatar

Instead of commenting out F_CPU, make the compiler tell the difference:

#ifndef F_CPU
#define F_CPU 14745600
#endif F_CPU

This way, if it isn't defined, it uses your define, otherwise, it relies on was was already defined in a previous header file.

BM

July 19, 2011
by Ralphxyz
Ralphxyz's Avatar

Ok so why do all 8 of the leds flash?

I just added an array, to Noter's code, to get a sequence of leds lit but all leds light.

#define F_CPU 14745600
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "../libnerdkits/io_328p.h"
#include "../libnerdkits/delay.h"

//int8_t slantLeft[7] = {3,6,12,24,48,96,192};

int main (void)
{
    UCSR0B = 0;                                     // make sure USART is disabled

    int8_t slantRight[] = {192,96,48,24,12,6,3};

    DDRD = 0xFF;                                    // set all PORTD output
    int16_t ON, OFF = 0, i;
    //uint16_t line_display[256];                   // allocate array
    ON = 20;                                        // initialize delays
    OFF = 20;

    while (1)
    {
        for ( i = 0; i < 7 ; i++ )                  // very strange if I do i--!!
        {
            //PORTD = (line_display[i]);            // light the LEDs on PORTD
            //PORTD = 3;
            PORTD = slantRight[i];
            delay_ms(ON);
            PORTD = 0;                              // turn'em off
            delay_ms(OFF);
        }
    }
}

Ralph

July 19, 2011
by bretm
bretm's Avatar

The "standard" Nerdkits makefile doesn't include array initialization constants in the .hex file. It uses "-j" parameter in one place to specify which binary sections of the file are included so the ".data" section, usually included by default, is omitted.

If this is what's going on in your project's makefile then the array could contain all 0xFF's which is the typical "blank" value in .hex files, which would make all the LEDs light.

July 19, 2011
by Noter
Noter's Avatar

Maybe it's working but a 20ms blink is so fast all the leds appear to be on all the time?

July 19, 2011
by Ralphxyz
Ralphxyz's Avatar

I have the .data in the Makefile:

avr-objcopy -j .text .data -O ihex $(ProjectName).o $(ProjectName).hex
#avr-objcopy -j .text -O ihex $(ProjectName).o $(ProjectName).hex

But when I compile I get this:

miniMac:watercurtain Me$ make
make -C ../libnerdkits
make[1]: Nothing to be done for `all'.
avr-gcc -g -Os -Wall -mmcu=atmega328p  -Wl,-u,vfprintf -lprintf_flt -Wl,-u,vfscanf -lscanf_flt -lm -o WC.o WC.c ../libnerdkits/delay.o ../libnerdkits/lcd.o ../libnerdkits/uart.o
WC.c: In function 'main':
WC.c:19: warning: unused variable 'slantRight'
avr-objcopy -j .text .data -O ihex WC.o WC.hex
Usage: avr-objcopy [option(s)] in-file [out-file]
 Copies a binary file, possibly transforming it in the process
 The options are:
  -I --input-target <bfdname>      Assume input file is in format <bfdname>
  -O --output-target <bfdname>     Create an output file in format <bfdname>
  -B --binary-architecture <arch>  Set arch of output file, when input is binary
  -F --target <bfdname>            Set both input and output format to <bfdname>
     --debugging                   Convert debugging information, if possible
  -p --preserve-dates              Copy modified/access timestamps to the output
  -j --only-section <name>         Only copy section <name> into the output
     --add-gnu-debuglink=<file>    Add section .gnu_debuglink linking to <file>
  -R --remove-section <name>       Remove section <name> from the output
  -S --strip-all                   Remove all symbol and relocation information
  ...

I slowed the flash rate down and still get the same all on/off!

If I use the line_display[] array:

int main (void)
{
    UCSR0B = 0;                                     // make sure USART is disabled

    int8_t slantRight[] = {192,96,48,24,12,6,3};

    DDRD = 0xFF;                                    // set all PORTD output
    int16_t ON, OFF = 0, i;
    uint16_t line_display[255] = {0};                   // allocate array
    ON = 2000;                                      // initialize delays
    OFF = 2000;

    while (1)
    {
        for ( i = 0; i < 7 ; i++ )                  // very strange!!
        {
            PORTD = (line_display[i]);          // light the LEDs on PORTD
            //PORTD = 3;
            //PORTD = slantRight[i];
            delay_ms(ON);
            PORTD = 0;                              // turn'em off
            delay_ms(OFF);
        }
    }
}

If I initialize the array uint16_t line_display[255] = {0}; the leds are off all of the time.

If I do not initialize the line_display[] array then I get a seemingly random pattern of leds lighting!

If I hard code PORTD = 3; then the value is displayed!

This really should not be so hard I could easily do this in C# on a Windows PC.

I'll try using a Struct and PROGMEM but it seems the benefit of using a Struct is that you essentially make the Struct a Type and you can reuse it.

I would have to have dedicated Structs for each configuration which seems contrary to what I have read about using Structs.

Of course I am back to trying to use PORTD without the LCD or serial port so I can only debug by the action of the leds.

I can not get 8 pins using PORTB or PORTC probable I could use both PORTS but that would be pushing my programing abilities.

Ralph

July 19, 2011
by Noter
Noter's Avatar

When I don't have the .data in the makefile, I get 0xFF for all the values. Then when I put in the .data, it works fine. So just to be sure it is not an initalization issue try initializing after you declare the array like so - this should work no matter about the .data in the makefile.

uint8_t slantRight[7];
slantRight[0] = 192;
slantRight[1] = 96;
slantRight[2] = 48;
slantRight[3] = 24;
slantRight[4] = 12;
slantRight[5] = 6;
slantRight[6] = 3;
July 19, 2011
by Noter
Noter's Avatar

By the way, I think your missing a -j in the makefile. This is what works for me:

avr-objcopy -j .text -j .data -O ihex $< $@
July 19, 2011
by Noter
Noter's Avatar

Some time ago I wrote these macros for port/pin manipulation and I've used them quite a bit since. With these you can assign whatever free pins you have available to control your solonoids which will allow you to keep your display connected. You will really need the display working as you progress and your program becomes more and more complex. The following sample is based on your test program and demonstrates how to use the macros. It will need a few tweaks for your environment (F_CPU, etc.) but otherwise it's ready to go. Look it over and see what you think.

#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <stdbool.h>

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

// pin I/O macros
//
#define INPUT2(port,pin) DDR ## port &= ~_BV(pin) 
#define OUTPUT2(port,pin) DDR ## port |= _BV(pin) 
#define CLEAR2(port,pin) PORT ## port &= ~_BV(pin) 
#define SET2(port,pin) PORT ## port |= _BV(pin) 
#define TOGGLE2(port,pin) PORT ## port ^= _BV(pin) 
#define READ2(port,pin) ((PIN ## port & _BV(pin))?1:0)
#define STATE2(port,pin) ((DDR ## port & _BV(pin))?1:0)
//
#define INPUT(x) INPUT2(x) 
#define OUTPUT(x) OUTPUT2(x)
#define CLEAR(x) CLEAR2(x)
#define SET(x) SET2(x)
#define TOGGLE(x) TOGGLE2(x)
#define READ(x) READ2(x)
#define STATE(x) STATE2(x)
#define PULLUP_ON(x) INPUT2(x); SET2(x)
#define PULLUP_OFF(x) INPUT2(x); CLEAR2(x)

// define ports, pins
#define DB0     B,1
#define DB1     B,2
#define DB2     B,3
#define DB3     B,4
#define DB4     B,5
#define DB5     C,0
#define DB6     C,1
#define DB7     C,2

void set_data_pins_output(){
    OUTPUT(DB0);
    OUTPUT(DB1);
    OUTPUT(DB2);
    OUTPUT(DB3);
    OUTPUT(DB4);
    OUTPUT(DB5);
    OUTPUT(DB6);
    OUTPUT(DB7);
}

void write_data_pins(uint8_t data){
    if(data & 1)    SET(DB0); else CLEAR(DB0);
    if(data & 2)    SET(DB1); else CLEAR(DB1);
    if(data & 4)    SET(DB2); else CLEAR(DB2);
    if(data & 8)    SET(DB3); else CLEAR(DB3);
    if(data & 16)   SET(DB4); else CLEAR(DB4);
    if(data & 32)   SET(DB5); else CLEAR(DB5);
    if(data & 64)   SET(DB6); else CLEAR(DB6);
    if(data & 128)  SET(DB7); else CLEAR(DB7);
}

FILE lcd_stream;

int main() {

//    uart_init();
//    UCSR0A = 0;
//    UBRR0L = (F_CPU/(16*BAUD))-1;
//    FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
//    stdin = stdout = &uart_stream;

    lcd_init();
    fdev_setup_stream(&lcd_stream, lcd_putchar, 0, _FDEV_SETUP_WRITE); 
    lcd_clear_and_home();
    stdin = stdout = &lcd_stream;

    uint8_t slantRight[7];
    slantRight[0] = 192;
    slantRight[1] = 96;
    slantRight[2] = 48;
    slantRight[3] = 24;
    slantRight[4] = 12;
    slantRight[5] = 6;
    slantRight[6] = 3;

    set_data_pins_output();
//    DDRD = 0xFF;                                    // set all PORTD output
    int16_t ON, OFF = 0, i;
//    uint16_t line_display[255] = {0};                   // allocate array
    ON = 500;                                      // initialize delays
    OFF = 500;

    while (1)
    {
        for ( i = 0; i < 7 ; i++ )                  // very strange!!
        {
            printf_P(PSTR("%d"),slantRight[i]);

            write_data_pins(slantRight[i]);

            //PORTD = (line_display[i]);          // light the LEDs on PORTD
            //PORTD = 3;
            //PORTD = slantRight[i];
            _delay_ms(ON);
            lcd_clear_and_home();
            //PORTD = 0;                              // turn'em off

            write_data_pins(0);

           _delay_ms(OFF);
        }
    }
}
July 20, 2011
by Ralphxyz
Ralphxyz's Avatar

Thanks Paul, I have seen your macros before but never could comprehend them.

I am actually starting to understand them this time.

I am trying to just get something working in order to establish the feasibility of what I am trying to do with my Water Curtain, so at the moment I do not care about the LCD or other aspects I just need to be able to see something predictable happen to the LEDS (water flow).

I have already spent a lot of time but do not know if it will actually work or what I might have to do to make it work!

If your -j correction to the make file does not get the arrays working I am just going to put all of the configurations inline.

This works:

PORTD = 3;
delay_ms(ON);
PORTD = 0;
delay_ms(OFF);
PORTD = 6;
delay_ms(ON);
PORTD = 0;
delay_ms(OFF);
PORTD =12;
delay_ms(ON);
PORTD = 0;
delay_ms(OFF);
PORTD = 24;
delay_ms(ON);
PORTD = 0;
delay_ms(OFF);
...

and on and on but it works and I get my test patterns so now I can test my solenoids and entire setup.

I have my four components (slantLeft, slantRight, Bar and Up) each repeated (full configuration) 10 times.

I think these configurations will give me all the views I need to prove the feasibility of my concept.

It takes up:

avrdude: 13302 bytes of flash verified

So I have lots of room for more configurations as I am using an ATmega328p micro.

It actually looks very impressive on the LEDs so now I can try with water.

I'll also setup my strobe light with manual speed control to see if I can get it to match the water drip.

Hopefully I'll be posting a video so you all can see what you have all been working on :-)

Ralph

Post a Reply

Please log in to post a reply.

Did you know that a thermometer can be made "faster" by using a bit of math? Learn more...