| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| Chris 
 
 
 Joined: 11 Nov 2004
 Posts: 8
 
 
 
			    
 
 | 
			
				| Migrating servo controller code from 16F877 to 16F684 |  
				|  Posted: Thu Nov 11, 2004 6:16 am |   |  
				| 
 |  
				| Hi Everyone, I am developing a Radio Control style DC servo unit and have nearly completed the code functionality.
 
 I am not an expert using pics but have done 1 or 2 small projects in the past this is the first time I have used the CCP1 feature
 
 I started the development using a 16F877 chip because it has convenient serial for debugging. A few days back I was ready to migrate the code to the final PCB which has 16F684 and H bridge chips.
 
 I use CCP1 to capture the incoming PWM signal to tell the servo what position to be in. I have to continuously switch the CCP1 from capture "Hi 2 Lo" then capture "Lo 2 Hi" then subtract 1 timer value from the other to get the pulse width in time.
 
 The CCP1 worked fine on the 16F877 but I have spent 2 days trying to fire up the CCP1 of the 16F684. I am aware the 16F684 has ECCP which seems subtly different but I cannot see how this works.
 
 I am not an expert using pics but I have done 1 or 2 small projects in the past this is the first time I have used the CCP1 feature
 
 Any help greatly appreciated. Code used on the 16F877 follows
 
 Best Regards
 
 Chris
 
 #include <16F877.h>		// Header file for the code, <16f877.h>
 
 #ZERO_RAM	                // Always do this, zeros all RAM at startup
 #fuses HS,NOWDT,NOPROTECT,PUT,NOBROWNOUT,NOLVP//, NOWRT, NOCPD, NOLVP
 #use delay(clock=20000000)
 #use rs232(baud=115200, xmit=PIN_C6, rcv=PIN_C7)//PIC16F877 Tx = C6 = pin 25, Rx = C7 = pin 26.
 
 #include <input.c>
 
 void Initialise(void);
 void GetAtoD(void);
 void SpeedControl(void);
 void PID(void);
 
 char keypress;
 unsigned int Load=0, capture_mode, AtoD=0, Speed=127;
 unsigned int Duty_Hi, Duty_Lo, RangeLeft, RangeRight, clock_full;
 signed int BoundLeft=64, BoundRight=-64, DeadbandLeft=1, DeadbandRight=-1;
 unsigned long x, rise, fall, pulse_width;
 signed long Error, Error_Store=0, Error_Temp;
 
 #int_ccp1
 void isr()
 {
 if (capture_mode == 0)
 {
 rise = CCP_1;                  // save start time in "rise"
 setup_ccp1(CCP_CAPTURE_FE);    // Configure CCP1 to capture fall
 capture_mode = 1;
 }
 else if (capture_mode == 1)
 {
 fall = CCP_1;
 setup_ccp1(CCP_CAPTURE_RE);    // Configure CCP1 to capture rise
 pulse_width = fall - rise;
 capture_mode = 0;
 pulse_width = (pulse_width/5); // divide by 5 (I dunno why, works!) is done in orig EX_CCPMP.c prog
 speed = (pulse_width + 1000.0175)/3.9215;//y=mx + c
 }
 }
 
 void Initialise(void)
 {
 setup_adc( ALL_ANALOG );		// Set up PORTA for analogue capture
 setup_adc( ADC_CLOCK_INTERNAL );
 
 OUTPUT_HIGH ( PIN_c3 ); 		//MOSFET chip, disable2 pin 13, enable pin 20, set to 5 v
 OUTPUT_LOW ( PIN_D4 ); 			//MOSFET chip, disable pin 27 set to 0 v
 
 RangeLeft = (BoundLeft-DeadbandLeft+1); //(BoundLeft-DeadbandLeft+2);
 RangeRight = (DeadbandRight-BoundRight+1);//BoundLeft=64, BoundRight=-64, DeadbandLeft=1, DeadbandRight=-1;
 
 setup_ccp1(CCP_CAPTURE_RE);    	// Con	figure CCP1 to capture rise
 setup_timer_1(T1_INTERNAL);    	// Start timer
 
 enable_interrupts(INT_CCP1);   	// Setup interrupt on falling edge
 enable_interrupts(GLOBAL);
 
 capture_mode = 0;				// 0 = rising edge, 1 = falling	edge
 }
 
 void GetAtoD(void)
 {
 set_adc_channel(0);	// Select the channel to log
 delay_us(20);       // Wait 20us for ADC conversion to finish
 AtoD = Read_ADC();  // Read the value and convert to 10 bit number
 
 set_adc_channel(1);
 delay_us(20);
 Load = Read_ADC();
 }
 
 void PID(void)
 {
 Load = (Load*Load*Load) + 100;		//increase load values to stiffen up gearbox output
 Error = (((signed long)(Error * Load) / 100));
 }
 
 void SpeedControl(void)
 //calculation. Overall pulse width = 100us, duty cycle is varied to achieve speed control
 //direction & speed resolution = 8bit = 256 steps (0 - 255)
 //0 - 127 = clockwise, 0 = full speed, 127 = full stop
 //128 - 255 = anticlockwise, 128 = full stop, 255 = full speed
 //example calc, duty cycle = [127 (from pc)/255 (full range)] * 100
 //check if pot value is > or < than current speed and set direction of motor
 //
 //zoning speed and direction
 //Error = Speed - AtoD
 //127   =  127  -  0
 //64    =  127  -  63
 //2     =  127  -  125
 //254   =  127  -  129
 //192   =  127  -  191
 //128   =  127  -  255
 {
 Error = ((signed long)Speed - AtoD);
 
 //BoundLeft = 63, BoundRight = 191, DeadbandLeft=2, DeadbandRight=254, RampLeft, RampRight;
 if(Error <= 127 && Error > BoundLeft)	//full speed ahead
 {
 OUTPUT_low ( PIN_c0 );				//motor is full speed here
 OUTPUT_high ( PIN_c1 );
 delay_us(1000);
 //printf("full spe clock\r\n");
 }
 
 else if(Error <= BoundLeft && Error > DeadbandLeft)	//slowing down for setpoint
 {
 OUTPUT_LOW ( PIN_c0 ); 				//make other motor pin low
 Duty_Hi = ((float)Error/Rangeleft)*100;
 
 if (Duty_Hi < 25)	//speed must prevent overshoot & oppose rotation of out shaft
 {
 Duty_Hi = 25;
 }
 
 Duty_Lo = 100-Duty_Hi; 				// how long pulse is high
 //	printf("slowing clock\r\n");
 for (x=0;x<1000;x++)
 {
 OUTPUT_high ( PIN_c1 ); 		//MOSFET chip, disable2 pin 13, enable pin 20, set to 5 v
 delay_us(Duty_Hi);
 OUTPUT_low ( PIN_c1 ); 			//MOSFET chip, disable1 pin 18 set to 0 v
 delay_us(Duty_Lo);
 }
 }
 
 else if(Error >= DeadbandLeft && Error >= DeadbandRight)//dead stop
 {
 OUTPUT_LOW ( PIN_c0 ); 				//set motor to off
 OUTPUT_LOW ( PIN_c1 );
 //	printf("stop\r\n");
 }
 
 else if(Error < DeadbandRight && Error >= BoundRight)	//slowing down for setpoint
 {
 OUTPUT_LOW ( PIN_c1 ); 				//make other motor pin low
 Error = Error*-1;
 Duty_Lo = ((float)Error/RangeRight)*100;
 
 if (Duty_Lo < 25)	//speed must prevent overshoot & oppose rotation of out shaft
 {
 Duty_Lo = 25;
 }
 
 Duty_Hi = 100-Duty_Lo; 				// how long pulse is high
 //	printf("slowing anti\r\n");
 for (x=0;x<1000;x++)
 {
 OUTPUT_high ( PIN_c0 ); 		//MOSFET chip, disable2 pin 13, enable pin 20, set to 5 v
 delay_us(Duty_Lo);
 OUTPUT_low ( PIN_c0 ); 			//MOSFET chip, disable1 pin 18 set to 0 v
 delay_us(Duty_Hi);
 }
 }
 
 else if(Error < BoundRight && Error >= -128)	//full speed ahead
 {
 OUTPUT_low ( PIN_c1 );				//motor is full speed here
 OUTPUT_high ( PIN_c0 );
 delay_us(1000);
 //	printf("full spe anti\r\n");
 }
 }
 
 main() {
 setup_adc( ALL_ANALOG );				// Set up PORTA for analogue capture
 setup_adc( ADC_CLOCK_INTERNAL );
 
 Initialise();
 while(1)
 {
 GetAtoD();
 PID();
 //KeyHit();
 //	printf("Speed %u, AtoD %u, Error %ld, Error_Store %ld\r\n", Speed, AtoD, Error, Error_Store);
 //	printf("Duty_Hi %u, Duty_Lo %u\r\n", Duty_Hi, Duty_Lo);
 //	printf("Error_Temp %u\r\n", Error_Temp);
 printf("Error %ld, AtoD %u, Load %u\r\n",Error, AtoD, Load);
 //	printf("Error %ld, Error_Store %ld, Error_Temp %ld\r\n", Error, Error_Store, Error_Temp);
 SpeedControl();
 }
 }
 
 :confused
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Nov 11, 2004 12:19 pm |   |  
				| 
 |  
				| What's the version of your compiler ? 
 It's possible that your version of the compiler doesn't
 setup the ECCP correctly on the 16F684.
 |  |  
		|  |  
		| Chris 
 
 
 Joined: 11 Nov 2004
 Posts: 8
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Nov 11, 2004 1:36 pm |   |  
				| 
 |  
				| Hi PCM Programmer, I spotted your thorough reply to a similar question at:
 http://www.ccsinfo.com/forum/viewtopic.php?t=18181&highlight=eccp
 an hour ago.
 
 Could I test my code and target pic in the same manner you describe for the 18 series pics? If so I will try but it'll take me a while to understand all steps involved and try it.
 
 My versions are:
 PCB ver 3.184
 PCM ver 3.184
 PCH ver DLL Error
 
 I am a bit surprised by the DDL Error, could this be part of the problem?
 How should I proceed to fix this issue. Is there a patch or do I have to purchase something? A last resort is changing my PCB for a conventional CCP oriented pic but that seems drastic.
 
 Regards
 
 Chris
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Nov 11, 2004 2:00 pm |   |  
				| 
 |  
				| PCM 3.184 doesn't even compile  this line: setup_ccp1(CCP_CAPTURE_RE);
 It says:
 Error[12]   C:\PICC\TEST\test.c 12 : Undefined identifier  setup_ccp1
 
 The 16F684.H file doesn't have any constants in it for the CCP capture
 mode.   So I wonder how you're compiling the program.
 
 Anyway, I compiled two lines with the setup_ccp1() function for
 the latest version of the compiler.
 
 Here is the code produced by PCM vs. 3.212 for the 16F684:
 
  	  | Code: |  	  | 0000                00305 .................... setup_ccp1(CCP_CAPTURE_RE); 000F 1683       00306 BSF    03.5
 0010 1505       00307 BSF    05.2
 0011 1283       00308 BCF    03.5
 0012 0195       00309 CLRF   15
 0013 3005       00310 MOVLW  05
 0014 0095       00311 MOVWF  15
 0015 0197       00312 CLRF   17
 0016 0196       00313 CLRF   16
 0000                00314 ....................
 0000                00315 .................... setup_ccp1(CCP_CAPTURE_FE);
 0017 1683       00316 BSF    03.5
 0018 1505       00317 BSF    05.2
 0019 1283       00318 BCF    03.5
 001A 0195       00319 CLRF   15
 001B 3004       00320 MOVLW  04
 001C 0095       00321 MOVWF  15
 001D 0197       00322 CLRF   17
 001E 0196       00323 CLRF   16
 | 
 |  |  
		|  |  
		| Chris 
 
 
 Joined: 11 Nov 2004
 Posts: 8
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Nov 11, 2004 2:35 pm |   |  
				| 
 |  
				| Hi PCM Programmer, I reached the point where I was trying to hack the code by looking through what is available in .h file. The last setup I tried follows:
 SETUP_TIMER_1(T1_INTERNAL);
 EXT_INT_EDGE(L_TO_H);//(CCP_CAPTURE_RE);
 
 ENABLE_INTERRUPTS(INT_CCP1);
 ENABLE_INTERRUPTS(GLOBAL);// This line says "Go ! (start running) "
 
 I hoped that if it compiled I wasnt far off. The above has probably changed 50 times in the last 48 hours. I tried everything.
 
 I am very grateful for your help.
 
 Just so I understand fully, the version I have will not correctly compile 16F684 code so that the ECCP pin functionality works but if I upgrade to PCM ver 3.212 for the 16F684 the problem is solved?
 
 Many Thanks for your help. I will contact CCS tomorrow for details of an upgrade.
 
 Best Regards
 
 Chris
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Nov 11, 2004 2:54 pm |   |  
				| 
 |  
				| When I posted that code, I didn't check it.   I just posted it to show that a newer version of the compiler did compile code for it.
 
 Upon examining the code, I can a see bug.
 
 They're setting the bit 2 of  the TRISA register = 1.   This will make pin
 A2 be an input.   But there's a problem with that.  The CCP1 module is
 on pin C5.   They should have set TRISC, bit 5, as an input.
 
 The truth is, the PIC powers-up with the TRIS registers set to all 1's,
 and this configures the i/o ports as all inputs.    So as long as you
 haven't changed Pin C5 to an output with a previous line of code,
 it should be in the proper state.    The bug would only cause a problem
 if you were using pin A2 as an output.
 
 If it was me, I would just write directly to the registers to setup the
 ECCP module manually.  Why upgrade for something that isn't even
 correct ?   Do it yourself in this case.
 |  |  
		|  |  
		| Chris 
 
 
 Joined: 11 Nov 2004
 Posts: 8
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Nov 11, 2004 4:17 pm |   |  
				| 
 |  
				| Hi PCM Programmer, I can see what your getting at but I cant read assembler and therefore am not sure which part of the assembled text shows when the TRISA bit 2 gets changed. I also cannot see which commands I need to edit out or keep when setting up the ECCP pin.
 
 I have tried setting the TRISC, bit 5 (input) and bit 2 (output on C2). But I still cant see any pulse width out changes on pin C2. I am using C2 to generate a pulse of changing width depending on the pulse width measured.
 
 I have stripped the code down so it only measures incoming pulse widths on C5 and creates an output pulse (C2) from the measurements.
 
 The code below  does compile and run but the outgoing pulse stream doesnt change width when the input pulse to the ECCP pin changes.
 
 Could you describe in a bit more detail how to configure the ECCP pin. I think its mostly the initialise section thats wrong but am I also using the correct command to measure a rising edge? Or have I missed somthing obvious out?
 
 I think the reason I am struggling here is that my knowledge is a bit too low level to keep up, but with a nudge I should get it.
 
 Regards
 
 Chris
 
 Code follows:
 #include <16F684.h>	       // Header file for the code, <16f684.h>
 
 #ZERO_RAM	      // Always do this, zeros all RAM at startup
 #fuses HS,NOWDT,PUT,NOMCLR,NOPROTECT,NOBROWNOUT,IESO,FCMEN,NOCPD
 #use delay(clock=20000000)
 
 void Initialise(void);
 void SpeedControl(void);
 
 unsigned int capture_mode, Speed=127;
 unsigned long rise, fall, pulse_width;
 
 #int_ccp1
 void isr()
 {
 if (capture_mode == 0)
 {
 rise = INT_CCP1;                   // save start time in "rise"
 EXT_INT_EDGE(H_TO_L);//setup_ccp1(CCP_CAPTURE_FE);
 capture_mode = 1;
 }
 else if (capture_mode == 1)
 {
 fall = INT_CCP1;
 EXT_INT_EDGE(L_TO_H) ;//setup_ccp1(CCP_CAPTURE_RE);
 pulse_width = fall - rise;
 capture_mode = 0;
 pulse_width = (pulse_width/5); // divide by 5
 speed = (pulse_width + 1000.0175)/3.9215;//y=mx + c
 }
 }
 
 void Initialise(void)
 {
 SET_TRIS_C( 0x0F );
 
 SETUP_TIMER_1(T1_INTERNAL);
 
 EXT_INT_EDGE(L_TO_H);//(CCP_CAPTURE_RE);
 ENABLE_INTERRUPTS(INT_CCP1);
 ENABLE_INTERRUPTS(GLOBAL);
 }
 
 void main()
 {
 Initialise();
 while(1)
 {
 OUTPUT_low ( PIN_c2 );				//motor is full speed here
 delay_us(Speed);
 OUTPUT_high ( PIN_c2 );
 delay_us(10);
 
 }
 }
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Nov 11, 2004 4:38 pm |   |  
				| 
 |  
				| I just scanned your current program without trying to understand it and saw two errors, at least.
 
 You have these two lines in your isr.
 
  	  | Code: |  	  | rise = INT_CCP1; // save start time in "rise" fall = INT_CCP1;
 | 
 But these two lines are assigning a CCS constant value to
 your variables.   You should be using 'CCP1', as you did
 in the first program you posted.
 
 Here's what your code above is assigning to those variables.
 #define INT_CCP1                  0x8C20
 |  |  
		|  |  
		|  |  
  
	| 
 
 | 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
 
 |