View previous topic :: View next topic |
Author |
Message |
dan king
Joined: 22 Sep 2003 Posts: 119
|
delay_ms affects timer2 operation? |
Posted: Wed Jun 22, 2005 8:45 am |
|
|
I have run into this several times but usually found a way around the issue. The following code is essentailly written to wait for a pulse and then run timer2 for ~40 mS and count how many pulses occur in that time frame. At the end report the count if > a set value. I would like to wait ~50 mS before executing the routine again so I added a delay_ms but when I add this line, the timer2 operation fails to run for the expected duration. Is this a known issue and is there a fix for this?
CCS PCM C Compiler, Version 3.130, 17162
Code: |
#include <16f877.h>
#use delay(clock=4000000)
#fuses HS,NOWDT,PUT
#use standard_io(B)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,errors)
//
//
const char Build_Date[] = __DATE__;
const char Build_Time[] = __TIME__;
////////////////////////////////////////////////////
// Constants and variables
#byte PORTB = 6
#byte PORTC = 7
#byte PORTD = 8
#bit test = PORTC.3
#bit input = PORTD.0
//variable for lcd driver
#define WORD unsigned long // Data type definitions
//general code variables
int1 Read_Switch_Flag = False;
int duration=1; //
int count=0;
int trigger_count = 10;
//int time;
///////////////////////////////////////////////////////
// General prototypes //
// local prototypes
void send_build();
WORD getnum(void);
///////////////////////////////////////////////////
// TIMER2 ISR
#int_TIMER2
void timer_isr(){
test = 0;
Read_Switch_Flag = FALSE;
set_timer2(duration);
}
/////////////////////////////////////////////////////
///////////////////////////////////////////////////
// serial port ISR
#int_rda
rda_isr(){
switch (getc()){
case 'B': send_build();break;
case 'h': printf("HELP - switch jiggle switch evaluation (triggers active high)\r\n");
printf("B for code build date and time\r\n");
printf("t for trigger count change\r\n");
break;
case 't': printf("\r\ntrigger count?, was %u\r\n",trigger_count);
trigger_count = getnum();
printf("\r\n%u\r\n",trigger_count);
break;
}
}
///////////////////////////////////////////////////////
void wait_to_begin(){
while(!input);
test = 1;
count=1;
Read_Switch_Flag = TRUE;
}
////////////////////////////////////////////////////////////
void wait_for_low_to_high() {
while(!input) ;
delay_us(3);
}
////////////////////////////////////////////////////////////
void wait_for_low() {
delay_us(3);
while(input);
}
///////////////////////////////////////////////////////////
void main() {
disable_interrupts(global);
set_tris_b(0);
test = 0;
setup_timer_2(T2_DIV_BY_16,150,16);
set_timer2(duration);
enable_interrupts(INT_RDA|INT_TIMER2);
enable_interrupts(global);
printf("\r\n jiggle switch evaluation \r\n"); // serial display
printf("pull port D.0 (P3.1) high and then low to time\r\n");
printf("\r\nPress h for help \r\n"); // serial display
do {
printf("\n\rWaiting...\n\r");
wait_to_begin();
set_timer2(duration);
enable_interrupts(INT_TIMER2);
do {
wait_for_low_to_high();
delay_us(3);
wait_for_low();
count += 1;
} while (Read_Switch_Flag);
disable_interrupts(INT_TIMER2);
test = 0;
if (count >= trigger_count)
printf("%2u\n\n\r", count);
count=0;
//delay_ms(50);
} while(TRUE);
}
//////////////////////////////////////////////////////
// function sends build data via serial port
void send_build(){
printf("Build: %s %s\r\n", Build_Date,Build_Time); //serial
}
/* Get a 8-bit decimal number from the console - 3 digits
** Return it when any non-numeric key is pressed (except backspace) */
WORD getnum(void)
{
WORD val=0;
char c, buff[3];
int n=0, i=0;
do {
c = getchar();
if (c>='0' && c<='9')
{
if (n < sizeof(buff))
{
buff[n++] = c;
putchar(c);
}
}
else
c = 0;
} while (c);
while (n--)
val = (val * 10) + buff[i++] - '0';
return(val);
}
|
Thanks in advance for any help
Dan |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Jun 22, 2005 4:02 pm |
|
|
One possible error in your code is that in the serial receive interrupt you are transmitting serial data. This is trouble waiting to happen! You are receiving data at the same rate as you are transmitting. On reception of the first character you are transmitting more than a single character, this will cause queueing problems. The UART is capable of buffering 3 bytes and then will stall unless (unless you use the ERRORS directive in the #use rs232 statement).
Your timing problem might not be related to the above, but as an easy test, try disabling the RDA interrupt and see whether the timing problem still exists. |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Wed Jun 22, 2005 7:03 pm |
|
|
Thanks for your input. I have already tried that without any change. The serial routines are really just for initial setup and then not really used during operation.
I have actually narrowed the problem down a little. It appears that the problem isn't in the delay_ms routine but actually in the interrupt servicing for the timer. For some reason the timer2 interrupt status is not being reset when the timer2 value is being set and then the int_timer2 is being enabled. As soon as the code hits that line the timer2 ISR is being executed.
enable_interrupts(INT_RDA|INT_TIMER2);
enable_interrupts(global);
printf("\r\n jiggle switch evaluation \r\n"); // serial display
printf("pull port D.0 (P3.1) high and then low to time\r\n");
printf("\r\nPress h for help \r\n"); // serial display
do {
printf("\n\rWaiting...\n\r");
wait_to_begin();
set_timer2(duration);
enable_interrupts(INT_TIMER2);
do {
wait_for_low_to_high();
delay_us(3);
wait_for_low();
count += 1;
} while (Read_Switch_Flag);
I already removed the INT_TIMER2 from the first enable_interrupts but the issue remains.
I am looking into the datasheet to see how to clear the interrupts manually before I enable that interrupt. If you have any insight on that, it would be helpful.
Rgds,
Dan |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Wed Jun 22, 2005 7:04 pm |
|
|
Thanks for your input. I have already tried that without any change. The serial routines are really just for initial setup and then not really used during operation.
I have actually narrowed the problem down a little. It appears that the problem isn't in the delay_ms routine but actually in the interrupt servicing for the timer. For some reason the timer2 interrupt status is not being reset when the timer2 value is being set and then the int_timer2 is being enabled. As soon as the code hits that line the timer2 ISR is being executed.
enable_interrupts(INT_RDA|INT_TIMER2);
enable_interrupts(global);
printf("\r\n jiggle switch evaluation \r\n"); // serial display
printf("pull port D.0 (P3.1) high and then low to time\r\n");
printf("\r\nPress h for help \r\n"); // serial display
do {
printf("\n\rWaiting...\n\r");
wait_to_begin();
set_timer2(duration);
enable_interrupts(INT_TIMER2);
do {
wait_for_low_to_high();
delay_us(3);
wait_for_low();
count += 1;
} while (Read_Switch_Flag);
I already removed the INT_TIMER2 from the first enable_interrupts but the issue remains.
I am looking into the datasheet to see how to clear the interrupts manually before I enable that interrupt. If you have any insight on that, it would be helpful.
Rgds,
Dan |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Jun 23, 2005 3:13 am |
|
|
Check this thread regarding double posting.
Disabling the interrupts doesn't stop the timer, that's why the interrupt request flag is active on re-enabling the interrupts again. One solution is to add a call to clear_interrupt(INT_TIMER2) before enabling the interrupt. |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Thu Jun 23, 2005 5:40 am |
|
|
Yah, I read the post but I was working at home and didn't have time to go back in and remove the double post. My bad.
Thanks for the info on clearing the interrupts. I knew that the timer2 continued to run with disable_interrupts but I thought that kept the interrupt flags from being set. I also didn't know about the clear_interrupt(INT_TIMER2) command. Thanks a lot for that, very helpful.
Rgds,
Dan |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Thu Jun 23, 2005 5:48 am |
|
|
I tried adding the clear_interrupt(INT_TIMER2) and the compiler doesn't recognize it. Is that a CCS command or a custom routine? Anyhow, I should be able to manually clear the interrupt with the PIR1 register bit 1.
Dan |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Jun 23, 2005 7:19 am |
|
|
Sorry, I didn't see you are using an old compiler version. The clear_interrupt() function has been introduced somewhere around v3.180. |
|
|
|