CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

16f877a and Gyro Idg5oo
Goto page Previous  1, 2
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Ttelmah



Joined: 11 Mar 2010
Posts: 19249

View user's profile Send private message

PostPosted: Wed May 02, 2012 2:15 am     Reply with quote

I declare adc_sum at the start of my code as a global:
Fifth line of the code.

signed int32 adc_sum;

There shouldn't be any error from this.
On the setup_timer, RTFM. The syntax is setup_timer_1. I missed the extra underbar.

The big difference is that with the CCP, the _hardware_ triggers the ADC conversion, which takes place _in parallel_ with other things going on, allowing you to be doing other things while the conversion takes place. In your code you have stuffed everything inside the timer interrupt - including all the maths, so the code takes just as long as before - so you won't 'obtain the new angle every 20uSec' In fact if you did this would exceed the specs of the ADC anyway..... With the maths, and the print inside the timer, you will be taking:

Read_adc - takes 12 cycles of the ADC clock - ADC clock is 625KHz, so 19.2uSec
Maths, will depend if the compiler works out that *5/1023, can be reduced to *0.00488. Otherwise you are talking 1.2mSec for the first sum (reduces to about 400uSec if the compiler is smart enough....), then another 300uSec for the second calculation, then the LCD takes about 1.5mSec to clear the display, and typically about 40uSec/byte to display the data, so assume a dozen characters, gives about 2mSec to update the display - so total loop in your timer interrupt is taking about 4mSec. Nowhere near 'sampling every 20uSec.....'

In fact your timer interrupt will not even occur that fast. You are feeding the timer off the master clock/256/4 = 19531.25Hz. The timer counts to 65535, so as shown the timer will only interrupt every 3.5seconds - rather different from 20uSec!....

Now arithmetically, the 0.00002048, was the guess as to the conversion needed if you have taken approximately 20000 readings in a second, and already offset them for the origin. Then if the unit gave 2mV out for the entire second, it would have turned by one degree. Since the ADC sensitivity is nominally 3.9mV/step, you would see approximately 10000 counts for a degree, and need to multiply the result by 0.0001. I was suggesting 0.00002 as a starting point since I was not sure what your spec for the gyro really was.

Some further comments - you need a _much_ more stable Vref for your ADC than the 5v rail. Also reducing this, will allow the ADC to have better sensitivity. If the unit has a nominal 1.33 for stationary, then ideally you want a Vref about double this. Perhaps a 2.56v standard. Personally I'd also say you need more gain between the sensor and the ADC, otherwise slow movements _will_ be missed.

You are fundamentally 'missing the point', that you need to be concentrating on _sampling_ fast, and summing the value only. Integration is just a sum over time, so generate the sum ASAP, and just do a single division (or for speed a multiplication by a decimal fraction - since as I have already said multiplication is faster than division), before displaying the result. Do this in the 'spare time' left while the sampling/summing is still carrying on.

In the code I show, the chip is potentially taking a reading every 250 instructions. It takes about 60 instructions to handle the interrupt, another 20 to read the adc, and scale the value, then another ten to perform the sum. So the code will be taking about 100 instructions out of every 250 just doing this. The main code will therefore run at about half it's nominal speed, still plenty to give a reasonable display.

Some basic reading on the CCP, and some basic work on how _slow_ some things are is needed - Microchip have a very good application note about the timers and CCP's.

Best Wishes
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed May 02, 2012 2:52 am     Reply with quote

Besides all the important issues already mentioned by Ttelmah I want to comment on a few minor issues that I see popping up in all your posted program revisions:
Code:
#byte port_a = 5
#byte port_b = 6
#byte port_c = 7
#byte port_d = 8
#byte port_e = 9
You don't use these declarations, so get rid of them. Besides, in CCS programs you don't need these. It is much better to use the input_x and output_x functions as these are portable to other processors without a change to your program.

Code:
set_tris_c(0x00);
set_tris_a(0xff);
Again, these are not needed in standard CCS code. By default the compiler will set the TRIS registers for you when using the input_x and output_x functions. For time critical programs it can be an advantage to handle the TRIS registers yourself but then you have to add the #USE FAST_IO directive which is missing from your program. See the following thread for more info on using fast_io: http://www.ccsinfo.com/forum/viewtopic.php?t=48100

Code:
set_adc_channel(0);
You really like to write large programs? This line pops up on every ADC read that you do, but as you have only one ADC channel in use it makes your program shorter and faster when you select the channel 0 only once at startup and then leave it at that.

Code:
enable_interrupts(global);
enable_interrupts(int_timer0);
setup_timer_0(rtcc_internal | rtcc_div_256);
set_timer0(0);//do the interrupt program each 0.2us
This is exactly the wrong sequence! First configure all your hardware before you enable the interrupt, otherwise it is very well possible the interrupt is already triggered in the background while you are still busy setting it up. So correct sequence should be:
Code:
setup_timer_0(rtcc_internal | rtcc_div_256);  //do the interrupt program each 123456 us
set_timer0(0);      // This line is optional as you don't care so much as to when
                    // the _first_ interrupt will start (power up time of your hardware
                    // is random, so who cares about a few milliseconds here).
clear_interrupt(INT_TIMER0);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
karimpain



Joined: 15 Feb 2012
Posts: 39
Location: italia

View user's profile Send private message AIM Address MSN Messenger ICQ Number

PostPosted: Wed May 02, 2012 4:10 pm     Reply with quote

