Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Jeisson David Torrecilla A
Created February 7, 2017

Controlled environment (PID pseudocode) Using MATLAB

Here I will show how you can get data from any plant to create a focused controller, in this case i controlled temperature. (Pseudocode PID)

147
Controlled environment  (PID pseudocode) Using MATLAB

Things used in this project

Story

Read more

Schematics

Power Circuit

This power circuit was used to activate the actuator necessary to control

PSoC esquematic ON/OFF

PID Esquematic PSoC

Code

ON/OFF Program

C/C++
This is to generate a square signal
#include <project.h>
#include <stdio.h>

#define ADC_CHANNEL_VREF			(0u)
#define ADC_CHANNEL_VTH				(1u)
#define LED_ON						(0u)
#define LED_OFF						(1u)
#define TEMPERATURE_THRESHOLD_HIGH	(2700)
#define TEMPERATURE_THRESHOLD_LOW	(2500)
#define FILTER_COEFFICIENT_TEMPERATURE	(32u)
/* EzI2C Read/Write Boundary */
#define READ_WRITE_BOUNDARY         (0u)

/* Structure that holds the temperature sensor (thermistor) data                 */
/* Use __attribute__((packed)) for GCC and MDK compilers to pack structures      */
/* For other compilers use the corresponding directive.                          */
/* For example, for IAR use the following directive                              */
/* typedef __packed struct {..}struct_name;                                      */
typedef struct __attribute__((packed))
{
	int16 Vth;					/* Voltage across thermistor */
	uint16 Rth;					/* Thermistor resistance */
	int16 temperature;			/* Measured temperature */
}temperature_sensor_data;

/* Function Prototypes */
void InitResources(void);

/* Declare the i2cBuffer to exchange sensor data between Bridge Control 
Panel (BCP) and PSoC Analog Coprocessor */
temperature_sensor_data i2cBuffer = {0, 0, 0};

