Rotary dial added to enable target temp changing, GPIO 15 enabled as a gate pin for a mosfet power control
This commit is contained in:
100
src/main.rs
100
src/main.rs
@@ -9,6 +9,8 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
mod rotary;
|
||||
|
||||
use defmt::println;
|
||||
// Ensure we halt the program on panic (if we don't mention this crate it won't
|
||||
// be linked)
|
||||
@@ -27,6 +29,10 @@ use sh1106_pico_rs::{sh1106::SH1106Dev, graphics::GraphicsBuf};
|
||||
|
||||
// Some traits we need
|
||||
use embedded_hal::digital::OutputPin;
|
||||
use embedded_hal::digital::InputPin;
|
||||
|
||||
use crate::rotary::RotaryEnc;
|
||||
use crate::rotary::RotaryResponse;
|
||||
|
||||
/// The linker will place this boot block at the start of our program image. We
|
||||
/// need this to help the ROM bootloader get our code up and running.
|
||||
@@ -125,7 +131,52 @@ fn main() -> ! {
|
||||
let mut tick = 0u32;
|
||||
let mut last_gfx_push = 0u32;
|
||||
|
||||
let mut target_temp = 220;
|
||||
|
||||
let mut gate_pin = pins.gpio15.into_push_pull_output_in_state(rp2040_hal::gpio::PinState::Low);
|
||||
|
||||
|
||||
let mut rotary = RotaryEnc::default();
|
||||
// rotary encoder
|
||||
let mut clk_pin = pins.gpio16.into_pull_up_input();
|
||||
let mut dt_pin = pins.gpio17.into_pull_up_input();
|
||||
|
||||
let mut last_rotary = 0u32;
|
||||
|
||||
const CYCLES_PER_FRAME:u32 = 100_000;
|
||||
const CYCLES_PER_ROTARY:u32 = 10_000;
|
||||
|
||||
let mut rotary_input_allowed = true;
|
||||
|
||||
loop {
|
||||
|
||||
if tick - last_rotary > CYCLES_PER_ROTARY {
|
||||
rotary_input_allowed = true;
|
||||
}
|
||||
|
||||
if rotary_input_allowed {
|
||||
|
||||
let clk_now = clk_pin.is_low().unwrap();
|
||||
let dt_now = dt_pin.is_low().unwrap();
|
||||
|
||||
match rotary.update(clk_now, dt_now) {
|
||||
RotaryResponse::UP => {
|
||||
target_temp += 1;
|
||||
rotary_input_allowed = false;
|
||||
last_rotary = tick;
|
||||
// println!("Rotary up");
|
||||
}
|
||||
RotaryResponse::DOWN => {
|
||||
target_temp -= 1;
|
||||
rotary_input_allowed = false;
|
||||
last_rotary = tick;
|
||||
// println!("Rotary dn");
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let samples = adc_fifo.len();
|
||||
|
||||
if samples > 4 {
|
||||
@@ -141,7 +192,7 @@ fn main() -> ! {
|
||||
|
||||
tick = tick.wrapping_add(1);
|
||||
// tweak this magic number for lower/higher fps
|
||||
if tick.abs_diff(last_gfx_push) < 100_000 {
|
||||
if tick.abs_diff(last_gfx_push) < CYCLES_PER_FRAME {
|
||||
continue;
|
||||
}
|
||||
last_gfx_push = tick;
|
||||
@@ -180,7 +231,7 @@ fn main() -> ! {
|
||||
|
||||
let adc_val = (adc_avg / accepted_samps) as u16;
|
||||
|
||||
println!("ADC {=u16}, samps {}", adc_val, accepted_samps);
|
||||
// println!("ADC {=u16}, samps {}", adc_val, accepted_samps);
|
||||
|
||||
let deg = match adc_val {
|
||||
..ZERO_DEG_C => 0f32,
|
||||
@@ -194,26 +245,32 @@ fn main() -> ! {
|
||||
}
|
||||
};
|
||||
|
||||
let deg = (deg * 10.) as u32;
|
||||
let mut itoa_result = itoa(deg);
|
||||
const START_Y:u8 = 8;
|
||||
gfx_buf.draw_string(10, START_Y, "Probe temp");
|
||||
|
||||
let probe_temp = (deg * 10.) as u32;
|
||||
|
||||
let mut itoa_result = itoa(probe_temp);
|
||||
let deg_str = itoa_result.as_degrees_decicentigrade_str();
|
||||
|
||||
|
||||
let deg_buf = &mut itoa_result.buf;
|
||||
for i in 1..10usize {
|
||||
deg_buf[i-1] = deg_buf[i];
|
||||
}
|
||||
// println!("tenths of a deg {}, deg {}", probe_temp, deg_str);
|
||||
gfx_buf.draw_textfield(10, START_Y+12, 100, 60, deg_str);
|
||||
|
||||
deg_buf[9] = b'.';
|
||||
itoa_result.len += 1;
|
||||
gfx_buf.draw_string(10, START_Y+30, "Target Temp");
|
||||
|
||||
gfx_buf.draw_string(10, 10, "Probe temp");
|
||||
let deg_str = itoa_result.as_str();
|
||||
|
||||
println!("tenths of a deg {}, deg {}", deg, deg_str);
|
||||
gfx_buf.draw_textfield(10, 22, 100, 60, deg_str);
|
||||
gate_pin.set_state(match target_temp > probe_temp {
|
||||
true => rp2040_hal::gpio::PinState::High,
|
||||
false => rp2040_hal::gpio::PinState::Low
|
||||
}).unwrap();
|
||||
|
||||
// dancing sprite just for heartbeat visibility
|
||||
gfx_buf.sprites[0].y = 40 + ((test_val as i32) / 4) % 2;
|
||||
|
||||
itoa_result = itoa(target_temp);
|
||||
let deg_str = itoa_result.as_degrees_decicentigrade_str();
|
||||
gfx_buf.draw_string(10, START_Y+42, deg_str);
|
||||
|
||||
gfx_buf.redraw();
|
||||
sh1106_dev.blit_framebuffer(&mut i2c, &mut gfx_buf);
|
||||
|
||||
@@ -221,7 +278,6 @@ fn main() -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Can't return str without a ref to a lifetime somewhere else,
|
||||
// so instead return a buffer of the maximum i32 length
|
||||
pub struct ItoaResult {
|
||||
@@ -242,6 +298,18 @@ impl ItoaResult {
|
||||
pub fn as_str(&self) -> &str {
|
||||
core::str::from_utf8(&self.buf[11usize.checked_sub(self.len).unwrap()..]).unwrap()
|
||||
}
|
||||
|
||||
pub fn as_degrees_decicentigrade_str(&mut self) -> &str {
|
||||
let itoa_buf = &mut self.buf;
|
||||
for i in 1..10usize {
|
||||
itoa_buf[i-1] = itoa_buf[i];
|
||||
}
|
||||
|
||||
itoa_buf[9] = b'.';
|
||||
self.len += 1;
|
||||
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn itoa(mut value: u32) -> ItoaResult {
|
||||
|
||||
88
src/rotary.rs
Normal file
88
src/rotary.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
#[derive(Clone, Default)]
|
||||
pub struct RotaryEnc {
|
||||
state: RotaryEncState,
|
||||
wait_for_reset: bool,
|
||||
primed: bool
|
||||
}
|
||||
|
||||
impl RotaryEnc {
|
||||
pub fn update(&mut self, clk: bool, dt: bool) -> RotaryResponse {
|
||||
|
||||
let state_now = RotaryEncState::from_pin_states(clk, dt);
|
||||
|
||||
if state_now == self.state {
|
||||
return RotaryResponse::NOTHING;
|
||||
}
|
||||
|
||||
let response = match state_now {
|
||||
RotaryEncState::BOTH_OFF => {
|
||||
self.primed = false;
|
||||
self.wait_for_reset = false;
|
||||
RotaryResponse::NOTHING
|
||||
}
|
||||
RotaryEncState::CLK_ON | RotaryEncState::DT_ON => {
|
||||
match (self.wait_for_reset, self.state) {
|
||||
(false, RotaryEncState::BOTH_OFF) => {
|
||||
self.primed = true;
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
RotaryResponse::NOTHING
|
||||
},
|
||||
RotaryEncState::BOTH_ON => {
|
||||
match (self.primed, self.state) {
|
||||
(true, RotaryEncState::CLK_ON) => {
|
||||
self.primed = false;
|
||||
RotaryResponse::UP
|
||||
}
|
||||
(true, RotaryEncState::DT_ON) => {
|
||||
self.primed = false;
|
||||
RotaryResponse::DOWN
|
||||
}
|
||||
_ => {
|
||||
self.primed = false;
|
||||
self.wait_for_reset = true;
|
||||
RotaryResponse::NOTHING
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.state = state_now;
|
||||
|
||||
response
|
||||
}
|
||||
}
|
||||
|
||||
pub enum RotaryResponse {
|
||||
NOTHING,
|
||||
UP,
|
||||
DOWN
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq)]
|
||||
enum RotaryEncState {
|
||||
#[default]
|
||||
BOTH_OFF,
|
||||
CLK_ON,
|
||||
DT_ON,
|
||||
BOTH_ON
|
||||
}
|
||||
|
||||
impl RotaryEncState {
|
||||
pub fn from_pin_states(clk: bool, dt: bool) -> Self {
|
||||
if clk && dt {
|
||||
return Self::BOTH_ON;
|
||||
}
|
||||
|
||||
if clk {
|
||||
return Self::CLK_ON;
|
||||
}
|
||||
|
||||
if dt {
|
||||
return Self::DT_ON;
|
||||
}
|
||||
|
||||
Self::BOTH_OFF
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user