UDS Team / Mbed 2 deprecated Nucleo_UDS_controller_Alberto_version

Dependencies:   Menu PID_v2 PinDetect QEI TextLCD Thermistor mbed

main.cpp

Committer:
walter76
Date:
2015-09-30
Revision:
0:b6fd8ca8bfbf
Child:
1:219e882c32eb

File content as of revision 0:b6fd8ca8bfbf:

#include "mbed.h"
#include "TextLCD.h"
#include "PID.h"
#include "QEI.h"

#define TPIT_MIN     70
#define TPIT_MAX     250
#define TMEAT_MIN    50
#define TMEAT_MAX    120
#define TPIT_FAIL    300
#define TMEAT_FAIL   250
#define MAX_HOURS    24
 
/*

 This FW implements a PID temperature controller specifically designed for Ugly Drum Smokers (UDS)
 and uses a K-type termocouple as pit temperature sensors and a PWM-controlled fan to regulate the
 airflow at the intake.
 A second K-type termocouple is used to monitor the meat temperature, while a countdown timer takes care
 of the cooking time.
 The required HW consists of:
 - 1x STM32 F411RE Nucleo board
 - 1x 20x4 Text LCD
 - 1x Quadrature rotary encoder
 - 1x Pushbutton (if not embedded in the encoder)
 - 2x MAX6675 modules
 - 2x K-type termocouples (pit & meat)
 - 1x Buzzer
 - 1x 12V fan
 - 1x N-MOS capable of driving the fan
 - 1x fly-wheeling diode

*/

uint8_t Hrs=0, Min=0, Sec=0, warning=0, set_mode=1, timeout=0;
float FanSpeed, Tpit, Tmeat, Tset, Talm;
float Vpot;

DigitalOut  RLED    (PC_5);     // Pin 2 of CN10 (MORPHO connector, debug only)
DigitalOut  YLED    (PC_6);     // Pin 4 of CN10 (MORPHO connector, debug only)
DigitalOut  GLED    (PC_8);     // Pin 6 of CN10 (MORPHO connector, debug only)

PwmOut      FAN     (D3);       // D3=PB3 --> PMW output (FAN control)
AnalogIn    POT1    (A0);       // A0=PA0 <-- Pit setpoint potentiometer (debug only)
AnalogIn    POT2    (A1);       // A1=PA1 <-- Meat alarm potentiometer (debug only)

DigitalOut  TC_CLK  (D8);       // D4=PB5 --> MAX6675 CLK (to both chips)
//DigitalOut  TC_CS1  (D9);       // D5=PB4 --> MAX6675 CS (chip 1)
DigitalOut  TC_CS1  (A5);       // A0=PC0 --> MAX6675 CS (chip 1)
DigitalOut  TC_CS2  (D2);       // D2=PA10 --> MAX6675 CS (chip 2)
DigitalIn   TC_SDO  (D4);       // D8=PA9 <-- MAX6675 SDO (from both chips)

DigitalOut  BUZZER  (A2);       // A2=PA4 --> self-oscillating buzzer
PwmOut      ALM     (D9);
InterruptIn Button  (D7);       // D7=PA8 <-- Hold/Set pushbutton

PID myPID(0.003, 60.0, 0.0, 0.5);   // Specify Kc, Ti, Td & refresh rate
QEI Wheel(D5, D6, NC, 16);          // quadrature encoder
TextLCD MyLCD(D15, D14, D13, D12, D11, D10, TextLCD::LCD20x4); //20x4 LCD connection

Ticker Sec_Beat;        // timer ticker
Ticker LCD_Refresh;     // LCD refresh ticker


// ------------------- Prototypes -----------------------

void Button_Pressed(void);
void Timer_tick(void);
void Update_LCD(void);
int MAX6675_GetTemp(int);


// -------------------- Routines ------------------------

void Button_Pressed() {
    
    set_mode++;
    if(set_mode>3) set_mode = 0; 
    Button.fall(NULL);
    Wheel.reset();        
}


// -------------------------------------------------------------

void Timer_tick() 
{
                     
    if((Hrs==0)&&(Min==0)&&(Sec==0))
        timeout = 1;
    else 
    {    
        timeout = 0;
        BUZZER = 0;
        
        if ((!set_mode)&&(!timeout)) 
        {    
            Sec--;
            if((Hrs==0)&&(Min==0)&&(Sec==0)) 
                timeout = 1;
            else if((Sec==0)||(Sec>60))
            {
                Sec=59;
                if(Min>0) 
                    Min--;
                else if (Hrs>0)
                {
                    Min=59;
                    Hrs--;                
                } 
            }
        }            
    }
     
    Tmeat = (float)(MAX6675_GetTemp(0)/4); // read meat & pit temperature
    Tpit = (float)(MAX6675_GetTemp(1)/4);  
    
    if(timeout||warning)    // toggle the buzzer
        BUZZER=!BUZZER;
               
    return;
}

// -------------------------------------------------------------

