esp-rs / std-training

Embedded Rust on Espressif training material.

Home Page:https://esp-rs.github.io/std-training

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to save and pass 'PinDriver' objects

xiaguangbo opened this issue · comments

My basic idea is to encapsulate a onewire struct and pass a decimal pin number to drive the corresponding pin. But how do you preserve the objects returned by PinDriver: : input_output_od? I'm not gonna write this:

struch Onewire {
    pin : ???
};

...

let mut pin  = PinDriver::input_output_od(0) // Use numbers instead, and if no, use `match` a separate line for each peripheral.pins.gpiox.

now:

use esp_idf_hal::delay::FreeRtos;
use esp_idf_svc::hal::{
    delay::Delay,
    gpio::{PinDriver, Pull},
    peripherals::Peripherals,
};

fn main() {
    // It is necessary to call this function once. Otherwise some patches to the runtime
    // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
    esp_idf_svc::sys::link_patches();

    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    log::info!("Hello, world!");

    let peripherals = Peripherals::take().unwrap();

    let mut onewire = PinDriver::input_output_od(peripherals.pins.gpio0).unwrap();
    onewire.set_pull(Pull::Floating).unwrap(); // Use external pull-up

    let delay = Delay::new_default();

    loop {
        FreeRtos::delay_ms(1000);

        // reset
        onewire.set_low().unwrap();
        delay.delay_us(600);
        onewire.set_high().unwrap();
        delay.delay_us(80);

        if onewire.is_low() {
            log::info!("onewire: is exist");
            delay.delay_us(900);

            if onewire.is_high() {
                log::info!("onewire: reset ok");
            } else {
                log::warn!("onewire: reset err");
                continue;
            }
        } else {
            log::warn!("onewire: reset err");
            continue;
        }
    }
}

Hi! I would suggest using the matrix channel (https://matrix.to/#/#esp-rs:matrix.org) for this kind of questions as they are not issues per se and not strictly related with the training. Also, more people could jump in to help you.

Hi! I would suggest using the matrix channel (https://matrix.to/#/#esp-rs:matrix.org) for this kind of questions as they are not issues per se and not strictly related with the training. Also, more people could jump in to help you.

ok

is ok

use embedded_hal::digital;

use esp_idf_svc::hal::delay;
use esp_idf_svc::hal::gpio;
use esp_idf_svc::hal::peripherals;
use esp_idf_svc::hal::uart;
use esp_idf_svc::hal::units;

use std::fmt::Write;

const CMD_SKIP: u8 = 0xcc;
const CMD_WRITE_REG: u8 = 0x4e;
const CMD_TEMP_START: u8 = 0x44;
const CMD_READ_REG: u8 = 0xbe;

fn main() {
    // It is necessary to call this function once. Otherwise some patches to the runtime
    // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
    esp_idf_svc::sys::link_patches();

    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    log::info!("Hello, world!");

    let peripherals = peripherals::Peripherals::take().unwrap();

    // onewire
    let mut onewire = gpio::PinDriver::input_output_od(peripherals.pins.gpio0).unwrap();
    onewire.set_pull(gpio::Pull::Floating).unwrap(); // use external pull-up

    // uart
    let config = uart::config::Config::default().baudrate(units::Hertz(115_200));
    let mut uart = uart::UartDriver::new(
        peripherals.uart1,
        peripherals.pins.gpio1,
        peripherals.pins.gpio2,
        Option::<gpio::AnyIOPin>::None,
        Option::<gpio::AnyIOPin>::None,
        &config,
    )
    .unwrap();

    // delay
    let delay = delay::Delay::new_default();

    // ds18b20
    // wait reset
    while !onewire_reset(&mut onewire, &delay) {
        delay::FreeRtos::delay_ms(1000);
    }

    // set accuracy
    onewire_write_byte(&mut onewire, &delay, CMD_SKIP);
    onewire_write_byte(&mut onewire, &delay, CMD_WRITE_REG);
    onewire_write_byte(&mut onewire, &delay, 0xff);
    onewire_write_byte(&mut onewire, &delay, 0x00);
    onewire_write_byte(&mut onewire, &delay, 0x7f);

    loop {
        delay::FreeRtos::delay_ms(1000);

        // ds18b20
        // measurement temp
        if !onewire_reset(&mut onewire, &delay) {
            continue;
        }

        onewire_write_byte(&mut onewire, &delay, CMD_SKIP);
        onewire_write_byte(&mut onewire, &delay, CMD_TEMP_START);

        // read temp
        if !onewire_reset(&mut onewire, &delay) {
            continue;
        }

        onewire_write_byte(&mut onewire, &delay, CMD_SKIP);
        onewire_write_byte(&mut onewire, &delay, CMD_READ_REG);

        let temp_l = onewire_read_byte(&mut onewire, &delay);
        let temp_h = onewire_read_byte(&mut onewire, &delay);
        let temp = (((temp_h as i16) << 8 | (temp_l as i16)) as f64) * 0.0625;

        log::info!("temp: {:.1}", temp);

        // uart
        writeln!(uart, "temp: {:.1}", temp).unwrap();
    }
}

fn onewire_reset<T>(pin: &mut T, delay: &delay::Delay) -> bool
where
    T: digital::InputPin + digital::OutputPin,
{
    pin.set_low().unwrap();
    delay.delay_us(600);
    pin.set_high().unwrap();
    delay.delay_us(80);

    if pin.is_low().unwrap() {
        log::info!("onewire: is exist");
        delay.delay_us(900);

        if pin.is_high().unwrap() {
            log::info!("onewire: reset ok");
            true
        } else {
            log::warn!("onewire: reset err");
            false
        }
    } else {
        log::warn!("onewire: reset err");
        false
    }
}

fn onewire_write_byte<T>(pin: &mut T, delay: &delay::Delay, mut byte: u8)
where
    T: digital::InputPin + digital::OutputPin,
{
    for _ in 0..8 {
        let bit = byte & 0x01 != 0;
        byte >>= 1;

        if bit {
            pin.set_low().unwrap();
            delay.delay_us(5);

            pin.set_high().unwrap();
            delay.delay_us(90);
        } else {
            pin.set_low().unwrap();
            delay.delay_us(90);

            pin.set_high().unwrap();
            delay.delay_us(5);
        }
    }
}

fn onewire_read_byte<T>(pin: &mut T, delay: &delay::Delay) -> u8
where
    T: digital::InputPin + digital::OutputPin,
{
    let mut byte: u8 = 0;

    for _ in 0..8 {
        byte >>= 1;

        pin.set_low().unwrap();
        delay.delay_us(5);

        pin.set_high().unwrap();
        delay.delay_us(5);

        if pin.is_high().unwrap() {
            byte |= 0x80;
        }

        delay.delay_us(60);
    }

    byte
}