the code compiles but doesn't work!!!
so it's better put the maths inside the while loop and not inside the isr!!
but u said that timer0 count to 63535 but the timer0 is an 8 bit,so overflows when the count overflow ( 255 to 0)!!! , and the time of each count is
{t=(4/20M)*256*(256-255)=51.2us!
the gyro gives voltage that define the angular velocity (deg/sec) i must multiply this by the sample time(so i have to add all the times that spent to do the operation like the lcd time....adc time)>
and this gyro has two output one its sensitivity is 2mv and the second (amplified output) has 9,1mv>> and for an 10it adc which sensitivity is 5/1023=4.8mv the second one is better!


Last edited by karimpain on Wed May 02, 2012 5:03 pm; edited 1 time in total
karimpain



Joined: 15 Feb 2012
Posts: 39
Location: italia

View user's profile Send private message AIM Address MSN Messenger ICQ Number

PostPosted: Wed May 02, 2012 4:16 pm     Reply with quote

thx ckielstra for the advices!
Yeah, you are right for the #byte port_a = 5 ...etc
But for adc_channel I have to use more than one.
But for the sequence of the timer command you let me notice right things but the pic works the same Smile
karimpain



Joined: 15 Feb 2012
Posts: 39
Location: italia

View user's profile Send private message AIM Address MSN Messenger ICQ Number

PostPosted: Mon May 14, 2012 3:43 pm     Reply with quote

I write the code for the gyro idg500 and obtain good results but there
is still the problem of its drift. Now I'm gonna combine with my
accelerometer adxl335 but it seems that I am gonna use another pic and
communicate together via rs232... Thanx to Ttelmah Smile
Here is the code:
Code:

#include<16f877a.h>
#device adc=10
#Fuses HS,NOPROTECT,NOWDT,NOLVP
#use delay(clock=20000000)
#include<lcd420_b.c>

signed int32 adc_sum=0; //signed int32
signed int32 adc_sum1=0;
signed int32  origin=0; //signed int16
signed int32 comp=0;
signed int32 comp1=0;
signed int32 iuliano=0;
signed int32 iuliano1=0;
int num=0;

#INT_AD
void adc_reading(void){
num=!(num);

 if(num==0){
   SET_ADC_CHANNEL(0);
   iuliano=(read_adc(ADC_READ_ONLY) - origin);   
   adc_sum+=iuliano;
   if ((iuliano<10) && (iuliano>-10))
       {adc_sum=comp;}
   comp= adc_sum;
 }

if(num==1){
  SET_ADC_CHANNEL(1);
  comp1=read_adc();
  iuliano1=(read_adc(ADC_READ_ONLY) - origin);   
  adc_sum1+=iuliano1;
  if ((iuliano1<10) && (iuliano1>-10))
     {adc_sum1=comp1;}
  comp1= adc_sum1;
  }
}

void init(void) {
   set_tris_c(0x00);
   set_tris_a(0xff);
   SETUP_ADC(ADC_CLOCK_DIV_32);
   SETUP_ADC_PORTS(AN0_AN1_AN2_AN3_AN4_AN5);
   SET_ADC_CHANNEL(0);
   lcd_init();
   SETUP_CCP2(CCP_COMPARE_RESET_TIMER);
   SETUP_TIMER_1(T1_INTERNAL | T1_DIV_BY_1); 
   CCP_2=400;
 }

void main(void) {
   float angle=0;
   float angle1=0;
   int16 i_sum=0;
   int8 icount=0;
   signed int32 local_sum; //int32
   signed int32 local_sum1;
   int xx;
   init();

   for (icount=0;icount<10;icount++)
   {
      delay_us(20);
      i_sum+=read_adc();
   }

   origin=i_sum/10;
   set_timer1(0);
   clear_interrupt(INT_AD);
   enable_interrupts(INT_AD);
   enable_interrupts(GLOBAL);

   while(TRUE){
     disable_interrupts(GLOBAL);
     local_sum=(adc_sum);
     local_sum1=(adc_sum1);
     enable_interrupts(GLOBAL);
     angle=(local_sum*0.00021);//5/(sensitivity*12500*1023)=0.0000424
     angle1=(local_sum1*0.00021);
     if(angle>360 || angle<-360)
     {adc_sum=0;}
     if(angle1>360 || angle1<-360)
     {adc_sum1=0;}
     printf(LCD_PUTC,"\fAngle %f\n",angle);
     printf(LCD_PUTC,"Angle1 %f\n",angle1);
     printf(LCD_PUTC,"Start %ld\n",local_sum);   
   }
}
rubenskc



Joined: 28 Sep 2011
Posts: 12

View user's profile Send private message

Hi there....
PostPosted: Thu Aug 09, 2012 8:14 am     Reply with quote

Hi karimpain.... I'm working on a very similar project, also with a 16F877A but a XV 3500CB as gyro (I2C) and a MMA7260Q or MMA7361 (can't remember now which exact model) as accelerometer (analog). The analog part is working just fine - I could share real treasures about the measurement and some filters.... However I'm really struggling with the angular gyro.... Want to exchange contacts and share experiences?
_________________
Rubs
karimpain



Joined: 15 Feb 2012
Posts: 39
Location: italia

View user's profile Send private message AIM Address MSN Messenger ICQ Number

PostPosted: Sun Jun 23, 2013 11:55 am     Reply with quote

Hello rubenskc!
Sorry for being late i'd a lot of works in this year in other things..
but for everything now i'm here.
by the way i have to implement this project in this months.
Thax
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2
Page 2 of 2

 
Jump to:  
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