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

16F876 with 32768 kHz clock hangs up. but why?

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








16F876 with 32768 kHz clock hangs up. but why?
PostPosted: Sun Jan 15, 2006 2:40 am     Reply with quote

Hello to all,

I'm using an 16F876 with 32768 kHz clock which hangs up after reaching the command 'enable_interrupts(GLOBAL)'
I searched here in the forum for this problem, but I can't find any solutions.

Code:

#include <16f876.h>
#define clockspeed 32768
#use delay(clock=clockspeed)
#use RS232(baud=300, xmit=PIN_C6, rcv=PIN_C7)
#fuses LP,NOWDT,NOBROWNOUT,PUT,NOLVP,NODEBUG,NOPROTECT
#zero_ram

...some other stuff deleted...

void main (void)
{
  setup_timer_2(T2_DIV_BY_1,8,1);  // for having approx. 1ms tick
  enable_interrupts(INT_TIMER2);
  output_high(PIN_B0);  // This LED went on
  enable_interrupts(GLOBAL);
  output_high(PIN_B1);  // This LED stay out, but WHY ??

...some other stuff deleted...

}



With another crystal such as 4 MHz it's no problem.
Is there anybody who can help me? Please!!

Thanks for your assistance
Sven
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jan 15, 2006 3:13 am     Reply with quote

1. Do you have an interrupt service routine defined ?

2. Do you have a continuous loop defined somewhere, to prevent
your code from falling off the end of main() ?

3. Are you testing the exact same code with a 4 Mhz crystal
and with 32.786 KHz ? (Except for the "clockspeed" value)
wedilo



Joined: 16 Sep 2003
Posts: 71
Location: Moers, Germany

View user's profile Send private message

PostPosted: Sun Jan 15, 2006 3:28 am     Reply with quote

Dear PCM programmer,

Thanks for your quick reply.
Yes, it still works with 4 MHz and higher.
I only have to adapt as follows:

Clockspeed 4000000
#fuses HS, ...

In the main:
setup_timer_2(T2_DIV_BY_4,(clockspeed/80000),5);

All the code is from Mark. It's his wonderful 'button handling' code.
I modified it for my application, but it doesn't have something to do with this problem, I'm sure.

When I change it to 4MHz, the code works very well, but when I use the 32768kHz crystal then it hangs up. Unbelievable. I don't understand why it stops after the "enable_interrupts(GLOBAL);"

My compiler version is v3.209.

Sven
Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

PostPosted: Sun Jan 15, 2006 7:07 am     Reply with quote

For testing purposes only, try to disable timer2 and watch if the PIC doesn't hang.

Keep well,

Humberto
wedilo



Joined: 16 Sep 2003
Posts: 71
Location: Moers, Germany

View user's profile Send private message

PostPosted: Mon Jan 16, 2006 12:55 am     Reply with quote

Hi,

Thanks for help, I will try it out.

Is there any special to know for using 32768 kHz crystal?
It looks so different to the others. It's not the usual form, it's round.

Please help.
Sven
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

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

PostPosted: Mon Jan 16, 2006 9:16 am     Reply with quote

I think that value is most often used in clock cuircuits.
Are you using the suggested cap values?
wedilo



Joined: 16 Sep 2003
Posts: 71
Location: Moers, Germany

View user's profile Send private message

PostPosted: Tue Jan 17, 2006 11:54 am     Reply with quote

Hi,

Yes, I use 39pF each as C4 and C5 on PicDem2, that should be ok.

Best regards
Sven
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jan 17, 2006 12:27 pm     Reply with quote

Post a small (but complete) program that shows the problem.
If you post the program, then we can likely solve it.
wedilo



Joined: 16 Sep 2003
Posts: 71
Location: Moers, Germany

View user's profile Send private message

PostPosted: Tue Jan 17, 2006 1:04 pm     Reply with quote

Dear friends,

OK, I will post the complete program, but first one other thing.
When I have a look to the clock signal with a scope then the 4.0 MHz crystal has a nice sine form. The 32768 kHz crystal has a rectangle form but with very rounded edges. Could this be correct?

