Go Down

Topic: 30 Second Timer + LED Display + Pager Motor HELP!! (Read 3 times) previous topic - next topic

Shubs

Hello members,

Firstly, mods I wasn't too sure about which sub-forum I should open this thread in. Please move as per necessary.

Description of my project:
Our project consists of Transmitting device (ATmega128 MC) and a Receiving device (ATmega168 [Arduino Mini]).
The transmitter is going to send signals (characters/strings) over RF and receiver will execute a few commands.

Intro of sorts:
The receiver will have a pager motor, 2 digit LED Display and LED. LED display will countdown from a specific time and then cause the pager motor to vibrate and reset the countdown. Simultaneously, the receiver will be 'listening' for commands from the transmitter and execute specific commands - Vibrate pager motor and/or reset the countdown.

Problem:

I have managed to code something using the Serial library that listens for an input. If I press / it receives 'a' it activates the pager motor for a 5000 ms  and if press / it receives 'b' it starts the countdown. I still need to incorporate the LED display have the segments turn on and off.

I realized that when I am using the countdown, I can't simultaneously execute other actions. I read up on interrupt commands, but could barely understand what I had to do. I, also, read up on how to change values in TIMER2 and I had hard time understanding that you. (Pardon me for being a Tissue engineer).

What I was hoping for, is a way that would keep the Countdown running and when I want the pager motor to vibrate, I could execute the command without interrupting the countdown.

I would appreciate any help from you guys! Thanks in advance.

Regards,
Shubs

Code: [Select]
/* include the SoftwareSerial library so you can use its functions:
#include <SoftwareSerial.h>
*/

int rxPin = 0;
int txPin = 1;
int motPin = 7;
int ledPin = 13;
Metro led_metro = Metro(500);

/* set up a new serial port
SoftwareSerial rfSerial =  SoftwareSerial(rxPin, txPin);
*/
byte pinState = 0;


void setup()  {
 // define pin modes for tx, rx, led pins:
 pinMode(rxPin, INPUT);
 pinMode(txPin, OUTPUT);
 pinMode(motPin, OUTPUT);
 pinMode(ledPin, OUTPUT);
 // set the data rate for the SoftwareSerial port
 Serial.begin(9600);
}

void loop() {
 // listen for new serial coming in:
 if (Serial.available() > 0)
 {  char someChar = Serial.read();
   // print out the character:
   Serial.print(someChar);
   // toggle an LED just so you see the thing's alive.  
   // this LED will go on with every OTHER character received:
   if (someChar == 'a'){
     motor(ledPin);
   }
   if (someChar == 'b'){
     timer(5000);
   }
 }

}

void timer(int time)
{
 for(int i = 0; i <= time; i++){
   Serial.println(i);
   ledBlink();
     }
     digitalWrite(ledPin, LOW);
 }

void ledBlink(){
 if (led_metro.check() == 1) { // check if the metro has passed it's interval .
   digitalWrite(ledPin,!digitalRead(ledPin)); // change the state of pin 13.
   if (digitalRead(ledPin)==HIGH)  {
     led_metro.interval(500); // if the pin is HIGH, set the interval to 0.5 seconds.
   }
   else {
     led_metro.interval(500); // if the pin is LOW, set the interval to 0.5 second.
   }
 }
}
void motor(int pinNum)
{
 digitalWrite(pinNum, HIGH);
 delayMicroseconds(5000);
 digitalWrite(pinNum, LOW);
}



BigMike

#1
Apr 21, 2008, 06:39 pm Last Edit: Apr 21, 2008, 06:39 pm by BigMike Reason: 1
My approach to this would not be to use interrupts, but to use state machines which are checked every milli second.

In pseudo code in the main loop I would havesomething like:

Code: [Select]

prvMilli = 0;

loop(){
 crtMilli = millis();
 if (crtMilli != prvMilli) {
   prvMilli = crtMilli;    

   // this bit runs every milli second - check for things to do

  if (serial.available){
    get the serial character
    if (serchar = 'a'){
     do the a thing
    }
    if (serchar = 'b'){
       do the 'b' thing
    }
   
    TimerVal --;
    if (TimerVal =<0){
       TimerVal = 5000;

       do teh 5 second timer stuff
     }
     etc.

  }
 }
}


All processes would be implemented as state machines with none of the states taking longer than a milli second - that way there are no clock cycles wasted.

I hope that was clear(ish).

Sorry for not putting up proper code - my first coding language isn't c.

Mike




mem

#2
Apr 21, 2008, 07:47 pm Last Edit: Apr 21, 2008, 08:20 pm by mem Reason: 1
Shubs, I have a clock timer library that I wrote that may help you do what you want. It enables functions to be called at user definable periods of time. Under the covers, it uses similar logic to that mentioned in  Mike's post, but it may be easier to use if you need to time multiple things in parallel (the current version supports eight different timers but more can be defined if needed.  But If you only need to time a single interval at a time, it may be easier to implement Mikes's suggestion.

Unfortunately, I have not documented it sufficiently to post somewhere like the playground. But have a look at this example sketch and if it looks useful, I will post the library code in the playground for you

Code: [Select]

