CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Simultaneous control of delay operated LEDs
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
TokTok



Joined: 22 Jan 2014
Posts: 35

View user's profile Send private message

Simultaneous control of delay operated LEDs
PostPosted: Fri Apr 25, 2014 9:45 am     Reply with quote

Hi all,
Apologies if this sound trivial but currently I’m stuck in terms of figuring out the logic to complete what I suspect is a fairly easy task.

I’m currently turning on my LEDs for a certain amount of time using the output_toggle() method as seen in my code at the end of my post but I’d like to move on to turning on another relay when I’ve got the first LED currently engaged. So essentially simultaneous operation of the LEDs is what I’m after.

How does one go about this in an efficient way?

I’m running the code on my PIC18F2580 PIC MCU and as I mentioned it runs fine but I would like to engage the LED simultaneously not sequentially.

Note: As I come from a java background is there any threading within the CCS library?

Any help is appreciated.

TokTok


Code:

#include<18F2580.h>

#include <stdlib.h>
#include <string.h>

#fuses XT,PUT,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP
 
#use delay(clock=4000000)
#use rs232(baud=19200, parity=N, xmit=PIN_C6, rcv=PIN_C7, STREAM=HWAREUART, ERRORS)
#use rs232(baud=19200, parity=N, xmit=PIN_A4, Stream=PCSOFTWAREUART)

#define REL_1 PIN_A1
#define REL_2 PIN_A2
#define REL_3 PIN_B0
#define REL_4 PIN_B1
#define REL_5 PIN_A5