Code:

#include <16f876.h>
#device ADC=10 ICD=True
#include <string.h>
//#define clockspeed 4000000
#define clockspeed 32768
#use delay(clock=clockspeed)
#use RS232(baud=300, xmit=PIN_C6, rcv=PIN_C7)
//#fuses HS,NOWDT,NOBROWNOUT,PUT,NOLVP,NODEBUG,NOPROTECT
#fuses LP,NOWDT,NOBROWNOUT,PUT,NOLVP,NODEBUG,NOPROTECT
#zero_ram

#define CLICK_TIME 250       // Maximum time to consider a press/release a click
#define DBL_CLICK_TIME 500   // Time to wait for a dbl_click in ms
#define SWITCH_READ_TIME 30  // Interval to read the switches in ms

// Search for TO ADD MORE SWITCHES to find out where the code needs to be changed
#define NUM_SWITCHES 2  // Good for up to 8 switches without
                        // having to modify the variable types

// Different types of click events
enum SWITCH_STATES
{
  SWITCH_IDLE,
  SWITCH_DOWN,
  SWITCH_HELD,
  SINGLE_CLICK,
  DOUBLE_CLICK
};

// Our system timer
int8 Milliseconds;

// How often we read the switch inputs
int8 Read_Switch_Timer = 0;

// Signal to read the switches
int1 Read_Switch_Flag = FALSE;

// Timeout value or in this case the double click time
int16 Click_Timer[NUM_SWITCHES];

// Counter for checking the order of pressing buttons
int8 nInputOrder;

// Counter for accepting code pattern
int16 lCodeAcceptedLedCounter;

// Flag, if guarding should active or not
boolean bgGuarding;

// Flag, if output via COM
boolean bgCommunication = False;

enum SWITCH_STATES Switch_State[NUM_SWITCHES];

// Timer 2 is our system tick
#int_timer2
void timer2_isr(void)
{
  lCodeAcceptedLedCounter++;
  if (Milliseconds < 0xFF)
    Milliseconds++;
}

// Handles what happens when we release a switch
void Switch_Released(int8 number)
{
  // Make sure this is a valid switch
  if (number < NUM_SWITCHES)
  {
    switch (Switch_State[number])
    {
      case SWITCH_DOWN:
        // Set the timer to the maximum time between a press and release to consider this a single click
        Click_Timer[number] = CLICK_TIME;
        Switch_State[number] = SINGLE_CLICK;
        break;
      case SWITCH_HELD:
        // Just set the timer to a small number so that it will fire as soon as we release the switch
        Click_Timer[number] = 1;
        // Don't change the state here, the timers will take care of it
        break;
      case SINGLE_CLICK:
        // Set the timer for the maximum time we will wait for a double click
        Click_Timer[number] = DBL_CLICK_TIME;
        Switch_State[number] = DOUBLE_CLICK;
        break;
      case DOUBLE_CLICK:
        // The user is just clicking away at the button.  We won't really do until he stops or we could
        // cancel the operation by setting the state to idle and the timer to 0
        Click_Timer[number] = DBL_CLICK_TIME;
        Switch_State[number] = DOUBLE_CLICK;
        break;
      default:
        Click_Timer[number] = 0;
        Switch_State[number] = SWITCH_IDLE;
        break;
    }
  }
}

// Handles what happens when we press a switch
void Switch_Pressed(int8 number)
{
  // Make sure this is a valid switch
  if (number < NUM_SWITCHES)
  {
    // Set the state to down only if we haven't just processed a click
    if (Switch_State[number] == SWITCH_IDLE)
      Switch_State[number] = SWITCH_DOWN;
    Click_Timer[number] = DBL_CLICK_TIME;
  }
}