// this example sketch needs the Clock library, the code for this library has not yet been posted !
#include <Clock.h>

int ledPin = 13;                // choose the pin for the LED
int motorPin = 12;              // pin to for the motor

TimerClass Timer1;  // this will be the 5 second timer


void setup(){
  Serial.begin(9600);  
  pinMode(ledPin, OUTPUT);      // declare LED as output
  pinMode(motorPin, OUTPUT);    // declare motor pin as output

 if( Clock.Register( Timer1 ) ) {        
    Timer1.Value = 5;                     // we want our timer to tick in 5 seconds
    Timer1.OnTickHandler = &OnTimer1Tick;  // and call this function when the timer matures
 }
 Serial.println("Finished setup");    
}

void OnTimer1Tick(void *Sender){
// this function is called when the timer matures
  Serial.println("timer has matured");
  digitalWrite(motorPin, LOW); // turn the motor off  
  Timer1.Disable();  // stop the timer from triggering until re-enabled
}

void  motor( int pin){
  // do some motor thing    
  digitalWrite(pin, HIGH);   // we just keep the LED on    
}
     
void loop(){
   // listen for new serial coming in:
   if (Serial.available() > 0)
   {
       char someChar = Serial.read();
      // print out the character:
      Serial.print(someChar);
      // toggle an LED just so you see the thing's alive.  
       digitalWrite(ledPin, HIGH);   // sets the LED on
       Clock.Delay(100);            // waits for 100 ms - note this is calling the Clock delay function!
       digitalWrite(ledPin, LOW);    // sets the LED off
       Clock.Delay(100);            // wait using clock delay function
       // this LED will go on with every OTHER character received:
      if (someChar == 'a'){
          motor(motorPin); // activate the motor
       }
      if (someChar == 'b'){
         Timer1.Enable();  // this will call the timer function in 5 seconds.    
         Serial.println(" started Timer");
       }
   }
   Clock.Delay(1); // this must be called to service the clock timer
}



edit: Looking over the library code to get it ready to post, I realized that it requires a modification to wiring.c that eliminates the millis overflow problem. I posted this mod here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1205791157/7#7  But this may be more then you really need to deal with.

Shubs

#3
Apr 21, 2008, 09:13 pm Last Edit: Apr 21, 2008, 09:21 pm by Shubs Reason: 1
Thanks for the replies BigMike & mem.

Mike, your code seems very easy and effective in terms of what I need to do. It was clear for the most part, although I had a couple of questions

a) what is the crtMillis value going to be when it loops through the first time? cause it seems like as soon as the value of crtMillis changes,  you set it back to 0.

b) I didn't quite understand the TimerVal --; thing. Is it an int, I presume so. How does it know how much time has passed? Do I set it equal to another millis function?

Mem, I think your code makes a lot of sense. I just wanted to know in slight detail of some the functions that your library has.

a) I am guessing the Timer1.value sets the value of the first time in Seconds?

b) Does it run through the setup each time? I guess once you define the value in the setup, it checks if it's actually equal to that.

Finally, whatever the time it might be, I also need to run a 2 digit LED display. I already checked some inbuilt libraries, but I had a hard time understanding them. I just need it do a countdown from 30 seconds. Thus every second it counts, I need it change the display to 30, 29... and reset it back to 30 once it's matured.

Again, I sincerely appreciate your help. They're pretty inane questions, but I just have a hard time understanding it.

EDIT - Would you able to upload the initial Clock library somewhere so I can use it? Also, wouldn't the delay function cause the whole code to stop for a the defined time?

Much respect.


mem

#4
Apr 21, 2008, 09:35 pm Last Edit: Apr 21, 2008, 09:37 pm by mem Reason: 1
>I am guessing the Timer1.value sets the value of the first time in Seconds?  
 Yes, the event hander for Timer1 (OnTimer1Tick) will be called 5 seconds after Timer1 is enabled

> Does it run through the setup each time? I guess once you define the value in the setup, it checks if it's actually  equal to that.  
 Once the value is set it will be maintained until it is explicitly set to something else.  The timer will actually continue to trigger every 5 seconds unless it is disabled, which is why it is disabled for your applicaiton when it matures, and re-enabled when a trigger arrives on the serial port.

> Finally, whatever the time it might be, I also need to run a 2 digit LED display. I already checked some inbuilt libraries, but I had a hard time understanding them. I just need it do a countdown from 30 seconds. Thus every second it counts, I need it change the display to 30, 29... and reset it back to 30 once it's matured.

I would implement this using a timer with a value of 1 second. Each time the event handler is called I would decrement a counter initially set to 30 by 1. You could display this number on the lcd and turn the motor off when it gets to 0.
But, if this is the functionality you want, it may just be easier to do it using the millis counter, as per Mikes proposal.

>Also, wouldn't the delay function cause the whole code to stop for a the defined time?
 Calling Clock.Delay()  blocks the foreground sketch for the given number of millis (one millisecond per loop in the example sketch) but the underlying code in the Clock.delay function is constantly checking the timer states to see if a timer has matured.  

My suggestion if you have only a single delay going on at one time is to try Mikes approach first. But I will get you the code if you are comfortable modifying your copy of wiring.c

Go Up