Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: Menu PID_v2 PinDetect QEI TextLCD Thermistor mbed
Diff: main.cpp
- Revision:
- 1:219e882c32eb
- Parent:
- 0:b6fd8ca8bfbf
- Child:
- 3:884bfa90a09d
--- a/main.cpp Wed Sep 30 14:42:56 2015 +0000
+++ b/main.cpp Fri Nov 27 10:50:06 2015 +0000
@@ -2,15 +2,20 @@
#include "TextLCD.h"
#include "PID.h"
#include "QEI.h"
+#include "Menu.h"
+#include "PinDetect.h"
+#include "Thermistor.h"
-#define TPIT_MIN 70
-#define TPIT_MAX 250
+#define TPIT_MIN 0.0
+#define TPIT_MAX 250.0
+#define TCOAL_MIN 0.0
+#define TCOAL_MAX 1000.0
#define TMEAT_MIN 50
#define TMEAT_MAX 120
-#define TPIT_FAIL 300
-#define TMEAT_FAIL 250
#define MAX_HOURS 24
-
+
+#define PULLUP_MEAT 10000.0
+
/*
This FW implements a PID temperature controller specifically designed for Ugly Drum Smokers (UDS)
@@ -32,34 +37,83 @@
*/
-uint8_t Hrs=0, Min=0, Sec=0, warning=0, set_mode=1, timeout=0;
-float FanSpeed, Tpit, Tmeat, Tset, Talm;
+int Hrs=0, Min=0, Sec=0, warning=0, timeout=0;
+int TimerRunning = 0;
+float FanSpeed, TcoalPID, Tcoal, Tpit, Tmeat, Tset;
+float Talm = 200.0;
+float TcoalSet, DfanSet;
float Vpot;
+uint8_t req_LCD_update;
+
+uint8_t displayLine;
+
+int pitPidMode = 0;
+int coalPidMode = 0;
+
+char stringa[20];
+
+void UpdatePidMode(void);
+void SetCoalTemp(void);
+void SetFanDuty(void);
+void SetPIDK(void);
+void ResetSeconds(void);
+
+float coalKc = 0.1, coalTauI = 6.0;
+float pitKc = 0.1, pitTauI = 60.0;
+
+MenuNode MNhead(NULL,"Exit");
+MenuNode MNpid(&MNhead,"PID settings");
+//MenuNode MNpitap(&MNpid,"Pit Auto PID");
+MenuNode MNpitPidTarget(&MNhead,"Pit Target temp",(void *) &Tset,'f',NULL,1.0,TPIT_MIN,TPIT_MAX);
-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)
+MenuNode MNpitPidMode(&MNpid,"Pit PID mode",(void *) &pitPidMode,'i',&UpdatePidMode,1.0,0.0,1.0,(char *[]){"Manual","Auto"});
+MenuNode MNcoalPidMode(&MNpid,"Coal PID mode",(void *) &coalPidMode,'i',&UpdatePidMode,1.0,0.0,1.0,(char *[]){"Manual","Auto"});
+
+MenuNode MNpitPidOutput(&MNpid,"Coal Temp (man)",(void *) &TcoalSet,'f',&SetCoalTemp,5.0,TCOAL_MIN,TCOAL_MAX);
+MenuNode MNcoalPidOutput(&MNpid,"Fan Speed (man)",(void *) &DfanSet,'f',&SetFanDuty,0.05,0.0,1.0);
+MenuNode MNcoalKc(&MNpid,"Coal Kc",(void *) &coalKc,'e',&SetPIDK,1.25,0.0001,100.0);
+MenuNode MNcoalTauI(&MNpid,"Coal TauI",(void *) &coalTauI,'e',&SetPIDK,1.25,1.0,1000.0);
+MenuNode MNpitKc(&MNpid,"Pit Kc",(void *) &pitKc,'e',&SetPIDK,1.25,0.0001,100.0);
+MenuNode MNpitTauI(&MNpid,"Pit TauI",(void *) &pitTauI,'e',&SetPIDK,1.25,1.0,10000.0);
+
+MenuNode MNtmr(&MNhead,"Timer settings");
+MenuNode MNtmrRun(&MNtmr,"Timer mode",(void *) &TimerRunning,'i',NULL,1.0,0.0,2.0,(char *[]){"Stop","Countdown", "Timer"});
+MenuNode MNtmrHrs(&MNtmr,"Hours",(void *) &Hrs,'i',&ResetSeconds,1.0,0.0,24.0);
+MenuNode MNtmrMin(&MNtmr,"Minutes",(void *) &Min,'i',&ResetSeconds,5.0,0.0,55.0);
-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)
+MenuNode MNtalm(&MNhead,"Meat Target temperature", &Talm,'f', NULL, 1.0, 30.0, 150.0);
+
+Menu MN(&MNhead);
+
+Thermistor MeatThermistor(25.0, 100000.0, 3950.0);
+
-DigitalOut TC_CLK (D8); // D4=PB5 --> MAX6675 CLK (to both chips)
-//DigitalOut TC_CS1 (D9); // D5=PB4 --> MAX6675 CS (chip 1)
+//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 (D5); // D3=PB3 --> PMW output (FAN control)
+
+DigitalOut TC_CLK (D4); // D4=PB5 --> MAX6675 CLK (to both chips)
+
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)
+DigitalIn TC_SDO (D8); // D8=PA9 <-- MAX6675 SDO (from both chips)
-DigitalOut BUZZER (A2); // A2=PA4 --> self-oscillating buzzer
+//DigitalOut BUZZER (A2); // A2=PA4 --> self-oscillating buzzer
PwmOut ALM (D9);
-InterruptIn Button (D7); // D7=PA8 <-- Hold/Set pushbutton
+
+PinDetect Button (D7); // D7=PA8 <-- Hold/Set pushbutton
+
+AnalogIn MeatIn (A0);
-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
+PID pitPID(0.1, 60.0, 0.0, 1.0); // Specify Kc, Ti, Td & refresh rate
+PID coalPID(0.1, 6.0, 0.0, 1.0); // Specify Kc, Ti, Td & refresh rate
+QEI Wheel(D3, D6, NC, 16, QEI::X4_ENCODING); // quadrature encoder
+TextLCD MyLCD(D15, D14, D13, D12, D11, D10, TextLCD::LCD16x2); //20x4 LCD connection
Ticker Sec_Beat; // timer ticker
-Ticker LCD_Refresh; // LCD refresh ticker
+//Ticker decSecBeat; // 1/10th sec beat
// ------------------- Prototypes -----------------------
@@ -69,267 +123,356 @@
void Update_LCD(void);
int MAX6675_GetTemp(int);
+void ResetSeconds(void)
+{
+ Sec = 0;
+}
// -------------------- Routines ------------------------
+void SetPIDK(void)
+{
+ pitPID.setTunings(pitKc, pitTauI, 0.0);
+ coalPID.setTunings(coalKc, coalTauI, 0.0);
+}
-void Button_Pressed() {
-
- set_mode++;
- if(set_mode>3) set_mode = 0;
- Button.fall(NULL);
- Wheel.reset();
+void SetCoalTemp(void)
+{
+ if(!pitPID.isAuto())
+ pitPID.setOutput(TcoalSet);
+}
+
+void SetFanDuty(void)
+{
+ if(!coalPID.isAuto())
+ coalPID.setOutput(DfanSet);
}
-// -------------------------------------------------------------
-void Timer_tick()
+void Button_Pressed()
{
-
- 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--;
- }
- }
- }
+
+ if(!MN.isLeaf())
+ MN.descend();
+ else
+ {
+ if(MN.isSelect())
+ MN.setEdit();
+ else if(MN.isEdit())
+ {
+ MN.resetEdit();
+ MN.execFun();
+ }
}
-
- Tmeat = (float)(MAX6675_GetTemp(0)/4); // read meat & pit temperature
- Tpit = (float)(MAX6675_GetTemp(1)/4);
+
+ req_LCD_update = 1;
+ Wheel.reset();
- if(timeout||warning) // toggle the buzzer
- BUZZER=!BUZZER;
-
- return;
+}
+
+
+void UpdatePidMode(void)
+{
+ coalPID.setMode(coalPidMode);
+ pitPID.setMode(pitPidMode);
}
// -------------------------------------------------------------
-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;
+void Timer_tick()
+{
+ float Rmeat;
- 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((Hrs==0)&&(Min==0)&&(Sec==0) && (TimerRunning == 1))
+ timeout = 1;
+ else
+ {
+ timeout = 0;
- 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;
+ if (TimerRunning == 1)
+ {
+ 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--;
+ }
+ }
+ }
+ else if ((TimerRunning == 2) )
+ {
+ Sec++;
+ if((Sec>=60))
+ {
+ Sec=0;
+ Min++;
+ if(Min>=60)
+ {
+ Min = 0;
+ Hrs++;
+ }
+ }
+ }
}
- 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
+
+ Tcoal = (float)(MAX6675_GetTemp(0)/2); // read meat & pit temperature
+ Tpit = (float)(MAX6675_GetTemp(1)/2);
+
+ pitPID.setProcessValue(Tpit);
+ TcoalPID = pitPID.compute();
+ coalPID.setSetPoint( TcoalPID );
+
+ coalPID.setProcessValue(Tcoal);
+ FanSpeed = coalPID.compute();
+
+ FAN.write(FanSpeed);
+
+ if(MN.isHead())
+ req_LCD_update = 1;
+
+
+ Rmeat = MeatIn.read();
+ Rmeat = (Rmeat * PULLUP_MEAT) / (1 - Rmeat);
+
+ Tmeat = MeatThermistor.trans_R2T(Rmeat);
+
+
+ if(Tmeat>Talm || timeout) // Meat is ready!
+ warning = 1;
+ else
+ warning = 0;
+
+
+ return;
}
// -------------------------------------------------------------
+int saturate(int data, int min, int max)
+{
+ if(data > max)
+ return max;
+ else if (data < min)
+ return min;
+ else return data;
+}
+
+char * idleString(int n, char *dst)
+{
+ int tcoal_l, tpit_l, tmeat_l;
+
+ switch(n)
+ {
+
+ case 0:
+ sprintf(dst,"%02d:%02d:%02d Tgt %02dC",Hrs,Min,Sec,int(Talm));
+ break;
+ case 1:
+ tcoal_l = saturate(int(Tcoal),0,999);
+ tpit_l = saturate(int(Tpit),0,999);
+ tmeat_l = saturate(int(Tmeat),0,999);
+ sprintf(dst,"C%3dC P%3dC M%2dC",tcoal_l,tpit_l,tmeat_l);
+ break;
+ case 2:
+ sprintf(dst,"d%3d CP%4dC ",int(FanSpeed * 100), int(TcoalPID));
+ break;
+ case 3:
+ sprintf(dst,"Ciao Mamma");
+ break;
+ }
+
+ return dst;
+}
+
+
+void Update_LCD(void)
+{
+
+
+ if(MN.isHead())
+ {
+
+ MyLCD.locate(0,0);
+ MyLCD.printf(idleString(displayLine,stringa));
+ MyLCD.locate(0,1);
+ MyLCD.printf(idleString((displayLine+1)&0x03,stringa));
+
+ }
+ else
+ {
+ MyLCD.locate(0,0);
+ MyLCD.printf("%-16s",MN.getText());
+ if(MN.isSelect())
+ {
+ MyLCD.locate(0,1);
+ MyLCD.printf("%-16s",MN.getNextText());
+ }
+ else
+ {
+ MyLCD.locate(0,1);
+ MyLCD.printf("%-16s",MN.getDataText(stringa));
+ }
+ }
+
+
+ //Button.fall(&Button_Pressed);
+
+#if 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
+}
+
+#endif
+}
+
+// -------------------------------------------------------------
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);
+ 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++) {
- return(Temp);
-
+ 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() {
+int main()
+{
+
+ FAN.period_us(500); // set initial fan PWM period and duty-cycle
+ FAN.write(0.1);
+
+ pitPID.setInputLimits(TPIT_MIN, TPIT_MAX);
+ pitPID.setOutputLimits(TCOAL_MIN, TCOAL_MAX);
+
+ coalPID.setInputLimits(TCOAL_MIN, TCOAL_MAX);
+ coalPID.setOutputLimits(0.0, 1.0);
+
+ ALM.period_us(500); // set initial ALM period and duty-cycle
+ ALM.write(0.01);
- 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
+ TC_SDO.mode(PullDown); // enable pull-down on TC_SDO
+
+ Button.mode(PullUp); // enable pushbutton pull-up
+
+ Button.setSampleFrequency( 20000 );
+
+ //Wheel.reset(); // reset quadrature encoder
+ Hrs = 2;
+ timeout = 0;
- Wheel.reset(); // reset quadrature encoder
-
- MyLCD.cls(); // clear LCD
+ MyLCD.cls(); // clear LCD
+
+ MyLCD.locate(0,0);
+ MyLCD.printf(__TIME__, Hrs, Min, Sec);
+ MyLCD.locate(1,1);
+ MyLCD.printf(__DATE__, Hrs, Min, Sec);
+
+
+ Sec_Beat.attach(&Timer_tick, 1); // configure tickers
+ //decSecBeat.attach(&Fast_tick, 1); // configure tickers
+ FanSpeed = 0;
- Sec_Beat.attach(&Timer_tick, 1); // configure tickers
- LCD_Refresh.attach(&Update_LCD, 0.2);
+ //Button.fall(&Button_Pressed); // enable button interrupt
+ Button.attach_deasserted( &Button_Pressed );
- myPID.setInputLimits(0, 300); // set PID in/out ranges
- myPID.setOutputLimits(0, 1);
+ while(1)
+ {
+ if(req_LCD_update) {
+ Update_LCD();
+ req_LCD_update = 0;
+ }
+
+ if(warning)
+ ALM.write(0.01);
+ else
+ ALM.write(0.0);
+
+ if(MN.isSelect())
+ {
+ if(Wheel.getPulses() > 0)
+ {
+ MN.next();
+ Wheel.reset();
+ req_LCD_update = 1;
+ }
+ else if(Wheel.getPulses() < 0)
+ {
+ MN.prev();
+ Wheel.reset();
+ req_LCD_update = 1;
+ }
+ }
+ else if(MN.isEdit())
+ {
+ if(Wheel.getPulses())
+ {
+ MN.edit(Wheel.getPulses());
+ Wheel.reset();
+ req_LCD_update = 1;
+ }
+ }
+ else if(MN.isIdle())
+ {
+ if(Wheel.getPulses() > 0)
+ {
+ displayLine++;
+ displayLine &= 0x3;
+ Wheel.reset();
+ req_LCD_update = 1;
+ }
+ else if(Wheel.getPulses() < 0)
+ {
+ displayLine--;
+ displayLine &= 0x3;
+ Wheel.reset();
+ req_LCD_update = 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
\ No newline at end of file