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

How to handle strings with state machine ?-Reloaded

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Andrew83



Joined: 16 Sep 2008
Posts: 51

View user's profile Send private message Send e-mail

How to handle strings with state machine ?-Reloaded
PostPosted: Sun Jan 25, 2009 6:16 am     Reply with quote

Hello 2 all !

Fist of all :
- pic18f452
-10MhZ
-CCs C ver. 4.057.

Let's say i have a string like cmd[].
I want to be able to go through this string and if a certain element is "1", make a led sequence like this (output_low for 1ms, output_high for 1ms), or if it's a "0" (output_high for 1ms, output_low for 1ms).

If i use the delay code function, it messes up the code.


Any ideas ?

How can i make this work without using delay ?

Here is my simple test code:

Code:


#include <18f452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

//=======================================

char gc_COMMAND_timer;

char i=0;

char cmd[2]={'1','0'};
//=======================================
#bit TMR0IF = 0xFF2.2
//=======================================

//=======================================

#define COMMAND_TIMER_TICKS             4     // 4 ms

//=======================================
#define RTCC_PRELOAD 246

//=======================================

#int_rtcc
void rtcc_isr(void)
{
// Reload the RTCC, so it will keep overflowing every 10 ms.
set_rtcc(RTCC_PRELOAD);

// Decrement any timers that are running.

if(gc_COMMAND_timer)
   gc_COMMAND_timer--;
 

}

//=============================================================================
void check_COMMAND()
{
if(gc_COMMAND_timer )
   {
   return;
   }
else
 {
   gc_COMMAND_timer  = COMMAND_TIMER_TICKS;
   for(i=0; i<3; i++)
   {
       if (cmd[i]=='0')
       {
       output_low(pin_b0);
       delay_ms(1);
       output_high(pin_b0);
       delay_ms(1);
       }
       else
       {
       output_high(pin_b0);
       delay_ms(1);
       output_low(pin_b0);
       delay_ms(1);
       }
   }
 } 
}

//============================================================================



//=============================================================================
void main()
{

gc_COMMAND_timer = COMMAND_TIMER_TICKS;

// Setup the RTCC.
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256|RTCC_8_BIT);
   set_timer0(RTCC_PRELOAD);


enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);



while(1)
      {
               check_command();
             
     }
}


ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Sun Jan 25, 2009 3:44 pm     Reply with quote

Quote:
If i use the delay code function, it messes up the code.
Can you be more specific and provide an example of what you mean? Now we have no clue as to what we should be looking for.

A few remarks on your code:
Code:
#define COMMAND_TIMER_TICKS             4     // 4 ms

//=======================================
#define RTCC_PRELOAD 246

//=======================================

