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

adc -> pwm problems
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
luanfagu



Joined: 10 Feb 2015
Posts: 6

View user's profile Send private message

adc -> pwm problems
PostPosted: Tue Feb 10, 2015 1:58 am     Reply with quote

So, I'm making a code for job, my program read a potentiometer and returns a 10 bit value that i convert to a number (0~255) and put this number as a pwm duty cycle.
My problem is that comes to some of the potentiometer, and it just back, back to around 60% (which is the point that set minimum for him), when it is put in 100% it does not reach 255.

I don't know if the problem is in adc or when i set the duty cycle.

Code:
#include <18f4431.h>
#device adc=10
#fuses INTRC_IO, NOWDT, NOPROTECT, NOBROWNOUT, PUT, NOLVP
#use delay(clock=8MHz, crystal)

#define POWER_PWM_PERIOD 2048

/*
 *
 */
 
//global variables
float valorpwm, velopwm, valorad;
int valorad1 = 0;
int valorpwm1 = 0, velopwm1 = 0;

float decrementa(float velo, float valor){
   if(velo > valor){
      velo-=0.01;
      delay_ms(24);
   }
   if(valor == 0.0 && velo <=0.6){
      velo = 0.0;
   }
   return velo;
}
int decrementa1(int velo, int valor){
   if(velo > valor){
      velo--;
      delay_ms(24);
   }
   if(valor == 0 && velo <=153){
      velo = 0;
   }
   return velo;
}
int main() {
    setup_adc_ports(sAN0 | sAN1 | sAN2);
    setup_adc(ADC_CLOCK_DIV_4); 

      setup_power_pwm_pins(PWM_ODD_ON, PWM_ODD_ON, PWM_ODD_ON, PWM_ODD_ON);
      setup_power_pwm(PWM_CLOCK_DIV_4|PWM_FREE_RUN, 1, 0, POWER_PWM_PERIOD, 0, 1,0);
   
    setup_ccp1(CCP_PWM);
    setup_ccp2(CCP_PWM);

    setup_timer_2(T2_DIV_BY_4, 255, 1);
   
    set_pwm1_duty(0);
    set_pwm2_duty(0);

        while(1){
                 
                  while(input(PIN_E1)){
                        set_adc_channel(2);
                        delay_us(416);
                        valorad1 =(int) (read_adc());
                        delay_us(416);
                        valorpwm1 =(int) (((valorad1 - 511)*102)/510)+153;                     
                        if(valorpwm1 > velopwm1 && input(PIN_E1)){
                           if(velopwm1 == 0) velopwm1 = 153;
                           else{
                              while(velopwm1 < valorpwm1 && input(PIN_E1)){
                                    velopwm1++;
                                    delay_ms(24);
                                    set_pwm1_duty(velopwm1);
                              }
                           }
                        }else{
                           while(velopwm1 > valorpwm1){
                              velopwm1 = decrementa1(velopwm1, valorpwm1);
                              set_pwm1_duty(velopwm1);
                           }
                        }
                  }
                  valorpwm1 = 0;
                  while(velopwm1 > valorpwm1){
                       velopwm1 = decrementa1(velopwm1, valorpwm1);
                       set_pwm1_duty(velopwm1);
                  }
                  while(input(PIN_E2)){
                        set_adc_channel(2);
                        delay_us(416);
                        valorad1 =(int) (read_adc());
                        delay_us(416);
                        valorpwm1 =(int) ((((valorad1 - 510)*102)*(-1))/510)+153;                     
                        if(valorpwm1 > velopwm1 && input(PIN_E2)){
                           if(velopwm1 == 0) velopwm1 = 153;
                           else{
                              while(velopwm1 < valorpwm1 && input(PIN_E2)){
                                    velopwm1++;
                                    delay_ms(24);
                                    set_pwm2_duty(velopwm1);
                              }
                           }
                        }else{
                           while(velopwm1 > valorpwm1){
                              velopwm1 = decrementa1(velopwm1, valorpwm1);
                              set_pwm2_duty(velopwm1);
                           }
                        }
                  }
                  valorpwm1 = 0;
                  while(velopwm1 > valorpwm1){
                       velopwm1 = decrementa1(velopwm1, valorpwm1);
                       set_pwm2_duty(velopwm1);
                  }
        }
    return (0);
}
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

Divide and conquer
PostPosted: Tue Feb 10, 2015 3:34 am     Reply with quote

Test the ADC and PWM separately

You could try:-

1) Sending ADC output to a PC.
2) Send PWM control from PC to PIC.
3) Make sure each is working as it should on its own.

Mike
temtronic



Joined: 01 Jul 2010
Posts: 9205
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 6:03 am     Reply with quote

Why not simply the program ?
Read the ADC in 8 bit mode! That would automatically give you an 8 bit data to send to the PWM.
Also there is NO need to use floating point math. Again simplify your program! The CCP doesn't accept FP#s, so keep it simple ,use integer math.

