|
|
View previous topic :: View next topic |
Author |
Message |
Guest
|
16F876 with 32768 kHz clock hangs up. but why? |
Posted: Sun Jan 15, 2006 2:40 am |
|
|
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
|
|
Posted: Sun Jan 15, 2006 3:13 am |
|
|
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
|
|
Posted: Sun Jan 15, 2006 3:28 am |
|
|
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
|
|
Posted: Sun Jan 15, 2006 7:07 am |
|
|
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
|
|
Posted: Mon Jan 16, 2006 12:55 am |
|
|
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
|
|
Posted: Mon Jan 16, 2006 9:16 am |
|
|
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
|
|
Posted: Tue Jan 17, 2006 11:54 am |
|
|
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
|
|
Posted: Tue Jan 17, 2006 12:27 pm |
|
|
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
|
|
Posted: Tue Jan 17, 2006 1:04 pm |
|
|
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
|
|
Posted: Tue Jan 17, 2006 4:00 pm |
|
|
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
|
|
Posted: Tue Jan 17, 2006 5:04 pm |
|
|
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
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Jan 18, 2006 2:19 am |
|
|
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
|
|
Posted: Thu Jan 19, 2006 5:19 am |
|
|
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 |
|
|
|
|
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
|