Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to save and pass 'PinDriver' objects #241

Closed
xiaguangbo opened this issue Mar 15, 2024 · 3 comments
Closed

How to save and pass 'PinDriver' objects #241

xiaguangbo opened this issue Mar 15, 2024 · 3 comments

Comments

@xiaguangbo
Copy link

xiaguangbo commented Mar 15, 2024

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

@SergioGasquez
Copy link
Member

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.

@xiaguangbo
Copy link
Author

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

@github-project-automation github-project-automation bot moved this from Todo to Done in esp-rs Mar 15, 2024
@xiaguangbo
Copy link
Author

xiaguangbo commented Mar 15, 2024

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
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

No branches or pull requests

2 participants