As well FP math takes a HUGE amount of time(seconds vs microseconds) so your 'plant' will not respond as fast as it should.

Jay
luanfagu



Joined: 10 Feb 2015
Posts: 6

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 6:14 am     Reply with quote

the float is to another thing, im using power control pwm in this code, and need the float to this works.

@temtronic
thx for the tip, i will try 8bit conversion

EDIT: it doest work, my pic only accept 10 bit conversion.

@Mike Walne
nothing strange, its all right about the conversion, and pwm works fine with a number insted of variable.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 6:34 am     Reply with quote

luanfagu wrote:

EDIT: it doest work, my pic only accept 10 bit conversion.

Read the CCS manual.
As I understand it, this will make the ADC operate in 8 bit mode.
Code:
#DEVICE ADC=8

You believe the ADC is OK, so, have you examined what data is actually being sent to the PWM?

Mike
luanfagu



Joined: 10 Feb 2015
Posts: 6

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 7:14 am     Reply with quote

@Mike Walne
so, all working fine, i realy dont know what happening, when i used another compiler. it happens also, but i rewrote the code and works fine ( i realy dont know why).

if you can, i ask you to test the code and see if this problem occurs with you too.
Ttelmah



Joined: 11 Mar 2010
Posts: 19455

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 9:14 am     Reply with quote

The reason it doesn't work, is maths....

You have the variable used to take the ADC reading declared as 'int' This in CCS, is an _8 bit integer_.
So 10 bit reading into an 8bit integer. Immediate possible overflow.
Then you subtract 510. Result number overflows again (the default integer is _unsigned_) - the maths for this will use int16, since 510 is inherently an int16, but still unsigned..
Then you multiply by 102. Overflow again.
Then you divide by 510. Overflow again.
Then add 153.....

Result potential garbage.
luanfagu



Joined: 10 Feb 2015
Posts: 6

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 9:23 am     Reply with quote

I solve the problem!, i change int to float and it works perfectly.
thank you all guys!

here the code fixed:

Code:
#include <18f4431.h>
#device adc=10
#fuses INTRC_IO, NOWDT, NOPROTECT, NOBROWNOUT, PUT, NOLVP
#use delay(clock=8MHz, crystal)

#define POWER_PWM_PERIOD 2048

#include <lcd.c>

#define LCD_ENABLE_PIN  PIN_D0                                    ////
#define LCD_RS_PIN      PIN_D1                                    ////
#define LCD_RW_PIN      PIN_D2                                    ////
#define LCD_DATA4       PIN_D3                                    ////
#define LCD_DATA5       PIN_D4                                    ////
#define LCD_DATA6       PIN_D5                                    ////
#define LCD_DATA7       PIN_D6
 
//global variables
float valorpwm, velopwm, valorad;
int valorpwm1 = 0, velopwm1 = 0;

float decrementa(float velo, float valor){
   if(velo > valor){
      velo-=0.01;
      delay_ms(24);
   }
   if(valor == 0.0 && velo <=0.6){
      velo = 0.0;
   }
   return velo;
}
int decrementa1(int velo, int valor){
   if(velo > valor){
      velo--;
      delay_ms(24);
   }
   if(valor == 0 && velo <=153){
      velo = 0;
   }
   return velo;
}
int main() {
    setup_adc_ports(sAN0 | sAN1 | sAN2);
    setup_adc(ADC_CLOCK_DIV_4 | VSS_VDD); 

      setup_power_pwm_pins(PWM_ODD_ON, PWM_ODD_ON, PWM_ODD_ON, PWM_ODD_ON);
      setup_power_pwm(PWM_CLOCK_DIV_4|PWM_FREE_RUN, 1, 0, POWER_PWM_PERIOD, 0, 1,0);
   
    setup_ccp1(CCP_PWM);
    setup_ccp2(CCP_PWM);

    setup_timer_2(T2_DIV_BY_4, 255, 1);
   
    lcd_init();
   
    set_pwm1_duty(0);
    set_pwm2_duty(0);

        while(1){
                 
                  while(input(PIN_E1)){
                        set_adc_channel(2);
                        delay_ms(1);
                        valorad = (float) (read_adc());
                        delay_ms(1);
                        valorpwm = (float) ((((valorad - 510.0)*102.0)/510.0)+153.0);
                        valorpwm1 = (int) (valorpwm);
                        if(valorpwm1 > velopwm1 && input(PIN_E1)){
                           if(velopwm1 == 0) velopwm1 = 153;
                           else{
                              while(velopwm1 < valorpwm1 && input(PIN_E1)){
                                 velopwm1++;
                                 delay_ms(24);
                                 set_pwm1_duty(velopwm1);
                              }
                           }
                        }else{
                           while(velopwm1 > valorpwm1){
                              velopwm1 = decrementa1(velopwm1, valorpwm1);
                              set_pwm1_duty(velopwm1);
                           }
                        }
                  }
                  valorpwm1 = 0;
                  while(velopwm1 > valorpwm1){
                       velopwm1 = decrementa1(velopwm1, valorpwm1);
                       set_pwm1_duty(velopwm1);
                  }
                  while(input(PIN_E2)){
                        set_adc_channel(2);
                        delay_ms(1);
                        valorad = (float) (read_adc());
                        delay_ms(1);
                        valorpwm = (float) (((((valorad - 510.0)*102.0)*(-1.0))/510.0)+153.0);
                        valorpwm1 = (int) (valorpwm);                       
                        if(valorpwm1 > velopwm1 && input(PIN_E2)){
                           if(velopwm1 == 0) velopwm1 = 153;
                           else{
                              while(velopwm1 < valorpwm1 && input(PIN_E2)){
                                    velopwm1++;
                                    delay_ms(24);
                                    set_pwm2_duty(velopwm1);
                              }
                           }
                        }else{
                           while(velopwm1 > valorpwm1){
                              velopwm1 = decrementa1(velopwm1, valorpwm1);
                              set_pwm2_duty(velopwm1);
                           }
                        }
                  }
                  valorpwm1 = 0;
                  while(velopwm1 > valorpwm1){
                       velopwm1 = decrementa1(velopwm1, valorpwm1);
                       set_pwm2_duty(velopwm1);
                  }
        }
    return (0);
}


