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.

Project Help and Ideas » help with timing

November 04, 2012
by jfreethy
jfreethy's Avatar

Hello everybuddy,

In the clode below I am pressing a button the get the value (a1)which is a unit of time.Which is turning on an LED and the user input time(a1)I would like to keep that led on for 500ms but still move along with the code. for example the user inputs 100ms for (a1) I would like each led to turn on 100ms apart but stay light for 500ms total time. The fuction of delay was my failed attempt to adjust the timing.

code;

delay = ((500 +a1)-500);
 // wait untill fire imput 
if (fire() == 1)
{
}
else
// turn on LED or fire
{ // LED as output

  PORTC |= (1<<PC4); //TURN LED's ON
    delay_ms(delay);    
    PORTC &= ~(1<<PC4);// turn off led
        delay_ms(a1);
         //wait for delay value
    PORTC |= (1<<PC3);
    delay_ms(delay);
    PORTC &= ~(1<<PC3);
             delay_ms(a1);

    PORTC |= (1<<PC2);
        delay_ms(delay);
    PORTC &= ~(1<<PC2);
            delay_ms(a1);

    PORTC |= (1<<PC1);
    delay_ms(delay);    
    PORTC &= ~(1<<PC1);
            delay_ms(a1);

    PORTC |= (1<<PC0);
        delay_ms(delay);
    PORTC &= ~(1<<PC0);
            delay_ms(a1);

    PORTB |= (1<<PB5);
        delay_ms(delay);
    PORTB &= ~(1<<PB5);
            delay_ms(a1);

    PORTB |= (1<<PB4);
        delay_ms(delay);
    PORTB &= ~(1<<PB4);
        delay_ms(a1);

    PORTB |= (1<<PB3);
        delay_ms(delay);
    PORTB &= ~(1<<PB3);
        delay_ms(a1);

    PORTB |= (1<<PB2);
        delay_ms(delay);
    PORTB &= ~(1<<PB2);
        delay_ms(a1);

    PORTB |= (1<<PB1);
        delay_ms(delay);
    PORTB &= ~(1<<PB1);
        delay_ms(a1);

    PORTB |= (1<<PB0);
        delay_ms(delay);
    PORTB &= ~(1<<PB0);
        delay_ms(a1);
    delay_ms(100);
November 05, 2012
by JimFrederickson
JimFrederickson's Avatar

Look in the Forum "Microcontroller Programming" under "Double Tap Program, need help points"...

There is a discussion there with code that will help with what you are doing.

While the "delay_ms()" function is convenient you end up creating, at least what I call, a stuttering affect.

NOTHING ELSE can be done/processed while the "delay_ms()" is executing.

In order to avoid this problem you need to create a "Timebase" as well as change your programming thought process to become one more directly inline with programming for "Conditions, Events, Actions"...

I am also VERY BIG on making sure that input to my programs is valid. So for me I ALWAYS debounce and validate all switches or buttons before they are processed by my program. ("debouncing" is the process to remove electrical/mechanical interference from a button/switch. "validation" is, for me, refers to is it the appropriate time to recognize a button press, what is the "valid event" that this button press creates.)

The following code is from the aforementioned thread that I think has direct validity to what you are trying to accomplish.

    //  This should turn the LED on and keep it on for 1 second after the button is released
        uint8_t     mode_select1;
        uint16_t    flashcounter1;

        uint8_t     button1_state;
        uint8_t     button1_debounce_count;
        uint8_t     button1_pressed;

        mode_select1 = 0;
        flashcounter1 = 0;

        button1_debounce_count = 0;
        button1_pressed = 0;

        while(1) {  //main loop

            button1_state = (PINC & (1<<PC2)) >> PC2;

    //  Is the button being pressed
            if (button1_state == 0) {
                button1_debounce_count++;           //  Update our debounce count
                if (button1_debounce_count > 7) {   //  Once out debounce count > 7 we accept the button is being pressed
                    button1_debounce_count = 7;     //  Here we are just making sure we don't go beyound our Max debounce count
                    button1_pressed = 1;            //  Set button pressed state
                    }
                }
            else {
                if (button1_debounce_count != 0) {
                    button1_debounce_count--;       //  Our button is not pressed reduce debounce count
                    }
                else {
                    button1_pressed = 0;            //  Our becounce count is at 0 so the button is not being pressed
                    }
                }

    //  Do we have a valid button press
            if (button1_pressed == 1) {
                mode_select1 = 1;                   //  Set our mode to LED on
                flashcounter1 = 1000;               //  Set out timeout to 1,000 msec
                PORTB &= ~(1<<PB5);             //  Turn on the lead
                }

    //  If our counter has timed out and the mode is LED on then we need to change the mode and turn the LED off
            if ((flashcounter1 == 0) &&
                (mode_select1 == 1)) {
                mode_select1 = 0;
                PORTB |= (1<<PB4); 
                }

            delay_ms(1);

            if (flashcounter1 != 0) {
                flashcounter1--;
                }

            }
November 05, 2012
by Ralphxyz
Ralphxyz's Avatar

Here is the link to that Double Tap Program, need help points thread.

There are 640 threads in Microcontroller Programming to search through, which would be very informative but I would get very distracted looking at other "interesting" threads while I was looking for Double Tap.

And of course someone should post this subject to the Nerdkit Community Library as it seems to come up often.

Just Jim's exhortation of "Conditions, Events, Actions" would make a great article on best practices for programming. But the "timing" issue is applicable to so many projects to say nothing about switch debounce.

Ralph

November 05, 2012
by jfreethy
jfreethy's Avatar

Thank you everyone for your help. This was only but A snapshot of the over all code which is roughly 400 lines.

Cheers,

Jason

November 06, 2012
by pcbolt
pcbolt's Avatar

Jason -

Cool concept, not as simple as it sounds though. I think the way I would approach it is to create a couple of int16_t arrays to control when to turn each LED on and off. OK so as I understand it if the user inputs 100ms, LED1 lights up, LED2 lights up 100ms later, LED3 lights up 200ms after the first LED, LED4 lights up 300ms after the first LED, LED5 lights up 400ms after the first LED, LED6 lights up 500ms after the first LED AND LED1 turns off at the same time. So if you have an array called "light_on" and another called "light_off" , you can load it with the following...

for (i = 0; i < number_of_LEDs; i++){ 
  light_on[i] = i * a1;
  light_off[i] = light_on[i] + 500;
}

All you need now is a timer to count milliseconds using either the "Realtime Clock" code which uses interrupts, or in your main loop just have a "delay_ms(1)" execute along with a counter variable called say "tick_count" that increments by one for each loop. If LED1 is PC4 and LED2 is PC3 you can use this code to turn them on or off...

if (light_on[0] > tick_count) PORTC |= (1<<PC4);
if (light_off[0] > tick_count) PORTC &= ~(1<<PC4);
if (light_on[1] > tick_count) PORTC |= (1<<PC3);
if (light_off[1] > tick_count) PORTC &= ~(1<<PC3);
// etc

Don't worry if the light goes on then off eacch time, it will happen too quickly to notice.

November 06, 2012
by jfreethy
jfreethy's Avatar

pcb bolt I applied the code as you layed out and get error subsripted value is neither arry nor pointer.as an error.

any idea way;

{
if (time_read() == 1) //stand by
{
}
else // start timer for menu
{
a1 = abs (a1 + 5);
delay_ms(60); // give user time to press the button
}
for(i = 0; i < number_of_LEDs; i++)
 {  
 light_on[i] = i * a1;  
 light_off[i] = light_on[i] + 500;}

 // lcd go to time delay imput information
 lcd_home();
 lcd_line_one();
  lcd_write_string(PSTR("Select delay"));
  lcd_line_two();
  lcd_write_int16(a1);
  lcd_write_string(PSTR("MS "));

 // wait untill fire imput 
if (fire() == 1)
{
}
else
// turn on LED or fire
{ // LED as output

if (light_on[0] > tick_count) PORTC |= (1<<PC4);
if (light_off[0] > tick_count) PORTC &= ~(1<<PC4);
if (light_on[1] > tick_count) PORTC |= (1<<PC3);
if (light_off[1] > tick_count) PORTC &= ~(1<<PC3);
if (light_on[2] > tick_count) PORTC |= (1<<PC2);
if (light_off[2] > tick_count) PORTC &= ~(1<<PC2);
if (light_on[3] > tick_count) PORTC |= (1<<PC1);
if (light_off[3] > tick_count) PORTC &= ~(1<<PC1);
if (light_on[4] > tick_count) PORTC |= (1<<PC0);
if (light_off[4] > tick_count) PORTC &= ~(1<<PC0);

if (light_on[5] > tick_count) PORTB |= (1<<PB5);
if (light_off[5] > tick_count) PORTB &= ~(1<<PB5);
if (light_on[6] > tick_count) PORTB |= (1<<PB4);
if (light_off[6] > tick_count) PORTB &= ~(1<<PB4);
if (light_on[7] > tick_count) PORTB |= (1<<PB3);
if (light_off[7] > tick_count) PORTB &= ~(1<<PB3);
if (light_on[8] > tick_count) PORTB |= (1<<PB2);
if (light_off[8] > tick_count) PORTB &= ~(1<<PB2);
if (light_on[9] > tick_count) PORTB |= (1<<PB1);
if (light_off[9] > tick_count) PORTB &= ~(1<<PB1);
if (light_on[10]    > tick_count) PORTB |= (1<<PB0);
if (light_off[10] > tick_count) PORTB &= ~(1<<PB0);
    }
November 06, 2012
by pcbolt
pcbolt's Avatar

Hi Jason -

I don't know what code is above the portion you posted, but you should have a couple of declarations in the early portions of "main()" that look like...

uint8_t number_of_LEDs = 11;
uint16_t light_on[number_of_LEDs];
uint16_t light_off[number_of_LEDs];

I don't think there is a library file you need to include, but I'll look into it. If it still does not work, let me know I'll see if something else is wrong.

November 07, 2012
by jfreethy
jfreethy's Avatar

I did not have the declarations in the main .... douh but here is my full code below. When I go to make all it says that my uint8_t tick_count; declaration my not be called.

//led_blink.c
// for NerdKits with ATmega168
// jason_Freethy

#define F_CPU 14745600
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include <string.h>
// PIN DEFINITIONS:
//
// PC4 -- OUTPUT
// PC3 -- OUTPUT
// PC2 -- OUTPUT
// PC1 -- OUTPUT
// PC0 -- OUTPUT
//
// PB5 -- OUTPUT
// PB4 -- OUTPUT
// PB3 -- OUTPUT
// PB2 -- OUTPUT
// PB1 -- OUTPUT

void led_output(){
// LED as output
  DDRC |= (1<<PC4);
  DDRC |= (1<<PC3);
  DDRC |= (1<<PC2);
  DDRC |= (1<<PC1);
  DDRC |= (1<<PC0);

  DDRB |= (1<<PB5); // OUTPUT ON PORTB
  DDRB |= (1<<PB4);
  DDRB |= (1<<PB3);
  DDRB |= (1<<PB2);
  DDRB |= (1<<PB1);
  }
void time_input(){
DDRC &= ~(1<<PC5); // set Pc5 as input

PORTC |= (1<<PC5); // turn on pull up resistor
 }
uint16_t time_read(){
if(PINC & (1<<PC5)) {
    return 1;
  } else {
    return 0;
  }
}

void Read_sequencer(){
DDRD &= ~(1<<PCINT16); // EMATCH FIRE

PORTD |= (1<<PCINT16); // PULL UP RESISTOR FOR EMATCH
}
uint8_t fire(){
if(PIND & (1<<PCINT16)) {
    return 1;
  } else {
    return 0;
  }
}
void Button_2(){
DDRB &= ~(1<<PB0);
PORTB |= (1<<PB0);
}
uint8_t Button2(){
if (PINB & (1<<PB0)){
return 1;
}else{
return 0;
}
}
void Button_3(){
DDRD &= ~(1<<PCINT17);
PORTD |= (1<<PCINT17);
}
uint8_t Button(){
if (PIND & (1<<PCINT17)){
return 1;
} else {
return 0;
}
}

    int main() {
//declare uinte used for our imput
led_output();
time_input(); 
Read_sequencer();
Button();
Button2();

uint8_t cue;
int16_t a1;
lcd_init(); // main screen on start up
  lcd_clear_and_home();
  lcd_line_one();
  lcd_write_string(PSTR("Sky Painter v1.0"));
delay_ms(2000); // delay to make it able to be viewed by the user
lcd_clear_and_home();
  delay_ms(500);

// lcd go to time delay imput information
 lcd_home();
 lcd_line_one();
 lcd_write_string(PSTR("Mode selection"));
 lcd_line_two();
  lcd_write_string(PSTR("1 Sequence Mode "));
 lcd_line_three();
  lcd_write_string(PSTR("2 Stepper Mode" ));
  lcd_line_four();
  lcd_write_string(PSTR("3 Fire all Mode"));
while(1){

if(time_read()==0){
lcd_clear_and_home();
while(1){
if (time_read() == 1) //stand by
{
}
else // start timer for menu
{
a1 = abs (a1 + 5);
delay_ms(60); // give user time to press the button
}

 // lcd go to time delay imput information
 lcd_home();
 lcd_line_one();
  lcd_write_string(PSTR("Select delay"));
  lcd_line_two();
  lcd_write_int16(a1);
  lcd_write_string(PSTR("MS "));

 // wait untill fire imput 
if (fire() == 1)
{
}
else
// turn on LED or fire
{ // LED as output
uint8_t i;
uint8_t tick_count;
uint8_t number_of_LEDs = 11;
uint16_t light_on[number_of_LEDs];
uint16_t light_off[number_of_LEDs];
for(i = 0; i < number_of_LEDs; i++)
 {  
 light_on[i] = i * a1;  
 light_off[i] = light_on[i] + 500;}

if (light_on[0] > tick_count) PORTC |= (1<<PC4);
if (light_off[0] > tick_count) PORTC &= ~(1<<PC4);
if (light_on[1] > tick_count) PORTC |= (1<<PC3);
if (light_off[1] > tick_count) PORTC &= ~(1<<PC3);
if (light_on[2] > tick_count) PORTC |= (1<<PC2);
if (light_off[2] > tick_count) PORTC &= ~(1<<PC2);
if (light_on[3] > tick_count) PORTC |= (1<<PC1);
if (light_off[3] > tick_count) PORTC &= ~(1<<PC1);
if (light_on[4] > tick_count) PORTC |= (1<<PC0);
if (light_off[4] > tick_count) PORTC &= ~(1<<PC0);

if (light_on[5] > tick_count) PORTB |= (1<<PB5);
if (light_off[5] > tick_count) PORTB &= ~(1<<PB5);
if (light_on[6] > tick_count) PORTB |= (1<<PB4);
if (light_off[6] > tick_count) PORTB &= ~(1<<PB4);
if (light_on[7] > tick_count) PORTB |= (1<<PB3);
if (light_off[7] > tick_count) PORTB &= ~(1<<PB3);
if (light_on[8] > tick_count) PORTB |= (1<<PB2);
if (light_off[8] > tick_count) PORTB &= ~(1<<PB2);
if (light_on[9] > tick_count) PORTB |= (1<<PB1);
if (light_off[9] > tick_count) PORTB &= ~(1<<PB1);
if (light_on[10]    > tick_count) PORTB |= (1<<PB0);
if (light_off[10] > tick_count) PORTB &= ~(1<<PB0);
    }
    }
    }       
if(Button2() == 0){
lcd_clear_and_home();

//lcd go to time delay imput information
 lcd_home();
 lcd_line_one();
  lcd_write_string(PSTR("Stepper mode"));
 // wait untill fire imput 
#define cue1 1
#define cue2 2 
#define cue3 3
#define cue4 4
#define cue5 5 
#define cue6 6
#define cue7 7 
#define cue8 8 
#define cue9 9 
#define cue10 10

while(1){

if (fire() ==1) //stand by
{
}
else // start timer for menu
{
cue ++;
delay_ms(100); // give user time to press the button
}
switch (cue){

case cue1:
    PORTC |= (1<<PC4); //TURN LED's ON
    delay_ms(500);
    PORTC &= ~(1<<PC4); 
    break;
    // turn off led
case cue2:
    PORTC |= (1<<PC3);
    delay_ms(500);
    PORTC &= ~(1<<PC3);
    break;   
case cue3:
    PORTC |= (1<<PC2);
        delay_ms(500);
    PORTC &= ~(1<<PC2);
    break;      
case cue4:          
    PORTC |= (1<<PC1);
    delay_ms(500);  
    PORTC &= ~(1<<PC1);
    break;      
case cue5:          
    PORTC |= (1<<PC0);
        delay_ms(500);
    PORTC &= ~(1<<PC0);
    break;      
case cue6:  
    PORTB |= (1<<PB5);
        delay_ms(500);
    PORTB &= ~(1<<PB5);
    break;      
case cue7:             
    PORTB |= (1<<PB4);
        delay_ms(500);
    PORTB &= ~(1<<PB4);
    break;  
case cue8:             
    PORTB |= (1<<PB3);
        delay_ms(500);
    PORTB &= ~(1<<PB3);
    break;  
case cue9:
    PORTB |= (1<<PB2);
        delay_ms(500);
    PORTB &= ~(1<<PB2);
    break;  
case cue10:     
    PORTB |= (1<<PB1);
        delay_ms(500);
    PORTB &= ~(1<<PB1);
    break;  
default:
    PORTB |= (1<<PB0);
        delay_ms(500);
    PORTB &= ~(1<<PB0);
}
}
}

if(Button()==0){
lcd_clear_and_home();
lcd_line_one();
lcd_write_string(PSTR("All Fire Mode"));
while(1){
if (fire() == 1) //stand by
{
}
else // start timer for menu
{

    PORTC |= (1<<PC4); //TURN LED's ON
    PORTC |= (1<<PC3);
    PORTC |= (1<<PC2);
    PORTC |= (1<<PC1);
    PORTC |= (1<<PC0);  
    PORTB |= (1<<PB5);             
    PORTB |= (1<<PB4);             
    PORTB |= (1<<PB3);
    PORTB |= (1<<PB2);  
    PORTB |= (1<<PB1);
    PORTB |= (1<<PB0);
        delay_ms(500);

PORTC &= ~(1<<PC4);// turn off led
PORTC &= ~(1<<PC3); 
PORTC &= ~(1<<PC2);
PORTC &= ~(1<<PC1);
PORTC &= ~(1<<PC0);
PORTB &= ~(1<<PB5);
PORTB &= ~(1<<PB4);
PORTB &= ~(1<<PB3);
PORTB &= ~(1<<PB2);
PORTB &= ~(1<<PB1);
PORTB &= ~(1<<PB0);

}
}
}

}

return 0;

}
November 07, 2012
by pcbolt
pcbolt's Avatar

Jason -

Pretty sure you're getting that error or warning because the declarations are made inside an if/else block. Also, they will get declared over and over again inside the while(1) loop and that isn't what you want (not sure what happens in that case, it depends on how smart the compiler is). To get rid of the error/warning, move lines 153 to 157 and put them right after line 104 where the other declarations are. You might want to move the "define cue" lines (199-208) to the beginning of the code (after line 16) but I don't think it will cause a problem if you don't.

November 08, 2012
by jfreethy
jfreethy's Avatar

I made the corrections that you suggested PCBolt and I can make the program with out any errors. However, when I press the button start the sequence it does nothing. Could it be that I have not defined anything for the tick_count function?

November 08, 2012
by pcbolt
pcbolt's Avatar

Jason -

Usually the compiler sets the variables to 0 if you don't assign anything to them when you declare them. If you are worried about it you can just set it to 0 just like you set the "number_of_LEDs" variable to 11. You still need to increment it in the loop each time and add a delay of 1 mSec, best to do it right after this line...

if (light_off[10] > tick_count) PORTB &= ~(1<<PB0);
tick_count++;
delay_ms(1);

You also need a way to escape the "while(1)" loop so you can jump to the lower sections in your code. I'm not sure what you want to have happen but let say after LED10 goes off, you're done with that part of the code, you can modify the code above to...

if (light_off[10] > tick_count) PORTB &= ~(1<<PB0);
tick_count++;
delay_ms(1);
if ((light_off[10] > tick_count) break;

Post a Reply

Please log in to post a reply.

Did you know that you can aim and fire a servo-controlled water gun from your computer? Learn more...