Hello everyone,
I'm new to this so apologies in advance for any breach of protocol. This is my first attempt at writing in C++. I have been given a VB6 project which is used for data logging and (eventually) controlling temperature.I have written with the help of various tutorials on the web a little C++ dll with functions that can be used from the VB app.
I would like to be able to use this PidControl class written by Steve Hartmann I found at
http://www.ddj.com/cpp/184403292 to send back a proportional voltage (0 to 10 volts) to VB and consequently control the temperature.
My understanding is that Steve is using this for embedded PidControl in electronics whereas I would like to use this class on a PC directly. I have got to a point where I am stuck due my very limited programming experience (recording macros in Excel until recently).
I have done a test function "cPT100" that I can pass a value and get a temperature back from the calculation and this works fine. I have been able to set up the variables in the class but not store them, for when I call the CalculateGain function later on, I'm not sure how this is done or if possible
The other part of my question is the "PipingSet" part of the code, is this inheritance? Can I make this work without the embedded stuff?
I have changed a couple of lines from the original code in MyPidControl because I was getting compile errors so not really knowing what I was doing I changed "virtual void"
to just void on "SetSetpoint"
Please excuse my lame code, and thankyou to everyone in advance who takes the time to respond regards smithyc
Here is the code so far
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
|
// CarlsVCdll.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "CarlsVCdll.h"
#include "filestuff.h"
#include "MyPIDControl.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// This is an example of an exported variable
CARLSVCDLL_API int nCarlsVCdll=0;
// This is an example of an exported function.
CARLSVCDLL_API int fnCarlsVCdll(void)
{
return 42;
}
// This is the constructor of a class that has been exported.
// see CarlsVCdll.h for the class definition
CCarlsVCdll::CCarlsVCdll()
{
return;
}
CCarlsFileStuff::CCarlsFileStuff()
{
return;
}
MyPidControl::MyPidControl()
{
return;
}
MyPidControl::~MyPidControl()
{
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
//filestuff.h
#include "MyPIDControl.h"
using namespace std;
class CARLSVCDLL_API CCarlsFileStuff {
public:
CCarlsFileStuff(void);
double cPT100(float fvolt, double chnlfdgeConst,double chnlIntcpt)
{
const double Ro = 100;
const double A1 = -0.000000580195;
const double B1 = 0.00390802;
double a,b,c,dRT;
a = Ro * A1;
b = Ro * B1;
dRT = (fvolt + chnlIntcpt) * chnlfdgeConst;
c = -dRT;
return (-b + sqrt(b*b-4*a*c))/(2*a);
}
int setupPID(double vbKP,
double vbKI,
double vbKD,
double vbDC,
double PV)
{
MyPidControl WaterHeater;
WaterHeater.SetProportionalConstant(vbKP);
WaterHeater.SetIntegralConstant(vbKI);
WaterHeater.SetDifferentialConstant(vbKD);
WaterHeater.SetDifferentialCycle(vbDC);
return 1;
}
double getgain(double PV)
{
MyPidControl WaterHeater;
return WaterHeater.CalculateGain(PV);
}
};
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
// MyPidControl.h: interface for the MyPidControl class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_MYPIDCONTROL_H__F09DEBFC_F70A_4410_8F7C_290A72A0133E__INCLUDED_)
#define AFX_MYPIDCONTROL_H__F09DEBFC_F70A_4410_8F7C_290A72A0133E__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <math.h>
class MyPidControl
{
public:
MyPidControl();
virtual ~MyPidControl();
private:
double KProportional,
KIntegral,
KDifferential,
IntegralLimit,
ProportionalGain,
IntegralGain,
DifferentialGain,
Setpoint,
Gain;
unsigned DifferentialCycle;
unsigned DifferentialCycleCount;
double ErrorSum,
LastError;
protected:
MyPidControl( double kP, double kI, double kD,
double lI, double cD );
public:
double CalculateGain( double position );
void SetSetpoint( double setpoint );
double GetProportionalGain() { return ProportionalGain; }
double GetIntegralGain() { return IntegralGain; }
double GetDifferentialGain() { return DifferentialGain; }
void SetProportionalConstant( double kP )
{ KProportional = kP; }
void SetIntegralConstant( double kI )
{ KIntegral = kI; }
void SetDifferentialConstant( double kD )
{ KDifferential = kD; }
void SetDifferentialCycle( unsigned Dc )
{ DifferentialCycle = Dc; }
double GetProportionalConstant() { return KProportional; }
double GetIntegralConstant() { return KIntegral; }
double GetDifferentialConstant() { return KDifferential; }
double GetIntegralLimit() { return IntegralLimit; }
double GetSetpoint() { return Setpoint; }
};
double MyPidControl::CalculateGain( double position )
{
double error = Setpoint - position;
ErrorSum += error;
ProportionalGain = KProportional * error;
IntegralGain = KIntegral * ErrorSum;
if( fabs( IntegralGain ) > IntegralLimit ) {
if( IntegralGain > 0 )
IntegralGain = IntegralLimit;
else
IntegralGain = -IntegralLimit;
ErrorSum -= error;
}
if( ++DifferentialCycleCount >= DifferentialCycle ) {
DifferentialGain = KDifferential * ( error - LastError );
DifferentialCycleCount = 0;
}
LastError = error;
Gain = ProportionalGain + IntegralGain + DifferentialGain;
return Gain;
}
void MyPidControl::SetSetpoint( double setpoint )
{
Setpoint = setpoint;
}
#endif // !defined(AFX_MYPIDCONTROL_H__F09DEBFC_F70A_4410_8F7C_290A72A0133E__INCLUDED_)
|
This part is the PipingSet that I assume is embedded and not sure how to use
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
PipingSet::PipingSet( double kP, double kI, double kD,
double lI, double cD) :
PidControl( kP, kI, kD, lI, cD )
{
CurrentMode = PIPE_MEASURE;
mbox = OSMboxCreate( (void*) 0 );
OSTaskCreate( (void(*) (void*))PipingSet::StartControlTask,
(void *)this, &TaskStack[CONTROL_STACK_SIZE],
PD_CONTROL_PRIO );
}
//-----------------------------------------------------------------
void PipingSet::SetSetpoint( double SetPoint )
{
OSMboxPost( mbox, (void*)CHANGE_SETPOINT_START );
PidControl::SetSetpoint( ( SetPoint / FullScale ) * 100 );
OSMboxPost( mbox, (void*)SETPOINT_COMPLETE );
}
//-----------------------------------------------------------------
void PipingSet::ControlTask( void )
{
UBYTE err;
double pressure;
int stop_control;
double gain;
float volts;
void *msg;
for(;;) {
msg = OSMboxPend( mbox, 0, &err );
if( (int ) msg == START_CONTROL ) {
CurrentMode = PIPE_CONTROL;
stop_control = FALSE;
while( !stop_control ) {
pressure = controlSensor->get_pressure();
gain = CalculateGain( ( pressure / FullScale ) * 100 );
volts = -( gain / 100 );
if( volts > 10 )
volts = 10;
else if( volts < -10 )
volts = -10;
SetServoVoltage( volts );
msg = OSMboxPend( mbox, 1, &err );
if( err == OS_NO_ERR ) {
if( (int)msg == STOP_CONTROL ) {
SetServoVoltage( 0.0 );
stop_control = true;
}
else if( (int)msg == CHANGE_SETPOINT_START ) {
do
msg = OSMboxPend( mbox, 0, &err );
while( (int)msg != SETPOINT_COMPLETE );
}
}
}
CurrentMode = PIPE_MEASURE;
}
}
}
//End of File
|