/*******************************************************************************
* Function Name: main
********************************************************************************
*
* Summary:
*  This function initializes all the resources, and in an infinite loop, measures the temperature from the sensor 
*  readings and to send the data over I2C.
*
* Parameters:
*  None
*
* Return:
*  int
*
* Side Effects:
*   None
*******************************************************************************/
int main()
{
    char stringBuffer[32u];
    /* Variables to hold the the ADC readings */
    int16 adcResultVREF, adcResultVTH;
    int n1=1;
    /* Filter input and output variables for Vref and Vth measurements */
    int16 filterOutputVref=0;
    int16 filterOutputVth=0;
    
    /* Variables to hold calculated resistance and temperature */
    int16 thermistorResistance, temperature;
    
    /* Variable to store the status returned by CyEnterCriticalSection()*/
    uint8 interruptState = 0;
    
    /* Enable global interrupts */
    CyGlobalIntEnable;
    
    /* Initialize hardware resources */
    InitResources();

    /* Infinite Loop */
    for(;;)
    {
        /* Check if the ADC data is ready */
        if(ADC_IsEndConversion(ADC_RETURN_STATUS))
        {
            /* Read the ADC result for reference and thermistor voltages */
            adcResultVREF = ADC_GetResult16(ADC_CHANNEL_VREF);
            adcResultVTH = ADC_GetResult16(ADC_CHANNEL_VTH);
            
            /* Low pass filter the measured ADC counts of Vref */            
            filterOutputVref = (adcResultVREF + (FILTER_COEFFICIENT_TEMPERATURE - 1) * filterOutputVref) / FILTER_COEFFICIENT_TEMPERATURE;
                    
            /* Low pass filter the measured ADC counts of Vth */         
            filterOutputVth = (adcResultVTH + (FILTER_COEFFICIENT_TEMPERATURE - 1) * filterOutputVth) / FILTER_COEFFICIENT_TEMPERATURE;
                        
            /* Calculate thermistor resistance */
            thermistorResistance = Thermistor_GetResistance(filterOutputVref, filterOutputVth);           
            
            /* Calculate temperature in degree Celsius using the Component API */
            temperature = Thermistor_GetTemperature(thermistorResistance);
            
            /* Turn ON Ligth and turn OFF fan */ 
            
            while (n1==1){
             Fan_Write(0);
             Ligth_Write(1);
        uint16_t Temp1 = temperature;
        sprintf(stringBuffer, "%d",Temp1);
        UART_UartPutString(stringBuffer);        
        CyDelay(20);
        adcResultVREF = ADC_GetResult16(ADC_CHANNEL_VREF);
            adcResultVTH = ADC_GetResult16(ADC_CHANNEL_VTH);
            
            /* Low pass filter the measured ADC counts of Vref */            
            filterOutputVref = (adcResultVREF + (FILTER_COEFFICIENT_TEMPERATURE - 1) * filterOutputVref) / FILTER_COEFFICIENT_TEMPERATURE;
                    
            /* Low pass filter the measured ADC counts of Vth */         
            filterOutputVth = (adcResultVTH + (FILTER_COEFFICIENT_TEMPERATURE - 1) * filterOutputVth) / FILTER_COEFFICIENT_TEMPERATURE;
                        
            /* Calculate thermistor resistance */
            thermistorResistance = Thermistor_GetResistance(filterOutputVref, filterOutputVth);           
            
            /* Calculate temperature in degree Celsius using the Component API */
            temperature = Thermistor_GetTemperature(thermistorResistance);

             if(temperature>2549){
             n1=2;
            } 
            }
            while (n1==2){
             Fan_Write(1);
             Ligth_Write(0);
        uint16_t Temp1 = temperature;
        sprintf(stringBuffer, "%d",Temp1);
        UART_UartPutString(stringBuffer);        
        CyDelay(20);
        adcResultVREF = ADC_GetResult16(ADC_CHANNEL_VREF);
            adcResultVTH = ADC_GetResult16(ADC_CHANNEL_VTH);
            
            /* Low pass filter the measured ADC counts of Vref */            
            filterOutputVref = (adcResultVREF + (FILTER_COEFFICIENT_TEMPERATURE - 1) * filterOutputVref) / FILTER_COEFFICIENT_TEMPERATURE;
                    
            /* Low pass filter the measured ADC counts of Vth */         
            filterOutputVth = (adcResultVTH + (FILTER_COEFFICIENT_TEMPERATURE - 1) * filterOutputVth) / FILTER_COEFFICIENT_TEMPERATURE;
                        
            /* Calculate thermistor resistance */
            thermistorResistance = Thermistor_GetResistance(filterOutputVref, filterOutputVth);           
            
            /* Calculate temperature in degree Celsius using the Component API */
            temperature = Thermistor_GetTemperature(thermistorResistance);

             if(temperature<2501){
             n1=1;
            } 
            }
            /* Turn ON Ligth and turn OFF fan*/
            
            
            
            
                   
			/* Enter critical section to check if I2C bus is busy or not */
            interruptState = CyEnterCriticalSection();
            
        	if(!(EZI2C_EzI2CGetActivity() & EZI2C_EZI2C_STATUS_BUSY))
        	{
                /* Update I2C Buffer */
                i2cBuffer.Rth = thermistorResistance;
                i2cBuffer.temperature = temperature;
                i2cBuffer.Vth = filterOutputVth;
            }
			
			/* Exit critical section */
            CyExitCriticalSection(interruptState);
        }
    }
}

/*******************************************************************************
* Function Name: void InitResources(void)
********************************************************************************
*
* Summary:
*  This function initializes all the hardware resources
*
* Parameters:
*  None
*
* Return:
*  None
*
* Side Effects:
*   None
*******************************************************************************/
void InitResources(void)
{
    /* Start EZI2C Slave Component and initialize buffer */
    EZI2C_Start();
    EZI2C_EzI2CSetBuffer1(sizeof(i2cBuffer), READ_WRITE_BOUNDARY, (uint8 *)&i2cBuffer);
        
    /* Start the Scanning SAR ADC Component and start conversion */
    ADC_Start();
    ADC_StartConvert();
    UART_Start();
    /* Start Reference buffer */
    VrefBuffer_Start();
    
    /* Start Programmable Voltage Reference */
    PVref_Start();
    
    /* Enable Programmable Voltage Reference */
    PVref_Enable();
}

/* [] END OF FILE */

MATLAB Code

