| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| luanfagu 
 
 
 Joined: 10 Feb 2015
 Posts: 6
 
 
 
			    
 
 | 
			
				| adc -> pwm problems |  
				|  Posted: Tue Feb 10, 2015 1:58 am |   |  
				| 
 |  
				| 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
 
 
			    
 
 | 
			
				| Divide and conquer |  
				|  Posted: Tue Feb 10, 2015 3:34 am |   |  
				| 
 |  
				| 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: 9589
 Location: Greensville,Ontario
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Feb 10, 2015 6:03 am |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Feb 10, 2015 6:14 am |   |  
				| 
 |  
				| 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
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Feb 10, 2015 6:34 am |   |  
				| 
 |  
				|  	  | 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.
 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Feb 10, 2015 7:14 am |   |  
				| 
 |  
				| @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: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Feb 10, 2015 9:14 am |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Feb 10, 2015 9:23 am |   |  
				| 
 |  
				| 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: 9589
 Location: Greensville,Ontario
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Feb 10, 2015 9:59 am |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Feb 10, 2015 1:31 pm |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Feb 10, 2015 4:31 pm |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Feb 10, 2015 5:14 pm |   |  
				| 
 |  
				| 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: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Feb 11, 2015 2:22 am |   |  
				| 
 |  
				| 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: 9589
 Location: Greensville,Ontario
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Feb 11, 2015 6:23 am |   |  
				| 
 |  
				| 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
 |  |  
		|  |  
		|  |  
  
	| 
 
 | 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
 
 |