From e7aa77494be36140e5c1bea1216307beaecf623a Mon Sep 17 00:00:00 2001 From: Luca Date: Mon, 22 Jan 2024 23:11:48 +0100 Subject: [PATCH] Use fixed-precision decimal numbers --- .cargo/{config => config.toml} | 0 Cargo.lock | 67 ++++++++++++++++++++++++ Cargo.toml | 2 + src/main.rs | 95 ++++++++++++++-------------------- src/max6675.rs | 8 ++- 5 files changed, 115 insertions(+), 57 deletions(-) rename .cargo/{config => config.toml} (100%) diff --git a/.cargo/config b/.cargo/config.toml similarity index 100% rename from .cargo/config rename to .cargo/config.toml diff --git a/Cargo.lock b/Cargo.lock index 5edb366..595d57f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,12 +41,24 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" + [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "cortex-m" version = "0.7.7" @@ -94,6 +106,12 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "debug-helper" version = "0.3.13" @@ -175,6 +193,18 @@ dependencies = [ "void", ] +[[package]] +name = "fixed" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c69ce7e7c0f17aa18fdd9d0de39727adb9c6281f2ad12f57cbe54ae6e76e7d" +dependencies = [ + "az", + "bytemuck", + "half", + "typenum", +] + [[package]] name = "float-cmp" version = "0.9.0" @@ -199,6 +229,35 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" +[[package]] +name = "half" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + [[package]] name = "itertools" version = "0.10.5" @@ -407,7 +466,9 @@ dependencies = [ "display-interface", "embedded-graphics", "embedded-hal", + "fixed", "fugit", + "heapless", "nb 1.1.0", "panic-halt", "rp-pico", @@ -446,6 +507,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.10" diff --git a/Cargo.toml b/Cargo.toml index cacf10e..319bea0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,9 @@ cortex-m-rt = "0.7.3" display-interface = "0.4.1" embedded-graphics = "0.8.0" embedded-hal = "0.2.7" +fixed = "1.24.0" fugit = "0.3.7" +heapless = "0.8.0" nb = "1.1.0" panic-halt = "0.2.0" rp-pico = "0.7.0" diff --git a/src/main.rs b/src/main.rs index 142065b..d6e5c6f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,8 @@ mod max6675; -use core::str; +use core::fmt::Write; +use core::write; use cortex_m::delay::Delay; @@ -23,7 +24,9 @@ use embedded_hal::{ use fugit::{ExtU64, MicrosDurationU64, RateExtU32}; -use max6675::{Error, Max6675}; +use heapless::String; + +use max6675::{Error, FixedU16, Max6675}; use nb::Error::WouldBlock; @@ -49,19 +52,14 @@ use usb_device::{bus::UsbBus as UsbBusTrait, bus::UsbBusAllocator, prelude::*}; use usbd_serial::{SerialPort, USB_CLASS_CDC}; -const HYSTERESIS: u16 = 10; +const HYSTERESIS: FixedU16 = FixedU16::const_from_int(5); -const PEAK_TEMPERATURE: u16 = 240; +const PEAK_TEMPERATURE: FixedU16 = FixedU16::const_from_int(240); -const POWER_FACTOR: u16 = 10; -const POWER_MAX: u16 = 1000; - -const PREHEAT_TEMPERATURE: u16 = 150; +const PREHEAT_TEMPERATURE: FixedU16 = FixedU16::const_from_int(150); const SOAK_TIME: MicrosDurationU64 = MicrosDurationU64::secs(90); -const TEMPERATURE_BUFF: u16 = 10; - enum State<'a> { Off, Preheat, @@ -70,14 +68,6 @@ enum State<'a> { Cooling, } -fn clamp(value: u16, max: u16) -> u16 { - if value > max { - max - } else { - value - } -} - fn print_serial<'a, B: UsbBusTrait>( serial: &mut SerialPort<'a, B>, msg: &str, @@ -230,7 +220,6 @@ fn main() -> ! { let so = pins.gpio6.into_floating_input(); let cs = pins.gpio7.into_push_pull_output_in_state(PinState::High); let sck = pins.gpio8.into_push_pull_output(); - let mut thermocouple = Max6675::new(cs, sck, so); let button = pins.gpio15.into_pull_up_input(); @@ -246,7 +235,7 @@ fn main() -> ! { let mut counter = 0; let mut state = State::Off; let mut heating = false; - let mut power = 0; + let mut error_counter = 0; loop { delay.delay_ms(5); counter = (counter + 1) % 2000; @@ -271,15 +260,13 @@ fn main() -> ! { if counter % 50 == 0 { let thermocouple_result = thermocouple.read_temperature(&mut timer.count_down()); - if let Some(mut temperature) = thermocouple_result.as_ref().copied().ok() { - temperature = (temperature >> 2) + ((temperature & 2) >> 1); + if let Some(temperature) = thermocouple_result.as_ref().copied().ok() { + error_counter = 0; match state { - State::Off => (), State::Preheat => { if temperature < PREHEAT_TEMPERATURE { heating = true; - power = clamp((PREHEAT_TEMPERATURE - temperature + TEMPERATURE_BUFF) * POWER_FACTOR, POWER_MAX); } else { let mut time = timer.count_down(); time.start(SOAK_TIME); @@ -289,58 +276,61 @@ fn main() -> ! { State::Soak(ref mut time) => match time.wait() { Ok(_) => state = State::Reflow, Err(WouldBlock) => { - if temperature < PREHEAT_TEMPERATURE - HYSTERESIS { + if temperature < PREHEAT_TEMPERATURE { heating = true; - power = clamp((PREHEAT_TEMPERATURE - temperature + TEMPERATURE_BUFF) * POWER_FACTOR, POWER_MAX); - } else if temperature > PREHEAT_TEMPERATURE + HYSTERESIS * 2 { - state = State::Reflow; - } else if temperature > PREHEAT_TEMPERATURE { + } + if temperature > PREHEAT_TEMPERATURE + HYSTERESIS { heating = false; } } - Err(_) => state = State::Off, + Err(_) => unreachable!(), }, State::Reflow => { if temperature < PEAK_TEMPERATURE { heating = true; - power = clamp((PEAK_TEMPERATURE - temperature + TEMPERATURE_BUFF) * POWER_FACTOR, POWER_MAX); } else { heating = false; state = State::Cooling; } } - State::Cooling => state = State::Off, + State::Cooling if temperature < PREHEAT_TEMPERATURE => { + state = State::Preheat; + } + _ => (), } } else { + error_counter += 1; + } + + if error_counter >= 4 { state = State::Off; } - let mut bytes: [u8; 7] = [32, 32, 32, 32, 194, 176, 67]; - let text = match thermocouple_result { - Ok(mut temperature) => { - temperature = (temperature >> 2) + ((temperature & 2) >> 1); + let mut text: String<9> = String::new(); + let text_str; - for i in (0..3).rev() { - bytes[i] = 48u8 + (temperature % 10) as u8; - temperature /= 10; - - if temperature == 0 { - break; - } + match thermocouple_result { + Ok(temperature) => { + if let Err(_) = write!(&mut text, "{}", temperature) { + text_str = "format error"; + } else { + text_str = text.as_str(); } - - str::from_utf8(&bytes).unwrap() } - Err(Error::IOError) => "i/o error", - Err(Error::OpenThermocouple) => "n/c", + Err(Error::IOError) => { + text_str = "i/o error"; + } + Err(Error::OpenThermocouple) => { + text_str = "n/c"; + } }; - let _ = println_serial(&mut serial, text); + let _ = println_serial(&mut serial, text_str); display.clear_buffer(); - if let Err(err) = display_text(&mut display, text, Baseline::Bottom) { + if let Err(err) = display_text(&mut display, text_str, Baseline::Bottom) { let _ = println_serial(&mut serial, stringify_display_error(err)); } @@ -362,16 +352,11 @@ fn main() -> ! { } if let State::Off = state { - relay.set_low().unwrap(); heating = false; } if heating { - if counter == 0 { - relay.set_high().unwrap(); - } else if counter >= power { - relay.set_low().unwrap(); - } + relay.set_high().unwrap(); } else { relay.set_low().unwrap(); } diff --git a/src/max6675.rs b/src/max6675.rs index 33f018a..6094d66 100644 --- a/src/max6675.rs +++ b/src/max6675.rs @@ -3,10 +3,14 @@ use embedded_hal::{ timer::CountDown, }; +use fixed::types::extra::U2; + use fugit::{ExtU64, MicrosDurationU64}; use nb::block; +pub type FixedU16 = fixed::FixedU16; + #[derive(Debug)] pub enum Error { IOError, @@ -34,7 +38,7 @@ where Self { cs, sck, so } } - pub fn read_temperature(&mut self, timer: &mut CD) -> Result + pub fn read_temperature(&mut self, timer: &mut CD) -> Result where CD: CountDown, CD::Time: From, @@ -61,7 +65,7 @@ where if d & 0x4 == 0x4 { Err(Error::OpenThermocouple) } else { - Ok(d >> 3) + Ok(FixedU16::from_num(d >> 3)) } } }