MATLAB
This is to get data from PSoC
Thanks PSoC Latinoamérica
serial_PSoC=serial('COM4','BaudRate',9600,'Parity','none','DataBits',8,'StopBits',1); %declaración de los parámetros de puerto serial
set(serial_PSoC,'InputBufferSize',4); %número de datos que se van a recibir en este caso yo estoy recibiendo por ejemplo 12.65
fopen(serial_PSoC); 
contador=1; %inicializar un contador que se usa para llenar las posiciones de un vector donde se almacena cada dato recibido por el puerto serial
figure('Name','Conrolador ON/OFF Para generar la señal cuadrada de reconocimiento')        %Iniciar la ventana donde estará la gráfica 
title('Grafica Valor del sensor de temperatura');             %Título que se le da a la gráfica
xlabel('Muestras en Segundos');                                    %Nombre del Eje x
ylabel('Temperatura (0.01°C)');                                 %Nombre del Eje y
hold on                                                %Retener la gráfica para que no se abra una nueva con cada dato
Numero_Muestras=2000;

while contador<=Numero_Muestras                        %Ciclo while para rellenar el vector ADC con los valores recibidos por el puerto serial
    recepcion=fscanf(serial_PSoC,'%f')'              %Asi se recibe un valor float por el puerto serial, es un vector columna.
    ADC(contador)=recepcion(1);                        %Asignacion de el vector recepción en la posicion 1 en el vector ADC en la posición en que se encuentre el contador
    plot(ADC)                                          %grafica los valores del vector ADC
    grid on                                            %Para poner la malla en la gráfica
    ylim([0 4000]);                                     %límites inferior y superior de la grafica en el eje y
    xlim([0 Numero_Muestras]);                         %límites inferior y superior de la grafica en el eje x
    drawnow                                            %Para actualizar los parámetros de la gráfica cada vez que pasa por el loop, ya que si no se pone
                                                       %unicamente con la función plot la imprimir{ia hasta que el loop se acabe
    contador=contador+1;                               %se modifica el contador para rellenar la siguiente posicion del vector ADC
    
    if contador>Numero_Muestras                       %condición para reiniciar el contador cuando se llega al número de muestras total                    
        hold off                                       %para "despegarse" de la gráfica un momento mientras el contador toma su valor inicial
                                                       %y asi cuando el loop vuelva a iniciarse se dara un efecto de osciloscopio                                                      %loop vuelva a
fclose(serial_PSoC);                                    %asi se cierra el puerto
delete(serial_PSoC);                                   %así se borra el puerto de la memoria de matlab
    end
end
    

PID

C/C++
This is the PID made in MATLAB
/* Header File Includes */
#include <project.h>
#include <stdio.h>
#define ADC_CHANNEL_VREF			(0u)
#define ADC_CHANNEL_VTH				(1u)
#define LED_ON						(0u)
#define LED_OFF						(1u)
#define TEMPERATURE_THRESHOLD_HIGH	(3000)
#define TEMPERATURE_THRESHOLD_LOW	(2500)
/* IIR Filter coefficients for each signal */
/* Cut off frequency = fs/(2 * pi * iir_filter_constant).  In this project fs ~= 1 ksps.
This results in a cut-off frequency of 4.97 Hz.  We are using IIR filter as FIR requires 
more order of filter to get the same cut-off frequency*/
#define FILTER_COEFFICIENT_TEMPERATURE	(32u)
/* EzI2C Read/Write Boundary */
#define READ_WRITE_BOUNDARY         (0u)
#define CAPACITANCE_AT_55_RH        (1800)
/* Sensitivity numerator and denominator indicate sensitivity of the sensor */
#define SENSITIVITY_NUMERATOR       (31)
#define SENSITIVITY_DENOMINATOR     (100)
/* Value of reference capacitor.  Note that this value includes the pin capacitance
    and the physical 180pF reference capacitor */
#define CREF                        (1930)
/* Offset Capacitance */
#define COFFSET                     (150)
/* This is raw count equivalent to trace capacitance */
#define OFFSETCOUNT                 (1536)
#define BUFFERSIZE                  (8)
/* Nominal humidity 55% */
#define NOMINAL_HUMIDITY            (550)
#define HUMIDITY_0_PERCENT          (0)
#define HUMIDITY_100_PERCENT        (1000)
#define HUMIDITY_50                 (500)   

/* Structure that holds the temperature sensor (thermistor) data                 */
/* Use __attribute__((packed)) for GCC and MDK compilers to pack structures      */
/* For other compilers use the corresponding directive.                          */
/* For example, for IAR use the following directive                              */
/* typedef __packed struct {..}struct_name;                                      */
typedef struct __attribute__((packed))
{
	int16 Vth;					/* Voltage across thermistor */
	uint16 Rth;					/* Thermistor resistance */
	int16 temperature;			/* Measured temperature */
    uint16 humidityRawCounts;	/* Raw count from CapSense Component for the humidity sensor */
	uint16 capacitance;			/* Capacitance of the humidity sensor */
	uint16 humidity;			/* Measured humidity */
	uint16 rawCountsRefCap;     /* Raw count from CapSense Component for the Reference capacitor */
}temperature_sensor_data;

/* Function Prototypes */
void InitResources(void);
__inline uint16 CalculateCapacitance(uint16 rawCounts, uint16 refSensorCounts);
__inline uint16 CalculateHumidity(uint16 capacitance);
/* Declare the i2cBuffer to exchange sensor data between Bridge Control 
Panel (BCP) and PSoC Analog Coprocessor */
temperature_sensor_data i2cBuffer = {0, 0, 0, 0, 0, 0, 0};

/*******************************************************************************
* Function Name: main
********************************************************************************
*
* Summary:
*  This function initializes all the resources, and in an infinite loop, measures the temperature from the sensor 
*  readings and to send the data over I2C.
*
* Parameters:
*  None
*
* Return:
*  int
*
* Side Effects:
*   None
*******************************************************************************/
int main()
{
    char stringBuffer[32u];
    /* Variables to hold the the ADC readings */
    int16 adcResultVREF, adcResultVTH;
    char setpoint;
    char m1=0,m2=0,m3=0,m4=0,m5=0,m6=0;
    char error;
    
    /* Filter input and output variables for Vref and Vth measurements */
    int16 filterOutputVref=0;
    int16 filterOutputVth=0;
    
    /* Variables to hold calculated resistance and temperature */
    int16 thermistorResistance, temperature;
    
    /* Variable to store the status returned by CyEnterCriticalSection()*/
    uint8 interruptState = 0;
    /* Variable to hold calculated PWM duty cycle */
    uint16 pwmDutyCycle;
    
    /* Enable global interrupts */
    CyGlobalIntEnable;
    
    /* Initialize hardware resources */
    InitResources();

    /* Infinite Loop */
    for(;;)
    {
        /* Check if the ADC data is ready */
        if(ADC_IsEndConversion(ADC_RETURN_STATUS))
        {
            /* Read the ADC result for reference and thermistor voltages */
            adcResultVREF = ADC_GetResult16(ADC_CHANNEL_VREF);
            adcResultVTH = ADC_GetResult16(ADC_CHANNEL_VTH);
            
            /* Low pass filter the measured ADC counts of Vref */            
            filterOutputVref = (adcResultVREF + (FILTER_COEFFICIENT_TEMPERATURE - 1) * filterOutputVref) / FILTER_COEFFICIENT_TEMPERATURE;
                    
            /* Low pass filter the measured ADC counts of Vth */         
            filterOutputVth = (adcResultVTH + (FILTER_COEFFICIENT_TEMPERATURE - 1) * filterOutputVth) / FILTER_COEFFICIENT_TEMPERATURE;
                        
            /* Calculate thermistor resistance */
            thermistorResistance = Thermistor_GetResistance(filterOutputVref, filterOutputVth);           
            
            /* Calculate temperature in degree Celsius using the Component API */
            temperature = Thermistor_GetTemperature(thermistorResistance);
            
            /* Turn ON Blue LED if Temperature is <= 25°C */ 
            if (temperature <= TEMPERATURE_THRESHOLD_LOW)
            {
                Pin_LED_Blue_Write(LED_ON);
                Pin_LED_Red_Write(LED_OFF);
            }
            /* Turn ON both Blue and Red LEDs if the temperature is >25°C and <=30°C */
            else if ((temperature > TEMPERATURE_THRESHOLD_LOW) && (temperature < TEMPERATURE_THRESHOLD_HIGH)) 
            {
                Pin_LED_Blue_Write(LED_ON);
                Pin_LED_Red_Write(LED_ON);
            }
            /* Turn ON Red LED if temperature is >30°C */
            else 
            {
                Pin_LED_Blue_Write(LED_OFF);
                Pin_LED_Red_Write(LED_ON);
            }   

            
			/* Enter critical section to check if I2C bus is busy or not */
            interruptState = CyEnterCriticalSection();
            
        	if(!(EZI2C_EzI2CGetActivity() & EZI2C_EZI2C_STATUS_BUSY))
        	{
                /* Update I2C Buffer */
                i2cBuffer.Rth = thermistorResistance;
                i2cBuffer.temperature = temperature;
                i2cBuffer.Vth = filterOutputVth;
                i2cBuffer.humidityRawCounts = CSD_BUTTON0_SNS0_RAW0_VALUE;
                i2cBuffer.rawCountsRefCap = CSD_BUTTON0_SNS1_RAW0_VALUE;
                /* Convert raw counts to capacitance */
                i2cBuffer.capacitance = CalculateCapacitance(i2cBuffer.humidityRawCounts, i2cBuffer.rawCountsRefCap);
                /* Calculate humidity */
                i2cBuffer.humidity = CalculateHumidity(i2cBuffer.capacitance);

            }
			
			/* Exit critical section */
            CyExitCriticalSection(interruptState);
        }

        /* Update the PWM duty cycle */
        
        uint16_t Temp1 = temperature;
        sprintf(stringBuffer, "%d",Temp1);  
        UART_UartPutString(stringBuffer);
        sprintf(stringBuffer, "%d",CalculateHumidity(i2cBuffer.capacitance));
        UART_UartPutString(stringBuffer);
        setpoint=UART_UartGetChar();
        //Controlador Pseudocodigo
        error=setpoint-temperature;
        m3=error;
        m1=m2+4.3381*m3-4.3381*(0.9983)*m4;
        m5=m4;
        m4=m3;
        m2=m1;
        VDAC_SetValue(m1);
        
        //Delay para generar el tiempo de muestreo
        CyDelay(20);
    }
}

/*******************************************************************************
* Function Name: void InitResources(void)
********************************************************************************
*
* Summary:
*  This function initializes all the hardware resources
*
* Parameters:
*  None
*
* Return:
*  None
*
* Side Effects:
*   None
*******************************************************************************/
void InitResources(void)
{
    /* Start EZI2C Slave Component and initialize buffer */
    EZI2C_Start();
    EZI2C_EzI2CSetBuffer1(sizeof(i2cBuffer), READ_WRITE_BOUNDARY, (uint8 *)&i2cBuffer);
        
    /* Start the Scanning SAR ADC Component and start conversion */
    ADC_Start();
    ADC_StartConvert();
    UART_Start();
    VDAC_Start();
    /* Start Reference buffer */
    VrefBuffer_Start();
    
    /* Start Programmable Voltage Reference */
    PVref_Start();
    
    /* Enable Programmable Voltage Reference */
    PVref_Enable();
        /* Start CapSense Component */
    CSD_Start();
    
    //Start PWM 
}

__inline uint16 CalculateCapacitance(uint16 rawCounts, uint16 refsensorCounts)
{
    return (uint16)((float)(rawCounts - OFFSETCOUNT) * (CREF - COFFSET) / (float)(refsensorCounts - OFFSETCOUNT));
}
__inline uint16 CalculateHumidity(uint16 capacitance)
{
    int16 humidity;
    int16 delta;

    /* Find capacitance difference from nominal capacitance at 55% RH */
    delta = capacitance - CAPACITANCE_AT_55_RH;
    
    /* Calculate humidity from capacitance difference and sensor sensitivity */
    humidity = ((delta * SENSITIVITY_DENOMINATOR) / SENSITIVITY_NUMERATOR) + NOMINAL_HUMIDITY;
    
    /* If humidity is less than zero, limit it to 0; If humidity is greater than 1000 (100%), limit to 1000 */
    humidity = (humidity < HUMIDITY_0_PERCENT) ? HUMIDITY_0_PERCENT : (humidity > HUMIDITY_100_PERCENT) ? HUMIDITY_100_PERCENT : humidity;

    /* Return Humidity value */
    return humidity;
}

/* [] END OF FILE */

Credits

Jeisson David Torrecilla A

Jeisson David Torrecilla A

2 projects • 5 followers

Comments