Skip to content

Commit

Permalink
thermistor
Browse files Browse the repository at this point in the history
  • Loading branch information
ImplFerris committed Nov 17, 2024
1 parent fecf2de commit e682448
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 20 deletions.
56 changes: 37 additions & 19 deletions src/thermistor/temperature/action.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,28 @@ heapless = "0.8.0"
libm = "0.2.11"
```

## Interrupt Handler
We have set up only the ADC interrupt handler for the LDR exercises so far. For this exercise, we also need to set up an interrupt handler for I2C to enable communication with the OLED display.
### Additional imports

```rust
use embassy_rp::adc::InterruptHandler;
use heapless::String;
use ssd1306::mode::DisplayConfig;
use ssd1306::prelude::DisplayRotation;
use ssd1306::size::DisplaySize128x64;
use ssd1306::{I2CDisplayInterface, Ssd1306};

use embassy_rp::adc::{Adc, Channel};
use embassy_rp::peripherals::I2C1;
use embassy_rp::{adc, bind_interrupts, i2c};

use embassy_rp::gpio::Pull;

use core::fmt::Write;
```

### Interrupt Handler
We have set up only the ADC interrupt handler for the LDR exercises so far. For this exercise, we also need to set up an interrupt handler for I2C to enable communication with the OLED display.

```rust
bind_interrupts!(struct Irqs {
ADC_IRQ_FIFO => adc::InterruptHandler;
I2C1_IRQ => i2c::InterruptHandler<I2C1>;
Expand Down Expand Up @@ -119,6 +135,9 @@ We defined the reference temperature as 25°C for the thermistor. However, for t
let ref_temp = celsius_to_kelvin(REF_TEMP);
```

## Loop
In a loop that runs every 1 second(adjust as you require), we read the ADC value, calculate the resistance from ADC, then derive the temperature from resistance, and display the results on the OLED.

### Read ADC
We read the ADC value; we also put into the buffer.
```rust
Expand Down Expand Up @@ -153,18 +172,18 @@ Timer::after_secs(1).await;
#![no_main]

use embassy_executor::Spawner;
use embassy_rp as hal;
use embassy_rp::block::ImageDef;
use embassy_rp::{self as hal, gpio::Pull};
use embassy_rp::gpio::Pull;
use embassy_time::Timer;
use heapless::String;
use {defmt_rtt as _, panic_probe as _};

use ssd1306::mode::DisplayConfig;
use ssd1306::prelude::DisplayRotation;
use ssd1306::size::DisplaySize128x64;
use ssd1306::{I2CDisplayInterface, Ssd1306};
use {defmt_rtt as _, panic_probe as _};

use embassy_rp::adc::{Adc, Channel, InterruptHandler};
use embassy_rp::adc::{Adc, Channel};
use embassy_rp::peripherals::I2C1;
use embassy_rp::{adc, bind_interrupts, i2c};

Expand All @@ -176,11 +195,9 @@ use core::fmt::Write;
pub static IMAGE_DEF: ImageDef = hal::block::ImageDef::secure_exe();

bind_interrupts!(struct Irqs {
ADC_IRQ_FIFO => InterruptHandler;
ADC_IRQ_FIFO => adc::InterruptHandler;
I2C1_IRQ => i2c::InterruptHandler<I2C1>;
});

// Constants for ADC calculations
const fn calculate_adc_max(adc_bits: u8) -> u16 {
(1 << adc_bits) - 1
}
Expand All @@ -190,12 +207,14 @@ const ADC_MAX: u16 = calculate_adc_max(ADC_BITS); // 4095 for 12-bit ADC
const B_VALUE: f64 = 3950.0;
const REF_RES: f64 = 10_000.0; // Reference resistance in ohms (10kΩ)
const REF_TEMP: f64 = 25.0; // Reference temperature 25°C

// We have already covered about this formula in ADC chpater
fn adc_to_resistance(adc_value: u16, ref_res: f64) -> f64 {
let x: f64 = (ADC_MAX as f64 / adc_value as f64) - 1.0;
// ref_res * x // If you connected thermistor to power supply
ref_res / x
}

// B Equation to convert resistance to temperature
fn calculate_temperature(current_res: f64, ref_res: f64, ref_temp: f64, b_val: f64) -> f64 {
let ln_value = libm::log(current_res / ref_res); // Use libm for `no_std`
let inv_t = (1.0 / ref_temp) + ((1.0 / b_val) * ln_value);
Expand All @@ -213,10 +232,11 @@ fn celsius_to_kelvin(celsius: f64) -> f64 {
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_rp::init(Default::default());
// ADC to read the Vout value
let mut adc = Adc::new(p.ADC, Irqs, adc::Config::default());

let mut p26 = Channel::new_pin(p.PIN_26, Pull::None);

// Setting up I2C send text to OLED display
let sda = p.PIN_18;
let scl = p.PIN_19;
let i2c = i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, i2c::Config::default());
Expand All @@ -225,14 +245,9 @@ async fn main(_spawner: Spawner) {
let mut display =
Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0).into_terminal_mode();
display.init().unwrap();

let mut buff: String<64> = String::new();
let ref_temp = celsius_to_kelvin(REF_TEMP);

loop {
buff.clear();
display.clear().unwrap();

let adc_value = adc.read(&mut p26).await.unwrap();
writeln!(buff, "ADC: {}", adc_value).unwrap();

Expand All @@ -248,17 +263,20 @@ async fn main(_spawner: Spawner) {
}
}

// Program metadata for `picotool info`
// Program metadata for `picotool info`.
// This isn't needed, but it's recomended to have these minimal entries.
#[link_section = ".bi_entries"]
#[used]
pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
embassy_rp::binary_info::rp_program_name!(c"Blinky Example"),
embassy_rp::binary_info::rp_program_description!(
c"This example tests the RP Pico on-board ADC with a thermistor"
c"This example tests the RP Pico on board LED, connected to gpio 25"
),
embassy_rp::binary_info::rp_cargo_version!(),
embassy_rp::binary_info::rp_program_build_attribute!(),
];

// End of file
```


Expand Down
3 changes: 2 additions & 1 deletion src/thermistor/temperature/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Temperature on OLED

In this section, we'll calculate the temperature using the B equation and display it on an OLED screen.
In this section, we will measure the temperature in your room and display it on the OLED screen.


## Hardware Requirments

Expand Down

0 comments on commit e682448

Please sign in to comment.