//
void main() {
   output_low(REL_1);
   output_low(REL_2);
   output_low(REL_3);
   output_low(REL_4);   
   output_low(REL_5);

while(1) {
   int num, i;

   for(i=0; i<5; i++) {

       num = i;
   
      if(num == 1) {
         output_toggle(REL_1);
         delay_ms(10000);
         output_toggle(REL_1);
      } else if(num == 2) {
         output_toggle(REL_2);
      } else if(num == 3) {
         output_toggle(REL_3);
         delay_ms(5000);
         output_toggle(REL_3);
      } else if(num == 4) {
         output_toggle(REL_4);
      }  else if(num == 5) {
         output_toggle(REL_5);
         delay_ms(2500);
         output_toggle(REL_5);
      }
   }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Apr 25, 2014 10:08 am     Reply with quote

Do a search for these two words and you'll find sample code
which shows how to do it:
Quote:
multi-tasking

multitasking

http://www.ccsinfo.com/forum/search.php
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Fri Apr 25, 2014 11:00 am     Reply with quote

since you are using A6,A7 for the oscillator -

bit mapping your led on/off commands into a shadow BYTE
for port A would do what you want in a very clean way
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Sat Apr 26, 2014 1:59 am     Reply with quote

This is not quite the same as true multi-tasking, but may do what you want.

Set up one of the timers to give (say) a 1ms tick.
Use the tick to trigger an ISR.
Set up a tick_counter for each of your tasks.
In the ISR, decrement all the tick_counters.

In main() you simply poll each tick_counter in turn, and do the necessary.

OR

You can increment counters. Whichever you are most comfortable with.
I prefer to set tick_counters to a value for the delay needed, and watch for reaching zero.
In the ISR I also prevent the tick_counters going below zero.

Mike
TokTok



Joined: 22 Jan 2014
Posts: 35

View user's profile Send private message

Simultaneous control of delay operated LEDs
PostPosted: Mon Apr 28, 2014 4:29 am     Reply with quote

Hi all,
Following the advice from Mike Walne plus the sample code in the CCS C compiler manual the code below is my first attempt to enable the multiple operation of relays using a timer and its interrupt.

Apologies if the below approach sounds silly but I’m learning about interrupts as I try to use them to provide a solution to my task.

Code:

#include<18F2580.h>

#include <stdlib.h>
#include <string.h>

#fuses XT,PUT,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP
 
#use delay(clock=4000000)
#use rs232(baud=19200, parity=N, xmit=PIN_C6, rcv=PIN_C7, STREAM=HWAREUART, ERRORS)
#use rs232(baud=19200, parity=N, xmit=PIN_A4, Stream=PCSOFTWAREUART)

#define REL_1 PIN_B2
#define REL_2 PIN_B3
#define REL_3 PIN_A3
#define REL_4 PIN_B2
#define REL_5 PIN_B3

int LED_flag;

#INT_TIMER1
void LED_timer() {
      if(LED_flag == 1) {
         output_toggle(REL_1);
         set_timer1(0xFC4F);
         output_toggle(REL_1);
      } else if(LED_flag == 2) {
         output_toggle(REL_2);
      } else if(LED_flag == 3) {
         output_toggle(REL_3);
         set_timer1(0xFC4F);
         output_toggle(REL_3); 
      } else if(LED_flag == 4) {
         output_toggle(REL_4);
      }  else if(LED_flag == 5) {
         output_toggle(REL_5);
         set_timer1(0xFC4F);
         output_toggle(REL_5);
      }
}

void main() {
    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
    enable_interrupts(INT_TIMER1);
    enable_interrupts(GLOBAL);   

   output_low(REL_1);
   output_low(REL_2);   
   output_low(REL_3);
   output_low(REL_4);   
   output_low(REL_5);

   LED_flag = 1;

   LED_flag = 2;
   
   LED_flag = 3;

   LED_flag = 4;

   LED_flag = 5;
}


The code builds successfully but doesn’t work as I think it should.

Any suggestions/corrections regarding where I’m going wrong with my approach.

As I mentioned I’m also trying to grasp the use of timer interrupts (I’ve utilised the serial interrupt successfully on past occasions hence I’ve got a good idea on how the interrupt concept works).

Thanks for any help.
Ttelmah



Joined: 11 Mar 2010
Posts: 19350

View user's profile Send private message

PostPosted: Mon Apr 28, 2014 5:04 am     Reply with quote

OK.

First problem is speed. Your timer is counting in single machine instructions. Loading with FC4F, means it'll trigger next just 945 instructions later (counter counts _up_ and interrupt fires when it wraps from FFFF to 0000. 945 instructions is just under 1mSec. You are not going to see much....

Then your four instructions selecting the different things to do, are all executed before the timer triggers even once. So LED+flag gets to 5, before the timer gets called...
You need to have each change wait till the interrupt is triggered.

Then the code 'drops off the end'. Classic problem here. Remember _your code is the only thing running_. When writing code on a PC, you are running 'inside' an operating system. When the code drops off the end, you go back to running the OS. On the PIC, there is nothing else in the chip, and when the code runs off the end, everything stops (the chip goes to sleep).

Then in a couple of your states, you toggle the output twice. You are probably never going to see this. Just a couple of uSec apart....
If you mean these to be separated by 1mSec, then they need to become new states.

Best Wishes
TokTok



Joined: 22 Jan 2014
Posts: 35

View user's profile Send private message

PostPosted: Mon Apr 28, 2014 8:49 am     Reply with quote

Hi Ttelmah,

Thanks for the reply.

I don't fully get the following bit of your suggestion below:


Then your four instructions selecting the different things to do, are all executed before the timer triggers even once. So LED+flag gets to 5, before the timer gets called...
You need to have each change wait till the interrupt is triggered.


From my code below when LED_flag == 1, how should I look to set my delay in the ISR i.e. using set_timer() to toggle REL_1 and REL_2 assuming the delay between setting the value of LED_flag in the infinite while loop in the main varies.

Code:

#include<18F2580.h>

#include <stdlib.h>
#include <string.h>

#fuses XT,PUT,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP
 
#use delay(clock=4000000)
#use rs232(baud=19200, parity=N, xmit=PIN_C6, rcv=PIN_C7, STREAM=HWAREUART, ERRORS)
#use rs232(baud=19200, parity=N, xmit=PIN_A4, Stream=PCSOFTWAREUART)

#define REL_1 PIN_B2
#define REL_2 PIN_B3
#define REL_3 PIN_A3
#define REL_4 PIN_B2
#define REL_5 PIN_B3

int LED_flag;

#INT_TIMER1
void LED_timer() {
      if(LED_flag == 1) {
         output_toggle(REL_1);
         set_timer1(81);
         output_toggle(REL_1);
      } else if(LED_flag == 2) {
         output_toggle(REL_2);
      }
}

void main() {
    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
    enable_interrupts(INT_TIMER1);
    enable_interrupts(GLOBAL);   

    output_low(REL_1);
    output_low(REL_2);   
    output_low(REL_3);
    output_low(REL_4);   
    output_low(REL_5);
   
   while(1) {
       LED_flag = 1;
      delay_ms(2000);
       LED_flag = 2; 
   }
}


As for your advice regarding the classic error I made this is noted and I've applied an infinite while loop so the code won't fall of at the end.

Thanks.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Tue Apr 29, 2014 2:33 am     Reply with quote

The following code flashes two LEDs at slightly different rates.
They start off in step, slowly go out of step then back in step after ~2 minutes.
I've used a '458 and 16MHz because that's what happens to be plugged into my PICDEM2 board.
The PIC is a close relative of the one you're using, so should not be a problem.
Code:
#include <18F458.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=16000000)

signed int16   rb0_led_timer;            //
signed int16   rb1_led_timer;

#int_timer2
void update_timers()
{
   rb0_led_timer--;
   rb1_led_timer--;
   if (rb0_led_timer<0) { rb0_led_timer = 0;}
   if (rb1_led_timer<0) { rb1_led_timer = 0;}
}

void main()
{
   setup_timer_2(T2_DIV_BY_16, 249, 1);          // Generates 1ms tick
   enable_interrupts(int_timer2);
   enable_interrupts(global);

   rb0_led_timer = rb1_led_timer = 0;          // clears timers
   output_low(pin_b0);                         // forces defined state
   output_low(pin_b1);                         //   "

   while( TRUE )
   {
      if (rb0_led_timer==0)                     // Tests for time out
      {
         rb0_led_timer = 250;                   // Restarts timer
         output_toggle (pin_b0);                // Flashes LED
      }
     
      if (rb1_led_timer==0)                     // Tests for time out
      {
         rb1_led_timer = 251;                   // Restarts timer
         output_toggle (pin_b1);                // Flashes LED
      }
   }
}

Mike
Jerson



Joined: 31 Jul 2009
Posts: 122
Location: Bombay, India

View user's profile Send private message Visit poster's website

PostPosted: Tue Apr 29, 2014 6:17 am     Reply with quote

I prefer to write it this way.

Code:
#int_timer2
void update_timers()
{
   if (rb0_led_timer>0)  rb0_led_timer--;

   if (rb1_led_timer>0)  rb1_led_timer--;
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19350

View user's profile Send private message

PostPosted: Tue Apr 29, 2014 7:24 am     Reply with quote

Yes, and it is also slightly more code efficient. Forcing sign to be used, is a little extra work....
TokTok



Joined: 22 Jan 2014
Posts: 35

View user's profile Send private message

PostPosted: Tue Apr 29, 2014 8:26 am     Reply with quote

Hi All,

@Mike Walne:

Thanks for the reply. I really appreciate the code.

There's just one bit I need to clearly understand is the 249 setup_timer_2(T2_DIV_BY_16, 249, 1);

Based on the CCS C compiler manual, 249 is an int 0-255 that determines when the clock value is reset hence the first time it counts does it count from 249 to 255?

Note: I played around with the 249 and the smaler the values the faster the flashes and vice versa.

Apologies if my reasoning sounds basic.

I get more clearly the other two arguments i.e. T2_DIV_BY_16 being the prescaler and 1 - the postscaler.



Thanks.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Tue Apr 29, 2014 2:31 pm     Reply with quote

This is microchip's version of how PR2 affects Timer2.

The Timer2 module has an 8-bit period register, PR2.
Timer2 increments from 00h until it matches PR2 and
then resets to 00h on the next increment cycle. PR2 is
a readable and writable register. The PR2 register is
initialized to FFh upon RESET.


So in my case Timer2 counts from 0 to 249 then resets.
That's a total count between resets of 249 + 1 i.e. 250.

The second parameter in the CCS set_up_timer2 goes into the PR2 register

To completely understand what's going on you need to read the microchip manual as well as the CCS one.

Mike
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Tue Apr 29, 2014 2:34 pm     Reply with quote

Jerson wrote:
I prefer to write it this way.

Code:
#int_timer2
void update_timers()
{
   if (rb0_led_timer>0)  rb0_led_timer--;

   if (rb1_led_timer>0)  rb1_led_timer--;
}

Yes, I agree it's better.

Mike
Ttelmah



Joined: 11 Mar 2010
Posts: 19350

View user's profile Send private message

PostPosted: Tue Apr 29, 2014 2:48 pm     Reply with quote

The 249 value loads 'PR2' (a register in the PIC). Timer2, counts from 0 to PR2 (so gives PR2+1 counts). It is the only timer in the normal PIC's that has the ability to automatically reset 'at' a count.
TokTok



Joined: 22 Jan 2014
Posts: 35

View user's profile Send private message

PostPosted: Thu May 01, 2014 5:12 am     Reply with quote

Hi Mike and all,

Having read the PIC 18F2580 data sheet and the CCS C manual regarding the TIMER 2, I still cant seem how to piece together how the three arguments that go into the setup_timer_2(); method affect the counting.

Essentially below is what I would like to achieve specifically as per my comments:

Code:

#include<18F2580.h>

#include <stdlib.h>
#include <string.h>

#fuses XT,PUT,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP
 
#use delay(clock=4000000)
#use rs232(baud=19200, parity=N, xmit=PIN_C6, rcv=PIN_C7, STREAM=HWAREUART, ERRORS)

#define LED_ONE PIN_B2
#define LED_TWO PIN_B3

#define PUSH_BTN_ONE PIN_B4
#define PUSH_BTN_TWO PIN_A3

int push_btn_flag;

#int_timer2
void toggle_LED() {
   if(push_btn_flag == 1) {

      // At this point in time in the interrupt service routineI would like to count down or up for 5 seconds in here so as to turn off LED_ONE after 5 seconds

      output_toggle(LED_ONE);

      push_btn_flag = 0;
   } else if(push_btn_flag == 2) {

      // At this point in time in the interrupt service routine I would like to count down or up for 10 seconds in here so as to turn off LED_ONE after 10 seconds
      output_toggle(LED_TWO);

      push_btn_flag = 0;
   }
}

void main() {

   // ???? - Based on needing to count down for varying times dependent on which push button is engaged what do I need to set my prescaler, mode and postcaler parameters to be or do I need to use a different timer may be timer 1
   //setup_timer_2(?, ?, ?);
   enable_interrupts(int_timer2);
   enable_interrupts(global);

   output_low(LED_ONE);
   output_low(LED_TWO);

   // Here I essentially want to enable the user to play around with operating the LEDs SIMULTANEOUSLY
   // So user say user presses PUSH_BTN_ONE essentially I want it that the push_btn_flag changes and
   // this causes the timer interrupt to start counting down or up based on a specified time i.e. 5 secs

   // Now in the interrupt service routine whilst the counting related to LED one is ongoing if the user were
   // to press PUSH_BTN_TWO then I would like in the interrupt service rountine the counting for LED_TWO
   // to be started as the push_btn_flag would have been set to two.
   
   while(TRUE) {

      if(PUSH_BTN_ONE == 0) {
         delay_ms(10);

         output_toggle(LED_ONE);

         push_btn_flag = 1;
      } else if (PUSH_BTN_TWO == 0) {
         delay_ms(10);

         output_toggle(LED_TWO);

         push_btn_flag = 2;
      }

   }
}


Thanks.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group