void Update_LCD(void) {
    
    
    switch(set_mode)
    {
                  
    case 0:
          
        MyLCD.locate(19,0);
        MyLCD.printf(" ");
        MyLCD.locate(19,1);
        MyLCD.printf(" ");
        MyLCD.locate(19,2);
        MyLCD.printf(" ");                
        
    break;

    case 1:    // set cooking time
          
        MyLCD.locate(19,0);
        MyLCD.printf("*");
        Min = Sec = 0;
        Hrs = int(Wheel.getPulses());
        if((Hrs>MAX_HOURS))
        {  
            Wheel.reset();
            Hrs = MAX_HOURS;
        }
        
    break; 
    
    case 2:     // set meat temperature alarm
          
        MyLCD.locate(19,1);
        MyLCD.printf("*");
        Talm = TMEAT_MIN + int(Wheel.getPulses());
        if((Talm<TMEAT_MIN)||(Talm>TMEAT_MAX))
        {  
            Wheel.reset();
            Talm=TMEAT_MIN;
        }
        
    break;
    
    case 3:     // set pit target temperature
          
        MyLCD.locate(19,2);
        MyLCD.printf("*");
        Tset = TPIT_MIN + int(Wheel.getPulses());
        if((Tset<TPIT_MIN)||(Tset>TPIT_MAX))
        {  
            Wheel.reset();
            Tset=TPIT_MIN;
        }
        
    break;

    default:
        set_mode = 0;   
           
    };
                
    //Tmeat = (float)(MAX6675_GetTemp(0)/4);
    //Tpit = (float)(MAX6675_GetTemp(1)/4);
    //Tmeat = TMEAT_MIN + POT1*(TMEAT_MAX-TMEAT_MIN)-5;   // debug only
    //Tpit = 2+TPIT_MIN + POT2*(TPIT_MAX-TPIT_MIN);    // debug only        

    //-------------------------------------------------

    if(Tmeat>Talm)      // Meat is ready!
        warning = 1;        
    else
        warning = 0;        
        
    //-------------------------------------------------
    
    if(warning||timeout) // in case of a warning or timeout
    { 
        MyLCD.locate(0,3);
        MyLCD.printf(" ---- WARNING! ---- ");

        //FAN.write(0);     // stop the fan (optional)
    }
    else // otherwise
    {
        BUZZER = 0;             // buzzer off
        FAN.write(FanSpeed);    // update fan speed
        MyLCD.locate(0,3);
        MyLCD.printf(" FAN SPEED:         ");
        MyLCD.locate(12,3);
        MyLCD.printf("%2.0f%% ", FanSpeed*100);        
    }         
    
    //-------------------------------------------------
            
    if(Tpit>300)    // if Tpit is too high
    { 
        MyLCD.locate(0,2);  
        MyLCD.printf(" CHECK PIT PROBE!   ");
        FAN.write(0);     // stop the fan
        warning=1;
    }
    else // otherwise show pit temperature and setpoint
    {
        warning=0;
        MyLCD.locate(0,2);  
        MyLCD.printf(" TPIT=             ");
        MyLCD.locate(8,2);  
        MyLCD.printf("%2.0f ", Tpit);        
        MyLCD.locate(13,2);  
        MyLCD.printf("(%2.0f) ", Tset);        
    }      
               
 
    //-------------------------------------------------
 
    if(Tmeat>200)    // if Tmeat is too high
    { 
        MyLCD.locate(0,1);
        MyLCD.printf(" CHECK MEAT PROBE!   ");
        FAN.write(0);     // stop the fan
        warning=1;
    }
    else // otherwise show meat temperature and alarm threshold 
    {
        warning=0;
        MyLCD.locate(0,1);
        MyLCD.printf(" TMEAT=            ");
        MyLCD.locate(8,1);
        MyLCD.printf("%2.0f ", Tmeat);        
        MyLCD.locate(13,1);
        MyLCD.printf("(%2.0f) ", Talm);        
    }      
   
   
    MyLCD.locate(0,0);
    MyLCD.printf(" TIMER: %2d:%2d:%2d ", Hrs, Min, Sec);
   
    Button.fall(&Button_Pressed); // enable button interrupt  
}


// -------------------------------------------------------------

int MAX6675_GetTemp(int chip)
{
  int Temp=0, mask=32768;
  int i; 
        
  if(chip==0)
    TC_CS1 = 0; // select chip #1
  else
    TC_CS2 = 0;  // select chip #2
  wait_ms(1);
  for(i=0; i<16; i++){   
      
   TC_CLK = 1;  // CLK high    
   if(TC_SDO == 1 ) Temp = Temp | mask;  
   wait_ms(1); 
   TC_CLK = 0;  // CLK low 
   wait_ms(1);
   mask = mask/2;  
  }     
  wait_ms(1);
  TC_CS1 = 1;  // Both CS high
  TC_CS2 = 1;
  
  Temp=((Temp>>3)&0x0FFF);

  return(Temp);
  
}


// -------------------------------------------------------------
// -------------------------------------------------------------
// -------------------------------------------------------------

int main() {

  FAN.period_us(100);       // set initial fan PWM period and duty-cycle
  FAN.write(0.1);  
  
  ALM.period_us(2000);      // set initial ALM period and duty-cycle
  ALM.write(0.2);   
  
  TC_SDO.mode(PullDown);    // enable pull-down on TC_SDO
  Button.mode(PullUp);      // enable pushbutton pull-up   
    
  Wheel.reset();            // reset quadrature encoder 
    
  MyLCD.cls();              // clear LCD

  Sec_Beat.attach(&Timer_tick, 1);      // configure tickers
  LCD_Refresh.attach(&Update_LCD, 0.2);
    
  myPID.setInputLimits(0, 300);     // set PID in/out ranges 
  myPID.setOutputLimits(0, 1);     

  Button.fall(&Button_Pressed);  // enable button interrupt
 
  while(1) {
              
    myPID.setSetPoint(Tset);            // update pit setpoint (PID reference)                 
    myPID.setProcessValue(Tpit);        // update pit temperature (PID input)
    FanSpeed = float(myPID.compute());  // calculate fan speed (PID output)
          
  } //while
    
} //main