|
|
View previous topic :: View next topic |
Author |
Message |
John_Lintern
Joined: 30 Sep 2004 Posts: 14
|
Not enough RAM for a 368byte PIC, but ok for a 192byte PIC ? |
Posted: Fri May 13, 2005 7:01 am |
|
|
I am using,
- a PIC16F874A which has 192 bytes of RAM
- a PIC16F877A which has 368 bytes of RAM
The PIC16F877A is the same as the PIC16F874A but has twice the amount of ROM and EEPROM and almost twice as much RAM.
I am using MPLAB ICE2000 to emulate these PICS, with the PCM16XV0 processor module.
When I try to compile my program for the 192 byte PIC16F874A, it compiles fine.
But when I try to compile my program for a the 368 byte PIC16F877A, it comes up with an error saying "Not enough RAM" ! ??
This doesn't make any sense because the PIC16F877A has almost twice the RAM of the PIC16F874A.
I need to use the PIC16F877A because I'm starting to run out of ROM on the PIC16F874A and Ive got more code to add yet.
The PIC16F877A has twice as much program memory so is ideal, but even though it has nearly twice as much RAM it wont compile because of the "Not enough RAM" error.
How can this be ????????
It makes no sense what so ever ??????
Code: |
//************************** Inculde Files ***********************************//
#include <16F874A.h>
#device adc=8
#use delay(clock=20000000)
#fuses NOWDT,HS, PUT, NOPROTECT, NODEBUG, NOLVP, NOCPD, NOWRT, BROWNOUT
#use rs232(baud=38400,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#include <stdlib.h>
const long CCP1_Interrupt = 65216; // this value gives a 104.35ms with a clock speed of 20MHz and a prescale of 8.
// it is used to capture the TMR0 value used to count the pulses for RPM speed measurement.
//*************************** Definitions ************************************//
#define PID_Min_Limit 0 // Minimum value of PID output
#define PID_Max_Limit 255 // Maximum value of PID output
#define a_err_Min_Limit -255 // Minimum error limit for accumlative error (a_error)
#define a_err_Max_Limit 255 // Maximum error limit for accumlative error (a_error)
#define PWM_WRT PIN_E0 // PWM Controller WR pin low
#define PWM_SEL PIN_E1 // PWM Controller SEL pin high
#define PWM_RST PIN_E2 // PWM Controller RST pin low
#define RPM_Scaler 25 // Value RPM counter is multiplied by
#define RPM_SEL PIN_C2 // RPM source select
#define TESTPOINT_0 PIN_B0 // Used for debugging - test point 0 on evaluation board
#define TESTPOINT_1 PIN_B1 // Used for debugging - test point 1 on evaluation board
#define TESTPOINT_2 PIN_B2 // Used for debugging - test point 2 on evaluation board
#define OD_SWITCH PIN_B5 // Used for debugging - use switch to toggle overdrive output
#define LOCKUP PIN_C0 // Lockup output
#define OVERDRIVE PIN_C1 // Overdrive output
#define WARNLAMP PIN_C3 // Warning Lamp output
#define SPEEDDIAG PIN_C4 // Speed Sensor Diagnosis (for CS1124)
//******************************* TRS Sensor *********************************//
// The values for the TRS Sensor are shown in the table below. //
// //
// A tolerance of +/-10 will be used on the ADC value to allow for errors. //
// //
// Position Resistance Voltage ADC Value ADC Range //
// Park 522.2 4.20 214 204 - 224 //
// Reverse 206.2 3.37 171 161 - 181 //
// Neutral 108.6 2.60 132 122 - 142 //
// Drive 59.9 1.87 95 85 - 105 //
// 2nd 31.9 1.21 61 51 - 71 //
// 1st 13.7 0.60 30 20 - 40 //
// //
//****************************************************************************//
#define ParkMin 204
#define ParkMax 224
#define ReverseMin 161
#define ReverseMax 181
#define NeutralMin 122
#define NeutralMax 142
#define DriveMin 85
#define DriveMax 105
#define SecondMin 51
#define SecondMax 71
#define FirstMin 20
#define FirstMax 40
#define Park 0
#define Reverse 1
#define Neutral 2
#define Drive 3
#define Second 4
#define First 5
#define FIRSTGEAR 0
#define SECONDGEAR 1
#define THIRDGEAR 2
#define FOURTHGEAR 3
#define CalibIdle 0
#define CalibSetDuty 1
#define CalibReadOffset 2
#define MAXRPM 6000
#define MAXPRESSURE 100
//***************************** Debugging ************************************//
//#define DEBUG_RPM // use to measure sample time duration - test point 0
//#define DEBUG_RPM_RS232 // send RPM to RS232 port
//#define DEBUG_PID // use to measure duration and frequency of PID routine - test point 1
//#define DEBUG_PID_RS232 // send PID results to RS232 port
//#define DEBUG_a_error // use to measure duration and frequency of a_error - test point 2
//#define DEBUG_d_error // use to measure duration and frequency of d_error - test point 3
//#define DEBUG_ADC_RS232 // send ADC values to RS232 port
//#define DEBUG_TRS_RS232 // send Transmission Range Sensor position to RS232 port
//#define DEBUG_RPMSHIFT_RS232 // send Shift RPM to RS232 port
//#define DEBUG_PWM_CONTROL // manually control the IDX610 PWM Device
//#define DEBUG_PIDPOT // use the pot to control the PID setpoint
//#define DEBUG_PWM_POT_CONTROL // use the pot to control the PWM duty cycle
//#define DEBUG_OD // use switch to toggle overdrive output
#define DEBUG_SEND_PRESSURE_PORTB// sends 8-bit value of actual pressure to PORT B
#define PID_Neg_Feedback // uses negative feedback for the PID control loop (undefine for positive feedback)
//#define DEBUG_PRESSURECALC_RS232 // sends the cacucated pressure to RS232 port
//************************** Global Variables ********************************//
unsigned int RPM_Output=0; //
unsigned int RPM_Input=0; //
unsigned int RPM_Capture=0; //
int1 RPM_Select=0; //
int1 RPMREADY=0; // set RPM_Select to flag output speed
signed int16 error=0; // difference between the setpoint and measured output; error can range from -32,768 to +32,767
signed int16 a_error=0; // accumulative error which is the sum of all past errors; a_error can range from -32,768 to +32,767
signed int16 p_error=0; // previous error which is the value of the last error; p_error can range from -32,768 to +32,767
signed int16 d_error=0; // derivative error which is the difference between error and p_error; d_error can range from -32,768 to +32,767
signed int16 prop_term=0; // calculation of proportional term; prop_term can range from -32,768 to +32,767
signed int16 integ_term=0; // calculation of integral term; integ_term can range from -32,768 to +32,767
signed int16 deriv_term=0; // calculation of derivative term; deriv_term can range from -32,768 to +32,767
// Kp,Ki & Kd are 8-bit vlaues that cannot exceed 255. Enter the PID gains scaled by a factor of 16 (i.e. default is 10x16)
unsigned int kp=0x60; // proportional gain, default of 160, max=15 (16 levels)
unsigned int ki=0x20; // integral gain, default of 160, max=15 (16 levels)
unsigned int kd=0x20; // derivative gain, default of 160, max=15 (16 levels)
unsigned int PIDSetpoint;
unsigned int PIDFeedback;
unsigned int DerivValue=10; // value for derivative term (derivative action = CCP2 interrupt * DerivValue)
unsigned int DerivCounter; // counter for derivative term (derivative action = CCP2 interrupt * DerivValue)
unsigned int SCALE_FACTOR=0x10; // Scaling factor of PID Output
unsigned int16 CCP2_Interrupt = 37500; // this value gives a 60ms interrupt with a clock speed of 20MHz and a prescale of 8.
// it is used to calculate the a_error and d_error for the PID routine.
unsigned int Pressure_Sensor; // ADC measurement of Pressure Sensor
unsigned int Pressure_PSI;
unsigned int Pressure_Required;
unsigned int Pressure_Offset=16; // ADC measurement of Pressure sensor Zero Offset (must be between 0.315V [ADC 16] to 0.585V [ADC 30]; default to 0.315V)
unsigned int TPS; // ADC measurement of Throttle Position Sensor
unsigned int OILTEMP; // ADC measurement of Oil Temperature Sensor
unsigned int TRS; // ADC measurement of Transmission Range Sensor
signed int16 PID_Result=0; // calculation of PID output; PID_Result can range from -32,768 to +32,767
unsigned int TRS_Mode; // mode of Transmission Range Sensor (P,R,N,D,2,1)
int GEAR=FIRSTGEAR;
int UpShift_RPM=0;
int DownShift_RPM=0;
int ShiftPressure[3] = {20,40,60}; // setpoint pressures for first, second and third gear (in PSI)
unsigned int16 Timer2Counter=0;
int Calib_Mode=0;
int1 Timer2Running=0;
int1 PressureCalib=0;
int TPSPercent;
//************************ VMC Control Variables *****************************//
int r=0;
char RxBuffer[10];
int1 VMC_RECEIVED=FALSE;
int VMC_PWM;
int1 VMC_PWM_Flag=FALSE;
int1 VMC_PID_Flag=FALSE;
int1 VMC_ODFlag=FALSE;
int VMC_Overdrive;
int1 VMC_LUFlag=FALSE;
int VMC_Lockup;
//*************************** Shift Schedule *********************************//
int ShiftSched_1to2[2][4] = {{20,20,52,52}, // Co-ordinates work out as, (x) 500rpm 500rpm 1300rpm 1300rpm
{0,25,127,255}}; // (y) 0% 10% 50% 100%
int ShiftSched_2to3[2][4] = {{50,50,92,92}, // Co-ordinates work out as, (x) 1250rpm 1250rpm 2300rpm 2300rpm
{0,38,138,255}}; // (y) 0% 15% 54% 100%
int ShiftSched_3to4[2][4] = {{92,92,188,188}, // Co-ordinates work out as, (x) 2300rpm 2300rpm 4700rpm 4700rpm
{0,71,84,255}}; // (y) 0% 28% 33% 100%
int ShiftSched_4to3[2][4] = {{68,92,180,180}, // Co-ordinates work out as, (x) 1700rpm 2300rpm 4500rpm 4500rpm
{0,66,120,255}}; // (y) 0% 26% 47% 100%
int ShiftSched_3to2[2][4] = {{16,16,60,60}, // Co-ordinates work out as, (x) 400rpm 400rpm 1500rpm 1500rpm
{0,51,133,255}}; // (y) 0% 20% 52% 100%
int ShiftSched_2to1[2][4] = {{12,12,28,28}, // Co-ordinates work out as, (x) 300rpm 300rpm 700rpm 700rpm
{0,132,132,255}}; // (y) 0% 52% 52% 100%
//*************************** Shift Pressures ********************************//
// Co-ordinates work out as (x) 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%
// (y) 5psi 10psi 15psi 25psi 30psi 40psi 45psi 45psi 65psi 80psi 80 psi
// (y) 5psi 10psi 15psi 25psi 30psi 40psi 45psi 45psi 65psi 80psi 80 psi
// (y) 5psi 10psi 15psi 25psi 30psi 40psi 45psi 45psi 65psi 80psi 80 psi
BYTE CONST GearPressures[4][11] = {{0,26,51,77,102,128,153,179,204,230,255},
{0,0,0,5,5,10,5,5,30,40,35}, // first gear
{5,5,10,10,15,15,20,15,40,45,45}, // second gear
{5,10,15,25,30,40,45,45,65,80,80}}; // third gear
//***************************** Functions ************************************//
void Get_TRS(void); // function to read Transmission Range Sensor
int ShiftSchedule(int ShiftSched[2][4]); // function to determine the upshift and downshift RPM
void SendPWMControl(int CONTROL); // function to write control data to PWM Controller
void SendPWMDuty(int DUTY); // function to write PWM Duty Cycle to PWM Controller
void SendPIDConfig(void);
void CalPressureSensor(void);
void CalcPIDSetpoint(void);
int CalcPressure(void); // function to calculate the require pressure
int ProcArray(*int, int);
//************************* RS232 Receive Interrupt **************************//
#int_RDA
RDA_isr()
{
if ((RxBuffer[r++]=getchar())== '\r')
{
RxBuffer[--r]=0;
r=0;
VMC_RECEIVED=TRUE;
}
output_low(PIN_E0);
}
//************************** CCP1 Interrupt **********************************//
#int_CCP1
CCP1_isr()
{
RPM_Capture=get_timer0(); // store Timer0 in variable Timer0_Capture
CCP_1 += CCP1_Interrupt; // add sample time (CCP1_Interrupt) to compare register (CCPR1) for next compare interrupt
if (RPM_Select==0) // check status of which speed source is selected, input speed (1) or output speed (0)?
{ // ---> Output speed is selected
#ifdef DEBUG_RPM
output_high (TESTPOINT_0); // use to measure sample time duration
#endif
output_high (RPM_SEL); // set speed source to input speed
RPM_Output = RPM_Capture; // store RPM value
RPM_Select=1; // set RPM_Select to flag input speed
}
else
{ // ---> Input speed is selected
#ifdef DEBUG_RPM
output_low (TESTPOINT_0); // use to measure sample time duration
#endif
output_low (RPM_SEL); // set speed source to output speed
RPM_Input = RPM_Capture; // store RPM value
RPM_Select=0; // set RPM_Select to flag output speed
}
set_timer0(0); // reset the Timer0
RPMREADY=1;
}
//********************* Update a_error and d_error ***************************//
#int_CCP2
CCP2_isr()
{
CCP_2 += CCP2_Interrupt; // add sample time (CCP2_Interrupt) to compare register (CCPR2) for next compare interrupt
#ifdef DEBUG_a_error
if(bit_test(*6,2))
{
output_low (TESTPOINT_2);
}
else
{
output_high (TESTPOINT_2);
}
// output_high (TESTPOINT_2); // use to measure duration and frequency of a_error
#endif
if(error!=0)
{ // if error is not zero....
a_error=error+a_error; // calculate the accumulated error
if (a_error < a_err_Min_Limit) // is a_error less than the minimum limit ?
{
a_error=a_err_Min_Limit; // YES ----> set a_error to the minimum limit
}
if (a_error > a_err_Max_Limit) // is a_error greater than maximum limit ?
{
a_error=a_err_Max_Limit; // YES ----> set a_error to the maximum limit
}
DerivCounter--; // decrement DerivCounter
if(DerivCounter==0) // has DerivCounter reached zero ?
{
#ifdef DEBUG_d_error
if(bit_test(*6,3))
{
output_low (TESTPOINT_3);
}
else
{
output_high (TESTPOINT_3);
}
//output_high (TESTPOINT_3); // use to measure duration and frequency of d_error
#endif
d_error = (error - p_error); // subtract the previous error from the current error
p_error = error; // store the current error in previous error for next time round
DerivCounter=DerivValue; // restore DerivCounter for next delta error
#ifdef DEBUG_d_error
//output_high (TESTPOINT_3); // use to measure duration and frequency of d_error
#endif
}
}
#ifdef DEBUG_a_error
//output_low (TESTPOINT_2); // use to measure duration and frequency of a_error
#endif
}
#int_TIMER2
TIMER2_isr()
{
Timer2Counter--; // decrement timer counter
if (!Timer2Counter) // has timer counter reached zero ?
{
Timer2Running=FALSE; // YES -> clear flag Timer2Running to indicate the timer has finished
disable_interrupts(INT_TIMER2); // disable timer2 interrupts
}
}
#rom 0x2100={1,2,3,4}
#define TempArray 0x2104
#rom TempArray={1,2,3,4,5,6,7,8}
//**************************** Main Program **********************************//
void main()
{
#ifndef 16C74B
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
#endif
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_counters(RTCC_EXT_H_TO_L,RTCC_DIV_1);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
setup_timer_2(T2_DIV_BY_16,241,13);
CCP_1 = CCP1_Interrupt; // Load compare (CCPR1) with default sample time CCP1_Interrupt
CCP_2 = CCP2_Interrupt; // Load compare (CCPR2) with default sample time CCP2_Interrupt
DerivCounter=DerivValue;
set_tris_A(0b11111111); // set PORTA as inputs
port_b_pullups(FALSE);
set_tris_B(0b00000000); // set PORTB bits as outputs
set_tris_C(0b10000000); // set PORTC bits 0 to 6 as outputs and bit 7 as an input
set_tris_D(0b00000000); // set PORTD as outputs for the databus on the PWM IC
set_tris_E(0b00000000); // set PORTE bits 0, 1 and 2 as outputs to control PWM IC
output_D(0b00000000); // set PWM Controller databus to zero
output_high(PWM_WRT); // set PWM Controller WRT pin high
output_high(PWM_SEL); // set PWM Controller SEL pin high
output_high(PWM_RST); // set PWM Controller RST pin high
setup_adc_ports(A_ANALOG); // set PORTA bits 0,1,2 and 3 as analogue inputs for the ADC
setup_adc(ADC_CLOCK_INTERNAL);// set the ADC to run off the internal clock
set_adc_channel(0); // ADC set to look at channel 0
output_high(PWM_RST); // reset PWM Controller
output_low(PWM_RST); // reset PWM Controller
output_high(PWM_RST); // reset PWM Controller
output_high (RPM_SEL); // set speed source to output speed
output_low (LOCKUP); // set Lockup Solenoid off
output_low (OVERDRIVE); // set Overdrive Solenoid off
output_high (WARNLAMP); // set Warning Lamp off
output_low (SPEEDDIAG); // set Speed Sensor Diagnosis to off
SendPWMControl(0b11000000); // deadtime 0, control not locked, divide by 1, 8-bit resolution, output disabled
SendPWMDuty(0x00); // start with a 0% duty cycle
set_timer0(0); // Reset timer0 - used to count pulses for input and output speed
set_timer1(0); // Reset timer1 - used for two compare interrupts: CCP1 for speed measurement sample time: CCP2 for PID a_error and d_error
set_timer2(0); // Reset timer2 - used as 10ms interrupt for time delays
disable_interrupts(INT_TIMER2);
enable_interrupts(INT_RDA); // enable RS232 receive data interrupt
setup_ccp1(CCP_COMPARE_INT); // interrupt used to capture the TMR0 vaule which counts pulses to calculate the output speed.
setup_ccp2(CCP_COMPARE_INT); // interrupt used to calculate the a_error and d_error for the PID routine.
enable_interrupts(INT_CCP1); // enable interrupt to capture the TMR0 value used to count the pulses for RPM speed measurement.
enable_interrupts(INT_CCP2); // enable interrupt to calculate the a_error and d_error for the PID routine.
enable_interrupts(GLOBAL); // enable all global interrupts
#ifdef DEBUG_PWM_CONTROL // define this to manually control the IDX610 PWM Device
do
{
output_low(PWM_SEL); // set SEL pin low to write data to pulse width register
output_low(PWM_WRT); // set WRT pin low to prepare to write data (set 'breakpoint' on this line & manually change Port D value)
output_high(PWM_WRT); // set WRT pin high to write data on the low-to-high transition
}
while(TRUE);
#endif
Pressure_Required = ShiftPressure[0]; // set pressure setpoint to first gear
do
{
//************************** Read ADC Inputs *********************************//
#ifdef DEBUG_OD
output_bit(OVERDRIVE,!input(OD_SWITCH));
#endif
set_adc_channel(0); // ADC set to look at channel 0
delay_us(100); // wait a short time after changing the channel to get a valid read
Pressure_Sensor=read_adc(); // read ADC input from pressure sensor
if (Pressure_Sensor<Pressure_Offset) // ensure the pressure sensor does not fall below the zero pressure offset voltage (should never happen)
{
Pressure_Sensor=Pressure_Offset; // if it does make the pressure sensor equal to the zero pressure offset voltage
}
Pressure_PSI=(Pressure_Sensor-Pressure_Offset)/2.04; // calculate pressure in psi using transfer function of sensor
// i.e. PSI=(Sensor[ADC value] - Offset[ADC value]) ÷ 2.04
#ifdef DEBUG_SEND_PRESSURE_PORTB
output_B(Pressure_Sensor);
#endif
set_adc_channel(1); // ADC set to look at channel 1
delay_us(100); // wait a short time after changing the channel to get a valid read
TPS=read_adc(); // read value of Throttle Position Sensor
set_adc_channel(2); // ADC set to look at channel 2
delay_us(100); // wait a short time after changing the channel to get a valid read
OILTEMP=read_adc(); // read value of Transmission Oil Temperature
// 0°C = 1.6V (ADC value of 82) to 1.7V (ADC value of 87)
// 10°C = 1.7V (ADC value of 87) to 1.8V (ADC value of 92)
#ifdef DEBUG_PWM_POT_CONTROL // define this to manually control the IDX610 PWM Device
output_D(TPS); // place data on databus
output_low(PWM_SEL); // set SEL pin low to write data to pulse width register
output_low(PWM_WRT); // set WRT pin low to prepare to write data
output_high(PWM_WRT); // set WRT pin high to write data on the low-to-high transition
#endif
#ifndef DEBUG_PWM_POT_CONTROL
CalPressureSensor(); // calibrate the pressure sensor (if calibration conditions exist)
#endif
Get_TRS(); // determine the position of the Transmission Range Sensor
//************************ Act on TRS Position *******************************//
if(!VMC_PID_Flag) // is VMC PID control is in use ?
{
switch (TRS_Mode) // NO ---> find required governor pressures
{
case Park:
Pressure_Required=0;
break;
case Reverse:
Pressure_Required=0;
break;
case Neutral:
Pressure_Required=0;
break;
case Second:
Pressure_Required=0;
break;
case First:
Pressure_Required=0;
break;
case Drive:
Pressure_Required=CalcPressure();
#ifdef DEBUG_PRESSURECALC_RS232
TPSPercent=(((float)TPS/255)*100);
printf("Pressure = %03U\t Throttle (ADC) = %03U\t",Pressure_Required,TPS);
printf("Throttle (%%) = %03U\t Current Gear = %03U\r",TPSPercent,GEAR+1);
#endif
//**************** Determine Up Shift and Down Shift RPM ******************//
switch (GEAR)
{
case FIRSTGEAR:
UpShift_RPM=ShiftSchedule(ShiftSched_1to2); // determine the upshift rpm when in 1st gear
break;
case SECONDGEAR:
UpShift_RPM=ShiftSchedule(ShiftSched_2to3); // determine the upshift rpm when in 2nd gear
DownShift_RPM=ShiftSchedule(ShiftSched_2to1); // determine the downshift rpm when in 2nd gear
break;
case THIRDGEAR:
UpShift_RPM=ShiftSchedule(ShiftSched_3to4); // determine the upshift rpm when in 3rd gear
DownShift_RPM=ShiftSchedule(ShiftSched_3to2); // determine the downshift rpm when in 3rd gear
break;
case FOURTHGEAR:
DownShift_RPM=ShiftSchedule(ShiftSched_4to3); // determine the downshift rpm when in 4th gear
break;
default:
break;
} // end parenthesis switch (GEAR)
//****** If RPM rises above Up Shift threshold then change up a gear ******//
if (GEAR!=FOURTHGEAR)
{
if (RPM_Output > UpShift_RPM)
{
GEAR++;
if (GEAR==FOURTHGEAR) // is current gear in fourth (i.e. overdrive) ?
{
if (!VMC_ODFlag) // is VMC overdrive control not in use ?
{
output_high (OVERDRIVE); // set Overdrive Solenoid off
}
}
else
{
Pressure_Required=ShiftPressure[GEAR]; // required pressure used as the PID setpoint
}
}
}
//**** If RPM falls below Down Shift threshold then change down a gear ****//
if (GEAR!=FIRSTGEAR)
{
if (RPM_Output < DownShift_RPM)
{
if (GEAR==FOURTHGEAR) // is current gear in fourth (i.e. overdrive)
{
if (!VMC_ODFlag) // is VMC overdrive control not in use ?
{
output_low (OVERDRIVE); // set Overdrive Solenoid on
}
}
GEAR--;
Pressure_Required=ShiftPressure[GEAR]; // required pressure used as the PID setpoint
}
}
break;
default:
break;
} // end parenthesis switch (TRS_Mode)
} // end parenthesis of if(!VMC_PID_Flag)
#ifdef DEBUG_RPMSHIFT_RS232
printf ("Gear=%U\tRPM=%03U\tUpShift=%03U\tDownShift=%03U\tTPS=%03U\r",GEAR+1,RPM_output,UpShift_RPM,DownShift_RPM,TPS);
#endif
#ifdef DEBUG_ADC_RS232
PRINTF("Pressure=%4.1f psi\t Offset=%03U\t TPS=%03U\t Oiltemp=%03U\t TRS=%03U\t \r",Pressure_PSI,Pressure_Offset,TPS,OILTEMP,TRS); // send ADC values to RS232 port
#endif
//**************************** PID Routine ***********************************//
CalcPIDSetpoint();
#ifdef PID_Neg_Feedback // define type of feedback used for the PID control
error=(int16)PIDSetpoint-Pressure_Sensor; // negative feedback
#else
error=(int16)Pressure_Sensor-PIDSetpoint; // positive feedback
#endif
if(!VMC_PWM_Flag) // if VMC PWM control is not active then allow PID control
{
if ((error)&&(!PressureCalib)) // if error is not zero and pressure calibration is not active
{ // then allow PID control
#ifdef DEBUG_PID
output_high (TESTPOINT_1); // use to measure duration and frequency of PID routine
#endif
disable_interrupts(GLOBAL); // disable all interrupts whilst calculating the PID term
prop_term=error*kp; // calculate the proportional term
integ_term=a_error*ki; // calculate the integral term
deriv_term=d_error*kd; // calculate the derivative term
PID_Result=((prop_term + integ_term + deriv_term)/SCALE_FACTOR); // calculate the PID calculation
if (PID_Result < PID_Min_Limit) // is the result less than the minimum limit ?
{
PID_Result=PID_Min_Limit; // YES ----> return the minimum limit
}
if (PID_Result > PID_Max_Limit) // is the result greater than maximum limit ?
{
PID_Result=PID_Max_Limit; // YES ----> return the maximum limit
}
SendPWMDuty(PID_Result); // send PID result as the duty cycle for the PWM device
enable_interrupts(GLOBAL); // enable all global interrupts
#ifdef DEBUG_PID
output_low (TESTPOINT_1); // use to measure duration and frequency of PID routine
#endif
}
}
else
{
PID_Result=VMC_PWM; // use VMC PWM value as PID Result
SendPWMDuty(PID_Result); // send PID result as the duty cycle for the PWM device
}
#ifdef DEBUG_PID
output_low (TESTPOINT_1); // use to measure duration and frequency of PID routine
#endif
#ifdef DEBUG_PID_RS232
printf ("%03ld\t %03ld\t %03ld\t %03ld\t %03U\n\r",error,a_error,d_error,PID_Result,Pressure_PSI); // send PID results to RS232 port (takes 5-6ms at 38400 baud)
#endif
//****************************************************************************//
#ifdef DEBUG_RPM_RS232
if (RPMREADY)
{
PRINTF("Output=%04lu\t Input=%04lu\r",(int16)RPM_Output * RPM_Scaler,(int16)RPM_Input * RPM_Scaler); // send RPM to RS232 port
RPMREADY=0;
}
#endif
}
while(TRUE);
}
//***********************************************************************//
// Function: Get_TRS //
// Overview: This routine will read the ADC value for the Transmission //
// Range Sensor and set the necessary mode, P,R,N,D,2 or 1 //
// Input: - //
// Output: - //
//***********************************************************************//
void Get_TRS(void)
{
set_adc_channel(3); // ADC set to look at channel 3
delay_us(100); // wait a short time after changing the channel to get a valid read
TRS=read_adc(); // read value of Transmission Range Sensor
if ((TRS>=ParkMin)&&(TRS<=ParkMax))
{
TRS_Mode=Park;
}
if ((TRS>=ReverseMin)&&(TRS<=ReverseMax))
{
TRS_Mode=Reverse;
}
if ((TRS>=NeutralMin)&&(TRS<=NeutralMax))
{
TRS_Mode=Neutral;
}
if ((TRS>=DriveMin)&&(TRS<=DriveMax))
{
TRS_Mode=Drive;
}
if ((TRS>=SecondMin)&&(TRS<=SecondMax))
{
TRS_Mode=Second;
}
if ((TRS>=FirstMin)&&(TRS<=FirstMax))
{
TRS_Mode=First;
}
#ifdef DEBUG_TRS_RS232
printf ("%02U\r",TRS_Mode); // send TRS to RS232 port
#endif
}
//****************************************************************************//
// Function: CalPressureSensor //
// Input: - //
// Output: - //
// Description: //
// The governor pressure sensor will be affected by environmental changes as //
// well as manufacturing tolerances. //
// //
// Although the transfer function will remain constant, there could be an //
// offset variation due to barometric pressure and temperature change. This //
// requires a calibration procedure to measure the offset. //
// //
// The sensor will be calibrated by measuring the offset when the governor //
// pressure is at zero psi. //
// //
// The calibration will only be performed when the following conditions exist://
// //
// • the transmission oil temperature is above 10°C (50°F) //
// • the output speed falls below 200 rpm //
// //
// The calibration procedure works by providing the governor pressure //
// solenoid with a 95% duty cycle for 500ms, the governor pressure sensor is //
// then measured and this value is used as the offset value. The calibration //
// procedure is repeated every 3 seconds under the above conditions. //
// //
// The pressure sensor has the following transfer function... //
// Voltage = (0.04 * Pressure) + Offset //
// where Offset will be from 0.315V to 0.585V (with a supply voltage of 5V)//
// //
// Therefore... //
// Pressure = (Voltage - Offset) ÷ 0.04 //
// where Offset will be from 0.315V to 0.585V (with a supply voltage of 5V)//
// //
// The values in this equation are with a 5V supply, so as the ADC value will //
// be 255 at 5V, the values in the equation must be scaled by 51 (i.e.255÷5) //
// The equation becomes... //
// //
// Pressure = (Pressure_Sensor - Pressure_Offset) ÷ 2.04 //
// where Offset will be from 16 to 30 (with a supply voltage of 5V) //
//****************************************************************************//
void CalPressureSensor(void)
{
if (!VMC_PWM_Flag) // is VMC PWM Control not in use ?
{
if ((RPM_Output<8)&&(OILTEMP>87)) // is the output speed less than 200 rpm and the oil temp greater than 10°C ?
{
if (!Timer2Running) // YES---> is Timer2 running ?
{
PressureCalib=TRUE; // NO---> set flag PressureCalib as an indication not to use the PID control
switch (Calib_Mode)
{
case CalibIdle:
SendPWMDuty(0); // set duty cycle to 0%
Timer2Counter=300; // load counter with 300 (counter increments every 10ms, so 300 counts = 3sec)
Timer2Running=TRUE; // set flag Timer2Running to indicate the timer is running
set_timer2(0); // Reset timer2 - used as 10ms interrupt to increment counter (Timer2Counter)
enable_interrupts(INT_TIMER2); // enable timer2 interrupt
Calib_Mode=CalibSetDuty; // set Calib_Mode to indicate the duty cycle must be set next
break;
case CalibSetDuty:
SendPWMDuty(243); // set duty cycle to 95% (243/256 = 95%)
Timer2Counter=50; // load counter with 50 (counter increments every 10ms, so 50 counts = 500ms)
Timer2Running=TRUE; // set flag Timer2Running to indicate the timer is running
set_timer2(0); // Reset timer2 - used as 10ms interrupt for time delays
enable_interrupts(INT_TIMER2); // enable timer2 interrupt
Calib_Mode=CalibReadOffset; // set Calib_Mode to indicate the offset must be read next
break;
case CalibReadOffset:
set_adc_channel(0); // ADC set to look at channel 0
delay_us(100); // wait a short time after changing the channel to get a valid read
Pressure_Offset=read_adc(); // read value of Pressure sensor
SendPWMDuty(0); // set duty cycle to 0%
if ((Pressure_Offset>=16)&&(Pressure_Offset<=30)) // is zero pressure offset voltage between 0.313V [ADC 16] and 0.585V [ADC 30] ?
{
output_high (WARNLAMP); // turn off warning lamp to indicate zero pressure calibration was within range
}
else
{
if (Pressure_Offset<16) // is zero pressure offset voltage less than 0.313V [ADC 16]
{
Pressure_Offset=16; // limit the zero pressure offset to 0.315V [ADC 16]
output_low (WARNLAMP); // turn on warning lamp to indicate there was a fault with the zero pressure calibration (offset voltage too low)
}
if (Pressure_Offset>30) // is zero pressure offset voltage greater than 0.585V [ADC 30]
{
Pressure_Offset=30; // limit the zero pressure offset to 0.585V [ADC 30]
output_low (WARNLAMP); // turn on warning lamp to indicate there was a fault with the zero pressure calibration (offset voltage too high)
}
}
Calib_Mode=CalibIdle; // set Calib_Mode to indicate that calibration has finished and not in progress
break;
default:
break;
} // end parenthesis of switch statement
} // end parenthesis of if (Timer2Running)
} // end parenthesis of if ((RPM_Output<8)&&(OILTEMP>87)) statement
else
{
PressureCalib=FALSE; // set flag PressureCalib as an indication to use the PID control
Calib_Mode=CalibIdle; // set Calib_Mode to indicate that calibration is no longer in progress
}
} // end parenthesis of if (VMC_PWM_Flag!=TRUE) statement
} // end parenthesis of function CalPressureSensor
//***********************************************************************//
// Function: ShiftSchedule //
// Overview: This routine will determine which shift schedule should be //
// used from the sensors TRS, TPS and OILTEMP. //
// Input: - //
// Output: - //
//***********************************************************************//
int ShiftSchedule(int ShiftSched[2][4])
{
int x,temp;
float grad;
for(x=0 ; x<3 ; x++)
{
if ((TPS>=ShiftSched[1][x])&&(TPS<=ShiftSched[1][x+1]))
{
if ((ShiftSched[0][x])==(ShiftSched[0][x+1]))
{
return (ShiftSched[0][x]);
break;
}
else
{
grad= ((float)TPS-(float)(ShiftSched[1][x])) / ((float)(ShiftSched[1][x+1])-(float)(ShiftSched[1][x]));
temp=((((ShiftSched[0][x+1])-(ShiftSched[0][x])) * grad) + ShiftSched[0][x]);
return ((((ShiftSched[0][x+1])-(ShiftSched[0][x])) * grad) + ShiftSched[0][x]);
break;
}
}
}
#ifdef DEBUG_RPMSHIFT_RS232
printf ("ShiftRPM=%02U\t TPS=%03U\r",UpShift_RPM,TPS); // send UpShift_RPM to RS232 port
#endif
}
//***********************************************************************//
// Function: SendPWMDuty //
// Overview: This routine will send a duty cycle to the PWM controller. //
// Input: DUTY //
// Output: - //
//***********************************************************************//
void SendPWMDuty(int DUTY)
{
output_low(PWM_SEL); // set SEL pin low to write data to pulse width register
output_low(PWM_WRT); // set WRT pin low to prepare to write data
output_D(DUTY); // place data on databus
output_high(PWM_WRT); // set WRT pin high to write data on the low-to-high transition
}
//***********************************************************************//
// Function: SendPWMControl //
// Overview: This routine will send the control word to the PWM //
// controller (IXDP610). //
// Input: CONTROL //
// Output: - //
//Bit Name Description //
//bit 0 DT0 for setting the dead-time period //
//bit 1 DT1 0 is no dead-time delay and 7 is maximum dead-time. //
//bit 2 DT2 //
//bit 3 not used, reserved; always write a zero to this bit //
//bit 4 Lock setting this bit prevents further access to all bits in //
// the Control latch, except the Stop bit. //
//bit 5 DIV determines frequency of the internal PWM clock. //
//bit 6 7/8 chooses between 7-bit and 8-bit resolution. //
//bit 7 Stop disables (turns off) the complementary outputs. //
//***********************************************************************//
void SendPWMControl(int CONTROL)
{
output_high(PWM_SEL); // set SEL pin high to write data to control register
output_low(PWM_WRT); // set WRT pin low to prepare to write data
output_D(CONTROL); // place data on databus
output_high(PWM_WRT); // set WRT pin high to write data on the low-to-high transition
}
//***********************************************************************//
// Function: SendPIDConfig //
// Overview:
// Input: - //
// Output: - //
//***********************************************************************//
void SendPIDConfig(void)
{
printf ("%02X%02X%02X%04LX%02X%02X%02X%02X%02X\r",kp,ki,kd,CCP2_Interrupt,DerivValue,Pressure_Required,VMC_PID_Flag,Pressure_Offset,PIDSetpoint);
}
//***********************************************************************//
// Function: CalcPressure //
// Overview: This routine will determine the governor pressure which //
// changes depending on Throttle Position. //
// Input: - //
// Output: - //
//***********************************************************************//
int CalcPressure()
{
int x;
float grad;
for(x=0 ; x<10 ; x++)
{
if ((TPS>=GearPressures[0][x])&&(TPS<=GearPressures[0][x+1]))
{
if ((GearPressures[1+GEAR][x])==(GearPressures[1+GEAR][x+1]))
{
return (GearPressures[1+GEAR][x]);
break;
}
else
{
grad= ((float)TPS-(float)(GearPressures[0][x])) / ((float)(GearPressures[0][x+1])-(float)(GearPressures[0][x]));
if((GearPressures[1+GEAR][x+1])>=(GearPressures[1+GEAR][x]))
{
return ((((GearPressures[1+GEAR][x+1])-(GearPressures[1+GEAR][x])) * grad) + GearPressures[1+GEAR][x]);
}
else
{
return (GearPressures[1+GEAR][x]-(((GearPressures[1+GEAR][x])-(GearPressures[1+GEAR][x+1])) * grad));
}
break;
}
}
}
#ifdef DEBUG_RPMSHIFT_RS232
printf ("ShiftRPM=%02U\t TPS=%03U\r",UpShift_RPM,TPS); // send UpShift_RPM to RS232 port
#endif
}
//***********************************************************************//
// Function: SendPIDConfig //
// Overview:
// Input: - //
// Output: - //
//***********************************************************************//
void CalcPIDSetpoint(void)
{
PIDSetpoint=(Pressure_Required*2.04)+Pressure_Offset; // make PID setpoint equal to the required pressure (given in psi) which is then converted to an ADC value, including the offset pressure
}
|
|
|
|
rwyoung
Joined: 12 Nov 2003 Posts: 563 Location: Lawrence, KS USA
|
|
Posted: Fri May 13, 2005 7:16 am |
|
|
instead of "fixes" the issue. That is to say, the program compiles.
This is a bit odd though...
Email CCS support and let them chew on the problem too.
FYI, I tested with PCWH 3.224. Always give your compiler revision when posting. _________________ Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month! |
|
|
Ttelmah Guest
|
|
Posted: Fri May 13, 2005 7:47 am |
|
|
There is nothing 'odd' about this behaviour at all.
Without the *=16, you are only using the low two RAM banks on the chips, not the full area. On the 874, the banks are 'normal', but on the 876, the top 16bytes of the second bank, are duplicates of the top 16bytes on the first bank.
So the 874, has 96*2 bytes available in the bottom two banks, but the 877, only has 96+80 bytes available in the same area.
Without *=16, this is the total RAM available to the program, with the bigger chip having 16bytes less memory accessible in this mode.
Best Wishes |
|
|
|
|
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
|