// Handles debouncing of the switches
void Switch_Read_Value(void)
{
  static int8 last_read = 0xFF;
  static int8 last_state = 0xFF;
  static int8 debounce_count;
  int8 result = 0xFF;
  int8 i;
  int8 changed;

  // "ADD SWITCH" you need to put them into result

  // Read the current result
  if (!input(PIN_A4))
    bit_clear(result,0);

  if (!input(PIN_B0))
    bit_clear(result,1);

  // See if it changed
  if (result != last_read)
  {
    // It did so debounce it
    debounce_count = 5;
    last_read = result;
  }
  // We are debouncing
  else if (debounce_count)
  {
    debounce_count--;
    // Done debouncing
    if (debounce_count == 0)
    {
      // See if the state of the switch has changed
      changed = (result ^ last_state);
      // Determine what type of event occurred
      for(i=0;i<8;i++)
      {
        if (bit_test(changed,i))
        {
          if (bit_test(result,i))
            Switch_Released(i);
          else
            Switch_Pressed(i);
        }
        // Save the current state
        last_state = result;
      }
    }
  }
}

// What we do if a switch was pressed longer than the click time
void Switch_Pressed_Event(int8 number)
{
  // "ADD SWITCH" you need to add the cases
  switch(number)
  {
    case 0:
      // SW1 gedrückt
      if (bgCommunication == true) printf("2. Event\n\r");
      // Counter increment if order ok else reset
      // 2. Event
      if (nInputOrder == 1)
        nInputOrder++;
      else
        nInputOrder = 0;

      break;
   case 1:
      // SW2 gedrückt
//      output_high(PIN_B2);
      if (bgGuarding == True)
      {
        if (bgCommunication == true) printf("Opened with ALARM !!!\n\r");
        output_low(PIN_C2);
      }
      else
      {
        if (bgCommunication == true) printf("Opened\n\r");
      }
     break;
   default:
     break;
  }
}

// What we do if a switch was pressed and held longer than the click time
// and then released
void Switch_Release_Event(int8 number)
{
  int8 i;

  // "ADD SWITCH" you need to add the cases
  switch(number)
  {
    case 0:

      // Turn off the LED on RB3 of the picdem2 plus board
//      output_low(PIN_B3);
//      printf("\fSW1 Released");
      break;
   case 1:
      // Turn off the LED on RB2 of the picdem2 plus board
//      output_low(PIN_B2);
//      printf("\fSW2 Released");
      bgGuarding = True;
      if (bgCommunication == true) printf("Closed, Guarding active !!\n\r");

      for(i=0;i<3;i++)
      {
         lCodeAcceptedLedCounter = 0;
         output_high(PIN_B3);
         while(lCodeAcceptedLedCounter < 25)
         {
         }
         lCodeAcceptedLedCounter = 0;
         output_low(PIN_B3);
         while(lCodeAcceptedLedCounter < 250)
         {
         }
      }

      output_high(PIN_C2);
     break;
   default:
     break;
  }
}

// What we do on a single click
void Single_Click_Event(int8 number)
{
  // "ADD SWITCH" you need to add the cases
  switch(number)
  {
    case 0:
      // Light an LED on RB3 of the picdem2 plus board
//      output_high(PIN_B3);
      if (Switch_State[1] == SWITCH_HELD)
      {
//        printf("\fSW1 Click\nWhile SW2 Held");
      if (bgCommunication == true) printf("3. Event\n\r");
      }
      else
      {
//        printf("\fSW1 Click");
        if (bgCommunication == true) printf("3. Event\n\r");

        // Counter increment if order ok else reset
        // 3. Event
        if (nInputOrder == 2)
          nInputOrder++;
        else
         nInputOrder = 0;
       }

      break;
   case 1:
      // Light an LED on RB2 of the picdem2 plus board
//      output_high(PIN_B2);
      if (Switch_State[0] == SWITCH_HELD)
      {
        if (bgCommunication == true) printf("\fSW2 Click\nWhile SW1 Held");
      }     
      else
      {     
         if (bgCommunication == true) printf("\fSW2 Click");
      }
     break;
   default:
     break;
  }
}