#int_rtcc
void rtcc_isr(void)
{
// Reload the RTCC, so it will keep overflowing every 10 ms.
set_rtcc(RTCC_PRELOAD);
The COMMAND_TIMER_TICKS is defined as 4ms, but the RTCC interrupt has a resolution of 10ms??? It should be either 1ms RTCC interrupt or 40ms for the COMMAND_TIMER_TICKS.

Code:
#define RTCC_PRELOAD 246
With this setting you are now generating interrupts at a rate of:
(256 - 246) * 4 * 256 prescaler / 10MHz = 1ms

Code:
   for(i=0; i<3; i++)
This loops three times, not two. You are processing the non existing command cmd[2] and total execution takes 6ms which is longer than your 4ms COMMAND_TIMER_TICKS.
Andrew83-guest
Guest







PostPosted: Mon Jan 26, 2009 12:52 am     Reply with quote

Hello ckielstra !

Ok...so:

1.This code that I've posted is the code for a state machine. Basically it's the code for 1 state of the 4 that I have. I'm using a Oshon simulator to verify that the program is working. The delay should be 1 ms but instead it is about 500 uS.
I know that I shouldn't use the delay function in a state machine, but how else can I make the timed sequence work ?

2. The interrupt triggers every 1 ms. The comment is wrong and I apologize for that.
3. You are right also about the for loop. Yes...it is for 3 elements, and I declare only two, so thanks for pointing out this small (but critical) error.
Guest








PostPosted: Mon Jan 26, 2009 12:55 am     Reply with quote

And again ...thank's you 4 your time !

I really need to get this sorted to get things moving in the right dirrection!
Ttelmah
Guest







PostPosted: Mon Jan 26, 2009 3:16 am     Reply with quote

Some further comments:

Could you use a pin that is controllable by the CCP, for the signal you want to pulse?. The CCP, supports modes other than the simple PWM, and one of these allows a pin to be 'set' at a particular count, and another allows the same pin to be cleared at a count. There is a CCP interrupt at the same time. So what you could do, is in the original interrupt, set the pin, and program the CCP to clear it in 1mSec. Then when you get this CCP interrupt, program it to set it in another mSec. This way the hardware will do the pulsing, and you won't need to delay for it.

Second comment, do a search here about using multiple #use delay statements. Basically, though having a delay in the interrupt is 'nasty', it may be the simplest way to do what you want. The big problem it introduces though is that interrupts will then be disabled in the external code, whenever delays are called, which may cause problems. You can avoid this by adding a second #use delay statement. One for the 'interrupt' routines, and one for the main. The compiler then generates separate delay code for the interrupts,and doesn't have to tun off interrupts in the delays in the main.

Doublle check your crystal, and the settings in your simulator. The delay time is dependant on two things. The crystal, and the value in the #use delay statement. Basically, if the crystal was actually 20Mhz, and the delay statement was told it was 10MHz, you would see exactly half the required delay. Most simulators, have their own 'clock' value, that has to be set separately. It sounds as if yours is running at 20MHz.

Best Wishes
Wayne_



Joined: 10 Oct 2007
Posts: 681

View user's profile Send private message

PostPosted: Mon Jan 26, 2009 5:33 am     Reply with quote

The only solution I can think of is to put a state machine in your ISR.
Set your ISR to interrupt ever 1ms (if possible)

Code:

#define COMMAND_TIMER_TICKS             40     // 40 ms
#define MAX_CMD_SIZE 2

char cmd[MAX_CMD_SIZE] = {'1','0'};
int state = 0;
int cmdIndex = 0;

#int_rtcc
void rtcc_isr(void)
{
  // Reload the RTCC, so it will keep overflowing every 1 ms.
  set_rtcc(RTCC_PRELOAD);

  // Decrement any timers that are running.
  if(gc_COMMAND_timer)
    gc_COMMAND_timer--;
  else
  {
    gc_COMMAND_timer  = COMMAND_TIMER_TICKS;
    state = 1;  // start cmd
  }
 
  switch(state)
  {
    case 0:  // do nothing
      break;
    case 1:  // check next cmd
      if (cmdIndex == MAX_CMD_SIZE)
      {
        cmdIndex = 0;
        state = 0;  // Finished
        break;
      }
      if (cmd[cmdIndex] == '0')
      {
         output_low(pin_b0);
         state = 2; // low high
      }
      else if(cmd[cmdIndex] == '1')
      {
         output_high(pin_b0);
         state = 3; // hight low
      }
      cmdIndex++;
      break;
    case 2:
      output_high(pin_b0);
      state = 1:
      break;
    case 3:
      output_low(pin_b0);
      state = 1:
      break;
  }
}


Something like that.

Now your code has some discrepencies,
#define COMMAND_TIMER_TICKS 4 // 4 ms
// Reload the RTCC, so it will keep overflowing every 10 ms.

If the interrupt triggers every 10ms then your COMMAND_TIMER_TICKS will be a 40ms tick!

You say this is a statemachine but you don't actually show one!

Hope this helps. There may be issues with doing it this way I hope which others will point out. Smile

Some explination,
The interrupt fires every 1ms.
After 40 40ms, start the cmd
If 0, set low then next tick high
if 1 set high then next tick low
next tick, next command
Andrew83



Joined: 16 Sep 2008
Posts: 51

View user's profile Send private message Send e-mail

PostPosted: Mon Jan 26, 2009 1:17 pm     Reply with quote

Hello !

Thank you for your quick answers ! Smile

Concerning Ttelmah's post i must make the following clarifications:

Your idea about using a PWM controlled pin to achieve the behavior i was looking for is very appealing. I will try this as soon as possible and get back to you with my results.
Another thing .... you said in your post :
Quote:

Second comment, do a search here about using multiple #use delay statements.

I was faced with this kind of problem in another software, when interrupts where disabled because of a reentrancy problem caused by the use of delay function in an interrupt.
I've already tried to use multiple #use delay statements (as is mentioned in the FAQ of the compiler) but did not get the desired result until i've set a few flags in the isr and did the delay function in the main.

Can you please provide me with a thread where this problem was raised by someone else ? I'm sorry to ask you this but by searching this forum i've not been able to find any relevant threads.

Concerning Wayne_'s post :

Thank you 4 your interest. I will try your implementation. I kind'a makes sense....but...i'm sure there will be issues using a state machine inside a state machine. Anyway, i'll give it a try and let you know as soon as possible about the result!

Thank you everyone !
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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