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 CCS Technical Support

Migrating servo controller code from 16F877 to 16F684

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Chris



Joined: 11 Nov 2004
Posts: 8

View user's profile Send private message

Migrating servo controller code from 16F877 to 16F684
PostPosted: Thu Nov 11, 2004 6:16 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 11, 2004 12:19 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 11, 2004 1:36 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 11, 2004 2:00 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 11, 2004 2:35 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 11, 2004 2:54 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 11, 2004 4:17 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 11, 2004 4:38 pm     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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