Implement reflow process

This commit is contained in:
Luca 2023-08-01 01:33:18 +02:00
parent 6f052edad2
commit f4b60aad42
1 changed files with 124 additions and 23 deletions

View File

@ -10,18 +10,23 @@ use cortex_m::delay::Delay;
use display_interface::DisplayError; use display_interface::DisplayError;
use embedded_graphics::{ use embedded_graphics::{
mono_font::{iso_8859_1::FONT_6X10, MonoTextStyle}, mono_font::{iso_8859_1::FONT_10X20, MonoTextStyle},
pixelcolor::BinaryColor, pixelcolor::BinaryColor,
prelude::*, prelude::*,
text::{Alignment, Text}, text::{Alignment, Baseline, Text, TextStyleBuilder},
}; };
use embedded_hal::digital::v2::{InputPin, ToggleableOutputPin}; use embedded_hal::{
digital::v2::{InputPin, OutputPin, ToggleableOutputPin},
timer::CountDown as _,
};
use fugit::RateExtU32; use fugit::{ExtU64, MicrosDurationU64, RateExtU32};
use max6675::{Error, Max6675}; use max6675::{Error, Max6675};
use nb::Error::WouldBlock;
use panic_halt as _; use panic_halt as _;
use rp_pico::{ use rp_pico::{
@ -30,6 +35,7 @@ use rp_pico::{
clocks::{self, Clock}, clocks::{self, Clock},
gpio::PinState, gpio::PinState,
i2c::I2C, i2c::I2C,
timer::CountDown,
usb::UsbBus, usb::UsbBus,
Sio, Timer, Watchdog, Sio, Timer, Watchdog,
}, },
@ -43,6 +49,22 @@ use usb_device::{bus::UsbBus as UsbBusTrait, bus::UsbBusAllocator, prelude::*};
use usbd_serial::{SerialPort, USB_CLASS_CDC}; use usbd_serial::{SerialPort, USB_CLASS_CDC};
const HYSTERESIS: u16 = 5;
const PEAK_TEMPERATURE: u16 = 240;
const PREHEAT_TEMPERATURE: u16 = 150;
const SOAK_TIME: MicrosDurationU64 = MicrosDurationU64::secs(90);
enum State<'a> {
Off,
Preheat,
Soak(CountDown<'a>),
Reflow,
Cooling,
}
fn print_serial<'a, B: UsbBusTrait>( fn print_serial<'a, B: UsbBusTrait>(
serial: &mut SerialPort<'a, B>, serial: &mut SerialPort<'a, B>,
msg: &str, msg: &str,
@ -50,13 +72,18 @@ fn print_serial<'a, B: UsbBusTrait>(
let buf = msg.as_bytes(); let buf = msg.as_bytes();
let mut pos = 0; let mut pos = 0;
let mut retry_count = 0;
while pos < buf.len() { while pos < buf.len() {
match serial.write(&buf[pos..]) { match serial.write(&buf[pos..]) {
Ok(count) => { Ok(count) => {
pos += count; pos += count;
retry_count = 0;
continue;
}
Err(UsbError::WouldBlock) if retry_count < 100 => {
retry_count += 1;
continue; continue;
} }
Err(UsbError::WouldBlock) => continue,
Err(err) => return Err(err), Err(err) => return Err(err),
} }
} }
@ -88,6 +115,7 @@ fn stringify_display_error(err: DisplayError) -> &'static str {
fn display_text<DI, SIZE>( fn display_text<DI, SIZE>(
display: &mut Ssd1306<DI, SIZE, BufferedGraphicsMode<SIZE>>, display: &mut Ssd1306<DI, SIZE, BufferedGraphicsMode<SIZE>>,
text: &str, text: &str,
baseline: Baseline,
) -> Result<(), DisplayError> ) -> Result<(), DisplayError>
where where
DI: WriteOnlyDataCommand, DI: WriteOnlyDataCommand,
@ -95,11 +123,14 @@ where
{ {
let (w, h) = display.dimensions(); let (w, h) = display.dimensions();
Text::with_alignment( Text::with_text_style(
text, text,
Point::new((w / 2).into(), (h / 2).into()), Point::new((w / 2).into(), (h / 2).into()),
MonoTextStyle::new(&FONT_6X10, BinaryColor::On), MonoTextStyle::new(&FONT_10X20, BinaryColor::On),
Alignment::Center, TextStyleBuilder::new()
.alignment(Alignment::Center)
.baseline(baseline)
.build(),
) )
.draw(display)?; .draw(display)?;
@ -153,9 +184,8 @@ fn main() -> ! {
} }
let mut buf = [0u8]; let mut buf = [0u8];
match serial.read(&mut buf[..]) { if let Ok(_) = serial.read(&mut buf[..]) {
Ok(_) => break, break;
_ => (),
} }
} }
@ -177,9 +207,8 @@ fn main() -> ! {
) )
.into_buffered_graphics_mode(); .into_buffered_graphics_mode();
let result = display.init().map_err(stringify_display_error); if let Err(err) = display.init() {
if let Err(msg) = result { let _ = print_serial(&mut serial, stringify_display_error(err));
let _ = print_serial(&mut serial, msg);
panic!(); panic!();
} }
@ -195,17 +224,41 @@ fn main() -> ! {
let mut led = pins.led.into_push_pull_output_in_state(PinState::Low); let mut led = pins.led.into_push_pull_output_in_state(PinState::Low);
let mut button_held = false;
let mut button_cooldown = timer.count_down();
button_cooldown.start(0.secs());
let mut counter = 0; let mut counter = 0;
let mut current_temperature = Option::<u16>::None;
let mut state = State::Off;
loop { loop {
delay.delay_ms(5); delay.delay_ms(5);
counter = (counter + 1) % 100; counter = (counter + 1) % 100;
if let Ok(_) = button_cooldown.wait() {
let button_pressed = button.is_low().unwrap();
if button_pressed && !button_held {
state = if let State::Off = state {
State::Preheat
} else {
State::Off
};
button_cooldown.start(500.millis());
} else {
button_cooldown.start(0.secs());
}
button_held = button_pressed;
}
if counter == 0 { if counter == 0 {
led.toggle().unwrap(); led.toggle().unwrap();
let mut bytes: [u8; 7] = [32, 32, 32, 32, 194, 176, 67]; let mut bytes: [u8; 7] = [32, 32, 32, 32, 194, 176, 67];
let text = match thermocouple.read_temperature(&mut timer.count_down()) { let text = match thermocouple.read_temperature(&mut timer.count_down()) {
Ok(mut temperature) => { Ok(mut temperature) => {
current_temperature = Some(temperature);
temperature >>= 2; temperature >>= 2;
for i in (0..3).rev() { for i in (0..3).rev() {
@ -227,14 +280,65 @@ fn main() -> ! {
display.clear_buffer(); display.clear_buffer();
if let Err(err) = display_text(&mut display, text) { if let Err(err) = display_text(&mut display, text, Baseline::Bottom) {
let _ = println_serial(&mut serial, stringify_display_error(err));
}
let state_str = match state {
State::Off => "OFF",
State::Preheat => "PREHEAT",
State::Soak(_) => "SOAK",
State::Reflow => "REFLOW",
State::Cooling => "COOLING",
};
if let Err(err) = display_text(&mut display, state_str, Baseline::Top) {
let _ = println_serial(&mut serial, stringify_display_error(err)); let _ = println_serial(&mut serial, stringify_display_error(err));
} }
} }
if button.is_low().unwrap() { if let Some(temperature) = current_temperature {
relay.toggle().unwrap(); match state {
delay.delay_ms(1000); State::Off => (),
State::Preheat => {
if temperature < PREHEAT_TEMPERATURE {
relay.set_high().unwrap();
} else {
let mut time = timer.count_down();
time.start(SOAK_TIME);
state = State::Soak(time);
}
}
State::Soak(ref mut time) => match time.wait() {
Ok(_) => state = State::Reflow,
Err(WouldBlock) => {
if temperature < PREHEAT_TEMPERATURE - HYSTERESIS {
relay.set_high().unwrap();
} else if temperature > PREHEAT_TEMPERATURE + HYSTERESIS * 2 {
state = State::Reflow;
} else if temperature > PREHEAT_TEMPERATURE + HYSTERESIS {
relay.set_low().unwrap();
}
}
Err(_) => state = State::Off,
},
State::Reflow => {
if temperature < PEAK_TEMPERATURE {
relay.set_high().unwrap();
} else {
relay.set_low().unwrap();
state = State::Cooling;
}
}
State::Cooling => state = State::Off,
}
} else {
state = State::Off;
}
if let State::Off = state {
relay.set_low().unwrap();
} }
if !usb_dev.poll(&mut [&mut serial]) { if !usb_dev.poll(&mut [&mut serial]) {
@ -242,11 +346,8 @@ fn main() -> ! {
} }
let mut buf = [0u8; 64]; let mut buf = [0u8; 64];
match serial.read(&mut buf[..]) { if let Ok(count) = serial.read(&mut buf[..]) {
Ok(count) => {
let _ = serial.write(&buf[..count]); let _ = serial.write(&buf[..count]);
} }
_ => (),
}
} }
} }