// What we do for a dbl_click
void Double_Click_Event(int8 number)
{
  // "ADD SWITCH" you need to add the cases
  switch(number)
  {
    case 0:
      // Turn off the LED on RB3 of the picdem2 plus board
//      output_low(PIN_B3);
      if (Switch_State[1] == SWITCH_HELD)
      {
//        printf("\fSW1 Dbl_Click\nWhile SW2 Held");
        if (bgCommunication == true) printf("1. Event\n\r");
      }
      else
      {
//        printf("\fSW1 Dbl_Click");
        if (bgCommunication == true) printf("1. Event\n\r");
      // Counter increment if order ok else reset
      // 1. Event
      if (nInputOrder == 0)
        nInputOrder++;
      else
        nInputOrder = 0;
      }
      break;
   case 1:
      // Turn off the LED on RB2 of the picdem2 plus board
//      output_low(PIN_B2);
      if (Switch_State[0] == SWITCH_HELD)
      {
         if (bgCommunication == true) printf("\fSW2 Dbl_Click\nWhile SW1 Held");
      }
      else
      {     
         if (bgCommunication == true) printf("\fSW2 Dbl_Click");
      }

     break;
   default:
     break;
  }
}

// Handles all our switch timers
void Switch_Timers(void)
{
  int8 i;

  if (Read_Switch_Timer == 0)
    Read_Switch_Timer--;
  else
    Read_Switch_Flag = TRUE;

  for(i=0;i<NUM_SWITCHES;i++)
  {
    if (Click_Timer[i])
    {
      Click_Timer[i]--;
      if (Click_Timer[i] == 0)
      {
        switch (Switch_State[i])
        {
          case SWITCH_DOWN:
            Switch_Pressed_Event(i);
            Switch_State[i] = SWITCH_HELD;
            break;
          case SWITCH_HELD:
            Switch_Release_Event(i);
            Switch_State[i] = SWITCH_IDLE;
            break;
          case SINGLE_CLICK:
            Single_Click_Event(i);
            Switch_State[i] = SWITCH_IDLE;
            break;
          case DOUBLE_CLICK:
            Double_Click_Event(i);
            Switch_State[i] = SWITCH_IDLE;
            break;
          default:
            Switch_State[i] = SWITCH_IDLE;
            break;
        }
      }
    }
  }
}

// Handles all our switch tasks
void Switch_Tasks(void)
{
  if (Read_Switch_Flag)
  {
    Switch_Read_Value();
    Read_Switch_Timer = SWITCH_READ_TIME;
    Read_Switch_Flag = FALSE;
  }
}

// System counter
void System_Tick(void)
{
  while (Milliseconds)
  {
    Switch_Timers();
    Milliseconds--;
  }
}



void main (void)
{
  int8 i;

  for(i=0;i<NUM_SWITCHES;i++)
  {
    Click_Timer[i] = 0;
    Switch_State[i] = SWITCH_IDLE;
  }
  // Setup timer2 to int every 1ms
  // Note this is good for a clock between 80K - 20MHz
  // Although some frequencies that do not divide equally
  // by 80K will be slightly off.  You might want to verify this

//  setup_timer_2(T2_DIV_BY_4,(clockspeed/80000),5);
  // for 32768 kHz clock
  setup_timer_2(T2_DIV_BY_1,8,1);
  enable_interrupts(INT_TIMER2);
  enable_interrupts(GLOBAL);

  output_high(PIN_B0);   // test for seeing when hangs up only

  // Start counting now
  Milliseconds = 0;
  nInputOrder = 0;
  if (bgCommunication == true) putc(12);

  output_high(PIN_B1);  // test for seeing when hangs up only

   for(i=0;i<5;i++)
   {
      lCodeAcceptedLedCounter = 0;
      output_high(PIN_B3);
      while(lCodeAcceptedLedCounter < 25)
      {
      }
      lCodeAcceptedLedCounter = 0;
      output_low(PIN_B3);
      while(lCodeAcceptedLedCounter < 250)
      {
      }
   }

  output_high(PIN_B2);  // test for seeing when hangs up only

  while(1)
  {
    System_Tick();
    Switch_Tasks();

    if (nInputOrder == 3 && bgGuarding == True)
    {
      bgGuarding = False;
      if (bgCommunication == true) printf("Code ok, guarding switched off.\n\r");
      nInputOrder = 0;
      lCodeAcceptedLedCounter = 0;
      output_high(PIN_B3);
      while(lCodeAcceptedLedCounter < 500)
      {
      }
      output_low(PIN_B3);
//       putc(12);
    }
  }
}