thanks again!
temtronic



Joined: 01 Jul 2010
Posts: 9205
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 9:59 am     Reply with quote

You could also get rid of the floating points altogether and the program will run a LOT faster !!! Maybe 100* faster....

There is zero need for FP, neither the ADC nor CCP use FP.

just food for thought

Jay
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 12:53 pm     Reply with quote

Your program is complex. Test a very simple program that takes the
ADC value and uses it to set the pwm duty cycle:
http://www.ccsinfo.com/forum/viewtopic.php?t=40007
Does that program work for you ?

Here is a 10-bit ADC version:
http://www.ccsinfo.com/forum/viewtopic.php?t=40222&start=1
Ttelmah



Joined: 11 Mar 2010
Posts: 19455

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 1:31 pm     Reply with quote

and seriously, the last thing you want for power control, is floats.
They are too slow for most applications. For the last power control application I did, I used scaled 24bit maths (custom written fixed point), to get the speed needed for PWM control. FP is far to slow, resulting in overshoot in the regulator algorithm. 32bit fixed got 'close'. For me, 16bit didn't quite have the range needed, so I wrote 24bit versions. The values were treated as if they were fixed point binary values with an 8bit mantissa.
You need to start understanding why fp is probably not the solution.
luanfagu



Joined: 10 Feb 2015
Posts: 6

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 4:31 pm     Reply with quote

unfortunately my program has to be complex, I'm controlling 14 hydraulic coils with a astounding accuracy, and all this things with a series of parameters of a volvo hydraulic motor, its not easy for a beginner, like me.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Feb 10, 2015 5:14 pm     Reply with quote

I actually meant, start small, and prove that the basics are working
before you add complexity. Prove that you can read the adc and get
a smooth PWM duty cycle increase as the adc voltage increases.
Ttelmah



Joined: 11 Mar 2010
Posts: 19455

View user's profile Send private message

PostPosted: Wed Feb 11, 2015 2:22 am     Reply with quote

PCM programmer has said it all. You _need_ (mandatory, not optional), to start small. Start with the individual components. ADC. How good is a reading?. Does your circuit still read correctly when a coil is moving (odds are it won't). Then try to control one coil. If you must work with lots of other signals, then simulate these. Development is a series of small steps, not one big leap.
Your 'astounding accuracy' comment is exactly _why_ FP maths should not be used. It's worth realising, that FP is _never_ used for serious financial calculations, because it is too inaccurate. FP is a 'shortcut' to allow quick working with numbers over an enormous range, but comes at the cost of accuracy. When dealing with numbers over a fixed range (which you inherently are, since they come from an ADC), integer is vastly better, but does mean you need to actually understand the numbers and the ranges involved.
temtronic



Joined: 01 Jul 2010
Posts: 9205
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Feb 11, 2015 6:23 am     Reply with quote

hmm.. just noticed this....

#fuses INTRC_IO, NOWDT, NOPROTECT, NOBROWNOUT, PUT, NOLVP
#use delay(clock=8MHz, crystal)


....
pretty sure the fuses(INTRC_IO) is replaced by the use delay(...) so I'm assuming you have an 8MHz xtal for the PIC clock?

If not, you _must_ use a real xtal NOT the internal RC of the PIC. The internal Rc is NOT accurate enough for 'real' tight timing over any range of temperature over time..

just food for thought

also
since you're controlling 14 valves, start with one first, get it working 100% THEN proceed to #2,test,confirm, then keep adding more.
if you try cutting code all of them at one time you'll fail miserably,start small, in the end it's faster and easier to do.

jay
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 1, 2  Next
Page 1 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