Read temperature from thermocouple

This commit is contained in:
Luca 2023-07-29 00:05:58 +02:00
parent 722a38f633
commit 0956055d6a
4 changed files with 153 additions and 25 deletions

1
Cargo.lock generated
View File

@ -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",

View File

@ -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"

View File

@ -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);
} }

76
src/max6675.rs Normal file
View File

@ -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();
}