It is nearly the brilliant code from a Mark? who posted it some time ago.
It works fantastic with 4 MHz or 20 MHz, but not with the 32768kHz.

Please help

Best regards
Sven
ckielstra



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

View user's profile Send private message

PostPosted: Tue Jan 17, 2006 4:00 pm     Reply with quote

Sorry, I'm going to tease you a bit. Scanning this thread I think the error is obvious.

Humberto wrote:
For testing purposes only, try to disable timer2 and watch if the PIC doesn't hang.
You haven't tried this, have you?

Code:
  setup_timer_2(T2_DIV_BY_1,8,1);
This will interrupt every millisecond. How many instructions can you execute in 1ms when running at 32768Hz?......

How many instructions overhead are there in executing a PIC18 interrupt?....
gs



Joined: 22 Aug 2005
Posts: 30
Location: Ioannina - Greece

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

PostPosted: Tue Jan 17, 2006 5:04 pm     Reply with quote

I don't have the expierience to give you a solution, but I see something strange.

In your topic title, and your text, you say about 32768 kHz clock. OK this is 32Mhz
In your code you posted you write:

#define clockspeed 32768

This defines the clock to 32Khz not Mhz.


What is your osc frequency? Have you missed some commas.......?



PS I'm sorry if I say something you think obvious
_________________
www.hlektronika.gr
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

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

PostPosted: Tue Jan 17, 2006 5:30 pm     Reply with quote

That 32768 is just to strange. I figured he was talking about
32.768K Hz which is a standard clock/timing crystal.
http://www.digikey.com/scripts/DkSearch/dksus.dll?Detail?Ref=62113&Row=3605&Site=US

Have you tried what ckielstra and others have asked of you. Disableing the timer 2 IRQ.
ckielstra



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

View user's profile Send private message

PostPosted: Wed Jan 18, 2006 2:19 am     Reply with quote

About the 32kHz or 32MHz discussion:
Wedilo is using a 32768Hz clock, not kHz. Although he is very consistent in writing kHz you can tell it must be Hz for the following reasons:
- He defined clockspeed as 32768 in his code, not 32768000
- He changed the crystal fuse from HS to LS, a requirement for slow crystals.
- No PIC whatsoever will run with a crystal of 32MHz, the maximum crystal frequency for any PIC I've seen is 25MHz. Higher clock speeds are derived from slower crystals in combination with the 4xPLL driver (for example, the 40MHz clock uses a 10MHz crystal and the 4xPLL driver).
- The configuration of timer2 is consistent with 32768Hz

Now for the people who didn't understand my playfull mood of yesterday evening (sorry, it was the end of a long day):
Quote:
How many instructions can you execute in 1ms when running at 32768Hz?......
Only 8 instructions.
Quote:
How many instructions overhead are there in executing a PIC18 interrupt?....
The interrupt overhead for saving and restoring registers is about 60 instructions.

Conclusion:
At the end of the interrupt handler the Timer2 will have fired again and this new interrupt will be processed. The processor is extremely busy processing the interrupts and has no time to perform other tasks, it appears to be hanging.

Solution:
Change the timer2 setup so it will trigger the interrupt less frequently.
You don't want to spend more than 10% of the processor time in the interrupt functions. With this interrupt function including overhead taking about 100 instructions. I recommend changing the timer to 100ms periods or larger.
wedilo



Joined: 16 Sep 2003
Posts: 71
Location: Moers, Germany

View user's profile Send private message

PostPosted: Thu Jan 19, 2006 5:19 am     Reply with quote

Dear friends,

Thank you very very much for spending so much of your time in my problem.

Yes, Ckielstra is right, I use a 32768 Hz (32,768kHz) crystal for having much lower power consumption.
I will use it with two AA batteries in serial way (+3V)

I'm annoyed about this obviously mistake, that I did not realized, that the clock is now so much lower. I will try to change the timing.

Thanks to all especially to Ckielstra for your fine help !!
Sven
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