View previous topic :: View next topic |
Author |
Message |
mabauti
Joined: 08 Jul 2020 Posts: 4
|
Timer0 interrupt and adc conversion with pic16f88 |
Posted: Wed Jul 08, 2020 12:05 pm |
|
|
Hi gentlemen, I hope you're fine:
I'm writing here, because I having a problem with the Timer0 interrupt and adc conversion with pic16f88. Part of the code:
Code: | #INT_TIMER0
void timer0_isr(void)
{
char m,portb_aux;
clear_interrupt(INT_TIMER0); // Clear timer0 interrupt flag bit
set_timer0(61);
i++;
if(i > 2)
{
i = 0;
//output_toggle(PIN_A1);
m=read_adc(); //read ADC conversion
//portb_aux = dec_bin(m); //decimal to binary
//output_b(portb_aux);
output_b(m);
}
} |
main routine code
Code: | void main()
{
// Setup timer0 with internal clock and 256 prescaler
char portb_aux;
setup_oscillator(OSC_4MHZ);
setup_adc(ADC_CLOCK_DIV_32);
setup_adc_ports(sAN0);
set_adc_channel(0);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
set_timer0(61); // Timer0 preload value
clear_interrupt(INT_TIMER0); // Clear timer0 interrupt flag bit
enable_interrupts(INT_TIMER0); // Enable timer0 interrupt
enable_interrupts(GLOBAL); // Enable all unmasked interrupt
// Timer0_freq = MCU_freq / {4 * Prescaler * (256 – TMR0)}
//period = 1/Timer0_freq
while(TRUE) ; // Endless loop
} |
When I use delay instead of interrupts, the conversion is fine, however delays is a bad technique for this project; but when using interrupts like this I'm having irregular readings.
I'd appreciate your help pointing me at my mistake. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Wed Jul 08, 2020 1:03 pm |
|
|
hmm....
I believe that according to the ADC section of the datasheet, table 12-1 shows that ...
adc_clock-/32 is incorrect for a PIC clock of 4MHz....
also the ADC is actually 10 bits, so you need to tell the compiler to only use 8 bits ( 'm' is a char or 8 bits, 0-255). |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jul 08, 2020 2:18 pm |
|
|
Post a schematic of the circuit that is connected to the A/D input pin. |
|
|
mabauti
Joined: 08 Jul 2020 Posts: 4
|
|
Posted: Wed Jul 08, 2020 3:25 pm |
|
|
temtronic: I changed it to 8bits, same result
PCM programer, pic
and thx for your answers |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Wed Jul 08, 2020 4:09 pm |
|
|
Your 1st problem is that you cannot put an AC signal into the PIC ADC section !!!!
Like most(all ?) PICs, you'r ONLY accepts 0 to +5 VDC, never,ever a negative voltage.
Please reread the ADC section( 12 ?) as well as the 'electrical specification' section.
2nd problem is you don't have a current limiting resistor for the LED. There needs to be one, typically 470r for a VDD of 5 volts, though if you're using low current LEDs, you'll need maybe 2k2 or 4k7. That's easy to figure out once you know the 'specs' of the LED. |
|
|
mabauti
Joined: 08 Jul 2020 Posts: 4
|
|
Posted: Wed Jul 08, 2020 4:20 pm |
|
|
I'm using a function generator. sine wave, offset +2.2, Vpk 2.2V
and the led disconnected : same result
thx for your answer temtronic |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jul 08, 2020 6:47 pm |
|
|
Thanks for posting that.
Now, post your delay code that works, so we can compare it to the
interrupt code. Also, post the waveforms for the delay code. |
|
|
hmmpic
Joined: 09 Mar 2010 Posts: 314 Location: Denmark
|
|
Posted: Wed Jul 08, 2020 11:13 pm |
|
|
Some hints.
-Real hw or a simulator?
-What is the frequency you convert on the ad?
-What and why is i++ in the interrupt, where is it defined?
-Remove the clear_interrupt in the interrupt service, i never use it, compiler clear it. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Thu Jul 09, 2020 1:30 am |
|
|
One big problem here is that you end up sitting inside the timer interrupt
for the whole ADC conversion time. Now at Fosc/32, the ADC conversion
actually takes 1/13888 seconds. Now Fosc/32 is outside the specified
value for the chip:
Quote: |
For correct A/D conversions, the A/D conversion clock
(TAD) must be selected to ensure a minimum TAD time
as small as possible, but no less than 1.6 μs and not
greater than 6.4 μs.
|
You are using 8uSec.....
(actually I can't see where you say what clock rate you are using for the
CPU).
So the first thing to do is choose a legal divider. Fosc/8.
This then gives the conversion taking 1/55000th second. Rather better.
Then consider not waiting in the interrupt for the conversion. Instead have
the conversion being done between the interrupts:
Code: |
void main()
{
// Setup timer0 with internal clock and 256 prescaler
char portb_aux;
setup_oscillator(OSC_4MHZ);
setup_adc(ADC_CLOCK_DIV_8);
setup_adc_ports(sAN0);
set_adc_channel(0);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
set_timer0(61); // Timer0 preload value
clear_interrupt(INT_TIMER0); // Clear timer0 interrupt flag bit
read_adc(ADC_START_ONLY); //trigger the ADC
enable_interrupts(INT_TIMER0); // Enable timer0 interrupt
enable_interrupts(GLOBAL); // Enable all unmasked interrupt
// Timer0_freq = MCU_freq / {4 * Prescaler * (256 – TMR0)}
//period = 1/Timer0_freq
while(TRUE) ; // Endless loop
}
//Then the timer code:
#INT_TIMER0
void timer0_isr(void)
{
char m,portb_aux;
//clear_interrupt(INT_TIMER0); // Clear timer0 interrupt flag bit
//Not needed the compiler does this automatically
set_timer0(61);
i++;
if(i > 2)
{
i = 0;
//output_toggle(PIN_A1);
m=read_adc(ADC_READ_ONLY); //read ADC conversion already done
read_adc(ADC_START_ONLY); //start next conversion.
//portb_aux = dec_bin(m); //decimal to binary
//output_b(portb_aux);
output_b(m);
}
}
|
What is happening here is that each time in the interrupt I 'read' the
conversion the ADC has already performed, and start a new conversion
(since the interrupt frequency is lower than the total of ADC conversion
time and Tacq, the ADC has time to acquire after the last conversion is
completed). This makes the time in the interrupt vastly lower.
Now you do realise that given you have the 'i' counter, the ADC will only
read every third interrupt (why?....). Seems a really silly bit of coding.
Your interrupt is occurring every 195 clocks on the timer, which is running
off the CPU/256. So as posted at 4Mhz, you would be only interrupting
every (4000000)/(4*256*195) = 20 times a second, and reading the
ADC just 6.6 times a second. Not surprising that the waveform shows steps.
Do you really want just 6 samples/second?. |
|
|
mabauti
Joined: 08 Jul 2020 Posts: 4
|
|
Posted: Tue Jul 14, 2020 9:46 am |
|
|
hmmpic wrote: | Some hints.
-Real hw or a simulator?
-What is the frequency you convert on the ad?
-What and why is i++ in the interrupt, where is it defined?
-Remove the clear_interrupt in the interrupt service, i never use it, compiler clear it. |
Simulator
1Hz
global variable
ok, cleared
Ttelmah wrote: | Do you really want just 6 samples/second?. |
In fact, I want to sample a 10hz max signal, so I need at least 100 samples/s
Done!
It was a synchronization problem as Ttelmah said
Thank you Ttelmah, hmmpic ,PCM programmer and temtronic |
|
|
|