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:
- 0:b6fd8ca8bfbf
- Child:
- 1:219e882c32eb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Wed Sep 30 14:42:56 2015 +0000
@@ -0,0 +1,335 @@
+#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
\ No newline at end of file