|
|
View previous topic :: View next topic |
Author |
Message |
nicogorr
Joined: 12 May 2006 Posts: 3
|
Timer interrupt does not work properly |
Posted: Fri May 12, 2006 12:16 pm |
|
|
Hello.
I`m trying to send samples to a PC over RS232 at maximum speed. The fastest sample rate for 10 bit samples is about 5760HZ (115200bps constraint). The problem occurs in the Timer1 ISR that set the desired sampling frequency. The: setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_8 ); means that 1 count in timer1 represents 1.6us. So, when the timer1 interrupts the code is executed in about 72.8 us(Calculated using timers and then some corrections via ASM list), then the timer is set to interrupt every 64*1,6uS=102.4us....Summing that time to the 72.8us already elapsed it gives 175,2uS, thts gives a Fs of approx. 5707hz...
Here the things get messy...at this speed in the PC I`m only geting about 4 to 6 Bytes per second..the same it happens when i set the timer at -100 -150 -200(that's it decrasing the sample rate)..only when I reach about -270 I`m able to get all the samples, and -270 means a sample rate of 1/(270*1,6uS + 72.8us)=1980Hz that`s not even close to 5700hz...
If it's possible I want to be able to reach at least 5000Hz samples.
Thanks in advance.
Nicolas.
#include <16f877a.h>
#device adc=10
#fuses HS,NOWDT,PUT,NOPROTECT,BROWNOUT,NOWRT,LVP
#use delay (clock=20000000)
#use rs232 (baud=115200, xmit=PIN_C6, rcv=PIN_C7, PARITY=N, BITS=8)
#org 0x0F00, 0x0FFF void loader16F877(void) {}
unsigned long muestra;
char adc_ALTO, adc_BAJO;
#int_TIMER1
Timer_test(){
disable_interrupts(INT_TIMER1); |
delay_us(20); |
muestra=read_adc(); |
adc_ALTO = (char)(((muestra >> 5)& 0x1f)|0xe0);|
adc_BAJO = (char)(muestra & 0x1f); } This lines takes about 72.8uS to
putc(adc_ALTO); | complete
putc(adc_BAJO); |
delay_us(20); |
enable_interrupts(INT_TIMER1); |
set_timer1(-64);// set_timer1(-64) + 72.8uS(Already elapsed)=> Fs=5707Hz or Ts=175uS
}
void main(){
setup_adc_ports(RA0_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(0);
enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER1);
setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_8 );
set_timer1(0);
while(1){
output_high(PIN_D3);
delay_ms(1000);
output_low(PIND_D3);
delay_ms(500);
}
} |
|
|
rwyoung
Joined: 12 Nov 2003 Posts: 563 Location: Lawrence, KS USA
|
|
Posted: Fri May 12, 2006 12:30 pm |
|
|
Why are you delaying 20us inside your interrupt? That doesn't seem like a good idea. Also, the enable/disable timer interrupt calls are probably not necessary inside the ISR.
Consider using the ADC interrupt to let you know when a sample is completed, use the timer interrupt to schedule the start of the next acquisition and use your main loop to push new data out the RS232 port.
Also, as displayed, your code will not compile as there are extraneious "|" (pipe) symbols and at least one extra closing bracket "}" in the interrupt code. Use the Code button when posting code. _________________ Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri May 12, 2006 12:42 pm |
|
|
I see one possible bug. I think your intention is to load Timer1
with -64 so it will overflow and cause an interrrupt in 64 counts.
Here is the problem: Timer1 is a 16-bit timer, but you are loading
it with an 8-bit value. You need to put an "L" after the -64 to tell
the compiler that this is a 16-bit constant. Example: -64L
Notice the difference in the .LST file between the two methods:
Code: |
.................... set_timer1(-64);
0016: CLRF 0F
0017: MOVLW C0
0018: MOVWF 0E
....................
.................... set_timer1(-64L);
0019: MOVLW FF
001A: MOVWF 0F
001B: MOVLW C0
001C: MOVWF 0E |
|
|
|
nicogorr
Joined: 12 May 2006 Posts: 3
|
|
Posted: Fri May 12, 2006 12:53 pm |
|
|
Thanks rwyoung,
The interrupt code is this:
Code: |
#int_TIMER1
Timer_test(){
disable_interrupts(INT_TIMER1);
delay_us(20);
muestra=read_adc();
adc_ALTO = (char)(((muestra >> 5)& 0x1f)|0xe0);
adc_BAJO = (char)(muestra & 0x1f);
putc(adc_ALTO);
putc(adc_BAJO);
delay_us(20);
enable_interrupts(INT_TIMER1);
set_timer1(-64);
}
|
I been trying without enable/disable timer interrupt calls, thats does not make any difference..
I cannot deal with the ADC interrupt idea because in the main loop I need to do some others things...
Rwyoung, forget about the ADC problem..The next code has the same problem:
Code: |
#int_TIMER1
muestra_adc(){
disable_interrupts(INT_TIMER1);
putc(69);
putc(67);
enable_interrupts(INT_TIMER1);
set_timer1(-200);
}
|
I been trying that code without enable/disable timer ..same results.
Sorry for my poor english I'm from chile.
Any suggestions???? |
|
|
nicogorr
Joined: 12 May 2006 Posts: 3
|
|
Posted: Fri May 12, 2006 1:00 pm |
|
|
PCM programmer, your totally right!!. Thank you very much.
I have been looking for errors in the code for about 2 days "You can't see the forest for the trees"..
Well that fix it, Thanks again. |
|
|
|
|
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
|