![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
exodia505
Joined: 07 Feb 2012 Posts: 34
|
5 adc channels !!!! |
Posted: Tue Feb 07, 2012 6:26 am |
|
|
Hello !!
I would like to know where is problem in using (division). As you see I use Timer2 to read, each Timer2 interrupt a value from Adc (successively ch1....to ch5). When I display idiv.rem it does take value(0,1,2,3,4)!!!!
I just want to get some correction.
Thanks
Here's my code:
Code: |
#include <16F877.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES XT //Crystal osc <= 4mhz
#FUSES NOPUT //No Power Up Timer
#FUSES PROTECT //Code protected from reads
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NODEBUG //No Debug mode for ICD
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#include <LCD.C>
#include <Stdlib.h>
int a=0;
int val,val1,val2,val3,val4;
div_t idiv;
#int_TIMER2
void TIMER2_isr(void)
{
idiv=div(a,5);
switch(idiv.rem)
{
case 0:set_adc_channel(0);
delay_us(20);
val=read_adc();
output_high(pin_c0);
a=a+1;
break;
case 1:set_adc_channel(1);
delay_us(20);
val1=read_adc();
output_high(pin_c1);
a=a+1;
break;
case 2:set_adc_channel(2);
delay_us(20);
val2=read_adc();
output_high(pin_c2);
a=a+1;
break;
case 3:set_adc_channel(3);
delay_us(20);
val3=read_adc();
output_high(pin_c4);
a=a+1;
break;
case 4:set_adc_channel(4);
delay_us(20);
val4=read_adc();
output_high(pin_c5);
a=a+1;
break;
}
}
void main()
{
lcd_init();
setup_adc_ports(AN0_AN1_AN2_AN3_AN4);
setup_adc(ADC_clock_div_8);
setup_psp(PSP_DISABLED);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DIV_BY_1,99,16);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
while(1){
if(input(pin_b1)==1)
{
lcd_putc("\f");
lcd_gotoxy(1,1);
printf(lcd_putc,"%2u",val);}
else{
lcd_putc(" ");
}
if(input(pin_b2)==1){
lcd_putc("\f");
lcd_gotoxy(10,1);
printf(lcd_putc,"%2u",val1);
}else{
lcd_putc(" ");
}
if(input(pin_b3)==1){
lcd_putc("\f");
lcd_gotoxy(10,1);
printf(lcd_putc,"%2u",val2);
}
else{
lcd_putc(" ");
}
if(input(pin_b4)==1){
lcd_putc("\f");
lcd_gotoxy(10,1);
printf(lcd_putc,"%2u",val3);
}
else{
lcd_putc(" ");
}
if(input(pin_b4)==1){
lcd_putc("\f");
lcd_gotoxy(10,1);
printf(lcd_putc,"%2u",val4);
}
else{
lcd_putc(" ");
}
// TODO: USER CODE!!
}
}
|
_________________ NOway!! |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9180 Location: Greensville,Ontario
|
|
Posted: Tue Feb 07, 2012 6:53 am |
|
|
One problem is that ISRs -MUST- be short and quick !!
That means the ISR should just set a flag then exit.
Having ANY kind of math function inside, especially division, is very bad.
The same holds true for delays( delay_us(), delay_ms()).
And switch/case statements.
You've got all 3 in your ISR !!
One answer is to just have the ISR set a 'flag', then in 'main' read that flag and if set, increment a variable( channel),then read the adc,display data,if channel=>5 reset channel to 0, then clear flag to 0.
Also
You should always add 'errors' to the use RS232(options) to keep the UART from 'freezing' as it only has a 2 byte buffer. |
|
![](templates/subSilver/images/spacer.gif) |
exodia505
Joined: 07 Feb 2012 Posts: 34
|
|
Posted: Tue Feb 07, 2012 9:02 am |
|
|
thx anyway , it works now _________________ NOway!! |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19386
|
|
Posted: Tue Feb 07, 2012 9:18 am |
|
|
The other appraoch that works for this, is to use a state machine, and do just one job at a time in the ISR.
(I slightly disagree with temtronics comment about switch/case in an ISR - it can work very well, and is as quick as a single array access - it just _must_ be used with care...). The delays involved in the code though are even worse, since the normal use of the read_adc function, takes 12 cycles of the ADC clock - typically 24uSec - add the acquisition delays, and things are getting very slow....
So:
Code: |
#int_TIMER2
void TIMER2_isr(void) {
static int8 state=0;
switch(state++) {
case 0:
set_adc_channel(0); //This only used on the first pass
break;
case 1:
read_adc(ADC_START_ONLY); //Normal re-entry point for the loop
break;
case 2:
val=read_adc(ADC_READ_ONLY);
output_high(pin_c0);
set_adc_channel(1);
break;
case 3:
read_adc(ADC_START_ONLY);
break;
case 4:
val1=read_adc(ADC_READ_ONLY);
output_high(pin_c1);
set_adc_channel(2);
break;
case 5:
read_adc(ADC_START_ONLY);
break;
case 6:
val2=read_adc(ADC_READ_ONLY);
output_high(pin_c2);
set_adc_channel(3);
break;
case 7:
read_adc(ADC_START_ONLY);
break;
case 8:
val3=read_adc(ADC_READ_ONLY);
output_high(pin_c4);
set_adc_channel(4);
break;
case 9:
read_adc(ADC_START_ONLY);
break;
case 10:
val4=read_adc(ADC_READ_ONLY);
output_high(pin_c5);
set_adc_channel(0);
state=1; //start again _at the second state_.
break;
}
}
|
This takes 11 calls to the timer ISR to sample all five channels, but is _fast_ for each route. The switch takes about 18 machine cycles (note no 'default' - this is vital, since it forces a jump table to be made, rather than successive tests). Each call just sets a channel (a couple of machine cycles only), starts an ADC conversion (again just a couple of cycles), or reads a conversion (about 8 cycles).
No divisions - just set the state back to 0 on the last call.
No waiting for the ADC, start it on one ISR, and read it on the next.
Compiling this the _slowest_ route through the code takes under 40 machine cycles on a PIC16.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
exodia505
Joined: 07 Feb 2012 Posts: 34
|
|
Posted: Tue Feb 07, 2012 10:47 am |
|
|
yes, that's true i just changed two things and it worked well _________________ NOway!! |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9180 Location: Greensville,Ontario
|
|
Posted: Tue Feb 07, 2012 10:52 am |
|
|
The only issue I have with Case inside the ISR, is in timing. Depending on how the 'case' is made it might take too long to be effective inside the ISR. Looking at the listing will see how much code is created.
As we all have found out, code always seems to 'grow'....and ISRs should
always be fast !
The bottom line is that if it works, great ! BUT if you run into 'issues', reduce ISR code to the minimum. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19386
|
|
Posted: Tue Feb 07, 2012 3:53 pm |
|
|
temtronic wrote: | The only issue I have with Case inside the ISR, is in timing. Depending on how the 'case' is made it might take too long to be effective inside the ISR. Looking at the listing will see how much code is created.
As we all have found out, code always seems to 'grow'....and ISRs should
always be fast !
The bottom line is that if it works, great ! BUT if you run into 'issues', reduce ISR code to the minimum. |
Yes.
This is where I am with 'must be used with care'. Setup by someone who has worked out CCS's rather 'non plain' rules for how switches are decoded, so a jump table is used, it is quite fast. However the point Temtronic is making here is totally valid you _need_ to actually study the timings to be sure that it is coding the way you expect.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
exodia505
Joined: 07 Feb 2012 Posts: 34
|
|
Posted: Fri Feb 10, 2012 4:45 am |
|
|
if i want to send adc values to pc via serial port and i use this :
printf("%2u %2u %2u %2u %2u\n\r",val,val1,val2,val3,val4);
will be fine? i mean is it easy to separare between data in vb.net ?
what you advice me to do ?
thanks _________________ NOway!! |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9180 Location: Greensville,Ontario
|
|
Posted: Fri Feb 10, 2012 6:45 am |
|
|
How easy VB.NET works is up to you( I don't use it)
If you insert commas you creat 'CSV' data, Excel will display perfectly
original code...
printf("%2u %2u %2u %2u %2u\n\r",val,val1,val2,val3,val4);
modified code...
printf("%2u , %2u , %2u , %2u , %2u\n\r",val,val1,val2,val3,val4);
Also, you should read up on VB to see if \n\r is the 'end of line' delimiter or if \r\n is the 'end of line' delimiter.
I know for CSV files it's different than QB45. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|