Read temperature from thermocouple
This commit is contained in:
parent
722a38f633
commit
0956055d6a
|
@ -408,6 +408,7 @@ dependencies = [
|
||||||
"embedded-graphics",
|
"embedded-graphics",
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
"fugit",
|
"fugit",
|
||||||
|
"nb 1.1.0",
|
||||||
"panic-halt",
|
"panic-halt",
|
||||||
"rp-pico",
|
"rp-pico",
|
||||||
"ssd1306",
|
"ssd1306",
|
||||||
|
|
|
@ -12,6 +12,7 @@ display-interface = "0.4.1"
|
||||||
embedded-graphics = "0.8.0"
|
embedded-graphics = "0.8.0"
|
||||||
embedded-hal = "0.2.7"
|
embedded-hal = "0.2.7"
|
||||||
fugit = "0.3.7"
|
fugit = "0.3.7"
|
||||||
|
nb = "1.1.0"
|
||||||
panic-halt = "0.2.0"
|
panic-halt = "0.2.0"
|
||||||
rp-pico = "0.7.0"
|
rp-pico = "0.7.0"
|
||||||
ssd1306 = "0.8.0"
|
ssd1306 = "0.8.0"
|
||||||
|
|
100
src/main.rs
100
src/main.rs
|
@ -1,21 +1,27 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
|
mod max6675;
|
||||||
|
|
||||||
|
use core::str;
|
||||||
|
|
||||||
use cortex_m::delay::Delay;
|
use cortex_m::delay::Delay;
|
||||||
|
|
||||||
use display_interface::DisplayError;
|
use display_interface::DisplayError;
|
||||||
|
|
||||||
use embedded_graphics::{
|
use embedded_graphics::{
|
||||||
mono_font::{ascii::FONT_6X10, MonoTextStyleBuilder},
|
mono_font::{iso_8859_1::FONT_6X10, MonoTextStyle},
|
||||||
pixelcolor::BinaryColor,
|
pixelcolor::BinaryColor,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
text::{Baseline, Text},
|
text::{Alignment, Text},
|
||||||
};
|
};
|
||||||
|
|
||||||
use embedded_hal::digital::v2::{InputPin, ToggleableOutputPin};
|
use embedded_hal::digital::v2::{InputPin, ToggleableOutputPin};
|
||||||
|
|
||||||
use fugit::RateExtU32;
|
use fugit::RateExtU32;
|
||||||
|
|
||||||
|
use max6675::{Error, Max6675};
|
||||||
|
|
||||||
use panic_halt as _;
|
use panic_halt as _;
|
||||||
|
|
||||||
use rp_pico::{
|
use rp_pico::{
|
||||||
|
@ -25,13 +31,13 @@ use rp_pico::{
|
||||||
gpio::PinState,
|
gpio::PinState,
|
||||||
i2c::I2C,
|
i2c::I2C,
|
||||||
usb::UsbBus,
|
usb::UsbBus,
|
||||||
Sio, Watchdog,
|
Sio, Timer, Watchdog,
|
||||||
},
|
},
|
||||||
pac::{CorePeripherals, Peripherals},
|
pac::{CorePeripherals, Peripherals},
|
||||||
Pins,
|
Pins,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306};
|
use ssd1306::{mode::BufferedGraphicsMode, prelude::*, I2CDisplayInterface, Ssd1306};
|
||||||
|
|
||||||
use usb_device::{bus::UsbBus as UsbBusTrait, bus::UsbBusAllocator, prelude::*};
|
use usb_device::{bus::UsbBus as UsbBusTrait, bus::UsbBusAllocator, prelude::*};
|
||||||
|
|
||||||
|
@ -58,6 +64,14 @@ fn print_serial<'a, B: UsbBusTrait>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn println_serial<'a, B: UsbBusTrait>(
|
||||||
|
serial: &mut SerialPort<'a, B>,
|
||||||
|
msg: &str,
|
||||||
|
) -> Result<(), UsbError> {
|
||||||
|
print_serial(serial, msg)?;
|
||||||
|
print_serial(serial, "\r\n")
|
||||||
|
}
|
||||||
|
|
||||||
fn stringify_display_error(err: DisplayError) -> &'static str {
|
fn stringify_display_error(err: DisplayError) -> &'static str {
|
||||||
match err {
|
match err {
|
||||||
DisplayError::InvalidFormatError => "invalid format",
|
DisplayError::InvalidFormatError => "invalid format",
|
||||||
|
@ -71,6 +85,27 @@ fn stringify_display_error(err: DisplayError) -> &'static str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn display_text<DI, SIZE>(
|
||||||
|
display: &mut Ssd1306<DI, SIZE, BufferedGraphicsMode<SIZE>>,
|
||||||
|
text: &str,
|
||||||
|
) -> Result<(), DisplayError>
|
||||||
|
where
|
||||||
|
DI: WriteOnlyDataCommand,
|
||||||
|
SIZE: DisplaySize,
|
||||||
|
{
|
||||||
|
let (w, h) = display.dimensions();
|
||||||
|
|
||||||
|
Text::with_alignment(
|
||||||
|
text,
|
||||||
|
Point::new((w / 2).into(), (h / 2).into()),
|
||||||
|
MonoTextStyle::new(&FONT_6X10, BinaryColor::On),
|
||||||
|
Alignment::Center,
|
||||||
|
)
|
||||||
|
.draw(display)?;
|
||||||
|
|
||||||
|
display.flush()
|
||||||
|
}
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let mut p = Peripherals::take().unwrap();
|
let mut p = Peripherals::take().unwrap();
|
||||||
|
@ -110,7 +145,7 @@ fn main() -> ! {
|
||||||
.device_class(USB_CLASS_CDC)
|
.device_class(USB_CLASS_CDC)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
for _ in 0..2000 {
|
for _ in 0..1000 {
|
||||||
delay.delay_ms(5);
|
delay.delay_ms(5);
|
||||||
|
|
||||||
if !usb_dev.poll(&mut [&mut serial]) {
|
if !usb_dev.poll(&mut [&mut serial]) {
|
||||||
|
@ -124,7 +159,7 @@ fn main() -> ! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = print_serial(&mut serial, "Hello, world!\r\n");
|
let _ = println_serial(&mut serial, "Hello, world!");
|
||||||
|
|
||||||
let i2c = I2C::i2c0(
|
let i2c = I2C::i2c0(
|
||||||
p.I2C0,
|
p.I2C0,
|
||||||
|
@ -148,26 +183,15 @@ fn main() -> ! {
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
let text_style = MonoTextStyleBuilder::new()
|
let so = pins.gpio6.into_floating_input();
|
||||||
.font(&FONT_6X10)
|
let cs = pins.gpio7.into_push_pull_output_in_state(PinState::High);
|
||||||
.text_color(BinaryColor::On)
|
let sck = pins.gpio8.into_push_pull_output();
|
||||||
.build();
|
|
||||||
|
|
||||||
let result = Text::with_baseline("Hello, world!", Point::zero(), text_style, Baseline::Top)
|
let mut thermocouple = Max6675::new(cs, sck, so);
|
||||||
.draw(&mut display)
|
let timer = Timer::new(p.TIMER, &mut p.RESETS);
|
||||||
.map_err(stringify_display_error);
|
|
||||||
if let Err(msg) = result {
|
|
||||||
let _ = print_serial(&mut serial, msg);
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = display.flush().map_err(stringify_display_error);
|
|
||||||
if let Err(msg) = result {
|
|
||||||
let _ = print_serial(&mut serial, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut relay = pins.gpio14.into_push_pull_output_in_state(PinState::Low);
|
let mut relay = pins.gpio14.into_push_pull_output_in_state(PinState::Low);
|
||||||
let tmp_button = pins.gpio15.into_pull_up_input();
|
let button = pins.gpio15.into_pull_up_input();
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
@ -179,10 +203,36 @@ fn main() -> ! {
|
||||||
if counter == 0 {
|
if counter == 0 {
|
||||||
led.toggle().unwrap();
|
led.toggle().unwrap();
|
||||||
|
|
||||||
let _ = print_serial(&mut serial, "ping\r\n");
|
let mut bytes: [u8; 8] = [32, 32, 32, 32, 32, 194, 176, 67];
|
||||||
|
let text = match thermocouple.read_temperature(&mut timer.count_down()) {
|
||||||
|
Ok(mut temperature) => {
|
||||||
|
temperature >>= 2;
|
||||||
|
|
||||||
|
for i in (0..4).rev() {
|
||||||
|
bytes[i] = 48u8 + (temperature % 10) as u8;
|
||||||
|
temperature /= 10;
|
||||||
|
|
||||||
|
if temperature == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if tmp_button.is_low().unwrap() {
|
str::from_utf8(&bytes).unwrap()
|
||||||
|
}
|
||||||
|
Err(Error::IOError) => "i/o error",
|
||||||
|
Err(Error::OpenThermocouple) => "n/c",
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = println_serial(&mut serial, text);
|
||||||
|
|
||||||
|
display.clear_buffer();
|
||||||
|
|
||||||
|
if let Err(err) = display_text(&mut display, text) {
|
||||||
|
let _ = println_serial(&mut serial, stringify_display_error(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if button.is_low().unwrap() {
|
||||||
relay.toggle().unwrap();
|
relay.toggle().unwrap();
|
||||||
delay.delay_ms(1000);
|
delay.delay_ms(1000);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
use embedded_hal::{
|
||||||
|
digital::v2::{InputPin, OutputPin},
|
||||||
|
timer::CountDown,
|
||||||
|
};
|
||||||
|
|
||||||
|
use fugit::{ExtU64, MicrosDurationU64};
|
||||||
|
|
||||||
|
use nb::block;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
IOError,
|
||||||
|
OpenThermocouple,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Max6675<CS, SCK, SO>
|
||||||
|
where
|
||||||
|
CS: OutputPin,
|
||||||
|
SCK: OutputPin,
|
||||||
|
SO: InputPin,
|
||||||
|
{
|
||||||
|
cs: CS,
|
||||||
|
sck: SCK,
|
||||||
|
so: SO,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<CS, SCK, SO> Max6675<CS, SCK, SO>
|
||||||
|
where
|
||||||
|
CS: OutputPin,
|
||||||
|
SCK: OutputPin,
|
||||||
|
SO: InputPin,
|
||||||
|
{
|
||||||
|
pub fn new(cs: CS, sck: SCK, so: SO) -> Self {
|
||||||
|
Self { cs, sck, so }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_temperature<CD>(&mut self, timer: &mut CD) -> Result<u16, Error>
|
||||||
|
where
|
||||||
|
CD: CountDown,
|
||||||
|
CD::Time: From<MicrosDurationU64>,
|
||||||
|
{
|
||||||
|
self.cs.set_low().map_err(|_| Error::IOError)?;
|
||||||
|
delay(timer, 10.micros());
|
||||||
|
|
||||||
|
let mut d = 0u16;
|
||||||
|
|
||||||
|
for i in (0..16).rev() {
|
||||||
|
self.sck.set_low().map_err(|_| Error::IOError)?;
|
||||||
|
delay(timer, 10.micros());
|
||||||
|
|
||||||
|
if self.so.is_high().map_err(|_| Error::IOError)? {
|
||||||
|
d |= 1 << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.sck.set_high().map_err(|_| Error::IOError)?;
|
||||||
|
delay(timer, 10.micros());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cs.set_high().map_err(|_| Error::IOError)?;
|
||||||
|
|
||||||
|
if d & 0x4 == 0x4 {
|
||||||
|
Err(Error::OpenThermocouple)
|
||||||
|
} else {
|
||||||
|
Ok(d >> 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delay<CD>(timer: &mut CD, t: MicrosDurationU64)
|
||||||
|
where
|
||||||
|
CD: CountDown,
|
||||||
|
CD::Time: From<MicrosDurationU64>,
|
||||||
|
{
|
||||||
|
timer.start(t);
|
||||||
|
block!(timer.wait()).unwrap();
|
||||||
|
}
|
Loading…
Reference in New Issue