Skip to content

Commit

Permalink
27 add battery sensor to the bsc (#54)
Browse files Browse the repository at this point in the history
* Add mightybuga_bsc/examples/no_bsc_batt_sensor.rs

* Update apps/hello_world with light sensor reading

* Add battery sensor and example to the hello world app

* Fix unused import warning
  • Loading branch information
punkto authored Jul 31, 2024
1 parent 77a7c29 commit a9b8f1f
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 0 deletions.
2 changes: 2 additions & 0 deletions apps/hello_world/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ embedded-alloc = "0.5.1"

logging = { path = "../../libs/logging" }
engine = { path = "../../libs/engine" }
light_sensor_array_controller = { path = "../../libs/light_sensor_array_controller" }
battery_sensor_controller = { path = "../../libs/battery_sensor_controller" }

[profile.release]
codegen-units = 1 # better optimizations
Expand Down
25 changes: 25 additions & 0 deletions apps/hello_world/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use mightybuga_bsc::timer_based_buzzer::TimerBasedBuzzerInterface;
use mightybuga_bsc::EncoderController;

use engine::engine::EngineController;
use light_sensor_array_controller::LightSensorArrayController;
use battery_sensor_controller::BatterySensorController;

use nb::block;

Expand All @@ -34,6 +36,8 @@ fn main() -> ! {
let mut led_d2 = board.led_d2;
let mut buzzer = board.buzzer;
let mut engine = board.engine;
let mut light_sensor_array = board.light_sensor_array;
let mut battery_sensor = board.battery_sensor;

let mut logger = Logger::new(&mut uart.tx);

Expand Down Expand Up @@ -97,6 +101,25 @@ fn main() -> ! {
delay.delay(1000.millis());
engine.stop();
}
b'g' => {
// Read the light sensors
light_sensor_array.set_led(true);
delay.delay(500.millis());
logger.log("Light sensor values: ");
let light_map = light_sensor_array.get_light_map();
light_sensor_array.set_led(false);
for i in 0..8 {
logger.log(" ");
print_number(light_map[i] as isize, &mut logger);
}
logger.log("\r\n");
}
b'h' => {
// Read the battery sensor
logger.log("Battery sensor value: ");
print_number(battery_sensor.get_battery_millivolts() as isize, &mut logger);
logger.log(" milli Volts\r\n");
}
_ => {
// Print the menu
print_menu(&mut logger);
Expand Down Expand Up @@ -124,6 +147,8 @@ fn print_menu(logger: &mut Logger) {
logger.log(" s. Move the robot backward\r\n");
logger.log(" d. Turn the robot right\r\n");
logger.log(" f. Turn the robot left\r\n");
logger.log(" g. Read the light sensors\r\n");
logger.log(" h. Read the battery sensor\r\n");
logger.log(" Any other key prints this menu\r\n");
}

Expand Down
9 changes: 9 additions & 0 deletions libs/battery_sensor_controller/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "battery_sensor_controller"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

7 changes: 7 additions & 0 deletions libs/battery_sensor_controller/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#![no_std]

/// The trait implemented by the battery sensor to get the battery voltage in millivolts.
pub trait BatterySensorController {
fn get_battery_millivolts(&mut self) -> u16;
}

1 change: 1 addition & 0 deletions mightybuga_bsc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ hal_button = { path = "../libs/hal_button" }
hal-encoder-stm32f1xx = { path = "../libs/hal_encoder_stm32f1xx" }
timer_based_buzzer_interface = { path = "../libs/timer_based_buzzer_interface/" }
light_sensor_array_controller = { path = "../libs/light_sensor_array_controller/" }
battery_sensor_controller = { path = "../libs/battery_sensor_controller/" }

[profile.release]
codegen-units = 1 # better optimizations
Expand Down
139 changes: 139 additions & 0 deletions mightybuga_bsc/examples/no_bsc_batt_sensor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
//! battery sensor example without using the BSC
//! The battery sensor is a voltage divider with a 47k resistor and a 20k resistor.
//! The voltage is read from the middle of the two resistors.
//! The voltage is then converted to millivolts and printed to the serial port.
//!
//! Hardware connections:
//! - VBATT to the 47k resistor. The battery has 2 cells in series, so the maximum voltage is 8.4V
//! - GND to the 20k resistor
//! - The middle of the two resistors to PB0 (ADC1)
//! - Led to PC13
//! - Serial port to PA9 (tx) and PA10 (rx)
//!
//! Run with:
//! cargo xtask mightybuga_bsc example no_bsc_batt_sensor
//! or
//! cd mightybuga-bsc; cargo run --example no_bsc_batt_sensor
#![no_std]
#![cfg_attr(not(doc), no_main)]
use panic_halt as _;

use mightybuga_bsc as board;

use board::hal::adc::*;
use board::hal::serial::*;
use board::hal::{pac, prelude::*};
use cortex_m_rt::entry;
use nb::block;

#[entry]
fn main() -> ! {
// Get access to the core peripherals from the cortex-m crate
let cp = cortex_m::Peripherals::take().unwrap();
// Get access to the device specific peripherals from the peripheral access crate
let dp = pac::Peripherals::take().unwrap();

// Take ownership over the raw flash and rcc devices and convert them into the corresponding
// HAL structs
let mut flash = dp.FLASH.constrain();
let rcc = dp.RCC.constrain();

let mut afio = dp.AFIO.constrain();

// Freeze the configuration of all the clocks in the system and store the frozen frequencies in
// `clocks`
let clocks = rcc.cfgr.freeze(&mut flash.acr);

// create a delay abstraction based on SysTick
let mut delay = cp.SYST.delay(&clocks);

// Acquire the GPIOC peripheral
let mut gpioc = dp.GPIOC.split();

// Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the function
// in order to configure the port. For pins 0-7, crl should be passed instead.
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);

// turn on the led
led.set_high();

// Acquire the GPIOA peripheral
let mut gpioa = dp.GPIOA.split();

// Configure gpio A pins 9 and 10 as a push-pull output. The `crh` register is passed to the
// function in order to configure the port. For pins 0-7, crl should be passed instead.
let tx = gpioa.pa9.into_alternate_push_pull(&mut gpioa.crh);
let rx = gpioa.pa10;

// Configure the serial peripheral
let serial = Serial::new(
dp.USART1,
(tx, rx),
&mut afio.mapr,
Config::default()
.baudrate(115_200.bps())
.wordlength_8bits()
.parity_none(),
&clocks,
);

// Split the serial struct into a receiving and a transmitting part
let (mut tx, _rx) = serial.split();

let s = b"\r\nBattery readings:\r\n";
let _ = s.iter().map(|c| block!(tx.write(*c))).last();

// Acquire the ADC1 peripheral
let mut adc1 = Adc::adc1(dp.ADC1, clocks);

// Get the GPIOB port
let mut gpiob = dp.GPIOB.split();

// Configure PB0 as an analog input
let mut pb0 = gpiob.pb0.into_analog(&mut gpiob.crl);

loop {
// Read the battery voltage, take 100 samples and average them (later, so we don't lose precision):
let mut battery_voltage_by_100: u32 = 0;
for _ in 0..100 {
let sample: u16 = adc1.read(&mut pb0).unwrap();
battery_voltage_by_100 += sample as u32;
}

// Convert the voltage to millivolts. We multiply the raw value by the battery voltage and
// divide by the resister divider. The maximum value is 8.4V and the resister divider is
// 47k and 20k. The raw value is 12 bits, so the maximum value is 4096 that corresponds to
// 2.5 volts in the ADC. The formula is:
let raw_to_millivolts_multiplier_by_1000 = 2857;
let battery_voltage_mv =
(battery_voltage_by_100 * raw_to_millivolts_multiplier_by_1000 / 100000) as u16;

// Print the raw value and the battery voltage to the serial port
let mut buf = [0; 5];
u16_to_str((battery_voltage_by_100 / 100) as u16, &mut buf);
let _ = buf.iter().map(|c| block!(tx.write(*c))).last();

let s = b" - ";
let _ = s.iter().map(|c| block!(tx.write(*c))).last();

let mut buf = [0; 5];
u16_to_str(battery_voltage_mv as u16, &mut buf);
let _ = buf.iter().map(|c| block!(tx.write(*c))).last();

let s = b" mVolts\r\n";
let _ = s.iter().map(|c| block!(tx.write(*c))).last();

delay.delay_ms(500_u16);
led.toggle();
}
}

// function that fills a buffer with the string representation of a number
fn u16_to_str(n: u16, buf: &mut [u8; 5]) {
let mut n = n;
for i in (0..5).rev() {
buf[i] = b'0' + (n % 10) as u8;
n /= 10;
}
}
41 changes: 41 additions & 0 deletions mightybuga_bsc/src/battery_sensor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use crate::{
hal::{
gpio::{Analog, Pin},
prelude::_embedded_hal_adc_OneShot,
},
ADC_POOL,
};
use battery_sensor_controller::BatterySensorController;
use heapless::pool::arc::Arc;

/// The battery sensor used to detect the battery level.
/// It uses 1 analog pin connected to the resistor divider and the ADC1 to read the voltage.
pub struct BatterySensor {
/// The pin for the battery sensor
pub sensor_0: Pin<'B', 0, Analog>,

pub adc: Arc<ADC_POOL>,
}

impl BatterySensorController for BatterySensor {
fn get_battery_millivolts(&mut self) -> u16 {
let mut adc = self.adc.borrow_mut();

// Read the battery voltage, take 10 samples and average them (later, so we don't lose precision):
let mut battery_voltage_by_10: u32 = 0;
for _ in 0..10 {
let sample: u16 = adc.read(&mut self.sensor_0).unwrap();
battery_voltage_by_10 += sample as u32;
}

// Convert the voltage to millivolts. We multiply the raw value by the battery voltage and
// divide by the resister divider. The maximum value is 8.4V and the resister divider is
// 47k and 20k. The raw value is 12 bits, so the maximum value is 4096 that corresponds to
// 2.5 volts in the ADC. The formula is:
let raw_to_millivolts_multiplier_by_1000 = 2857;
let battery_voltage_mv =
(battery_voltage_by_10 * raw_to_millivolts_multiplier_by_1000 / 10000) as u16;

battery_voltage_mv
}
}
11 changes: 11 additions & 0 deletions mightybuga_bsc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ use stm32f1xx_hal::timer::PwmChannel;
mod light_sensor_array;
use light_sensor_array::LightSensorArray;

mod battery_sensor;
use battery_sensor::BatterySensor;

pub use crate::hal::*;

pub mod timer_based_buzzer;
Expand Down Expand Up @@ -83,6 +86,8 @@ pub struct Mightybuga_BSC {
pub encoder_l: IncrementalEncoder,
// Light sensor array
pub light_sensor_array: LightSensorArray,
// Battery sensor
pub battery_sensor: BatterySensor,
}

impl Mightybuga_BSC {
Expand Down Expand Up @@ -220,6 +225,11 @@ impl Mightybuga_BSC {
adc: adc_arc.clone(),
};

let battery_sensor = BatterySensor {
sensor_0: gpiob.pb0.into_analog(&mut gpiob.crl),
adc: adc_arc.clone(),
};

// Return the initialized struct
Ok(Mightybuga_BSC {
led_d1: d1,
Expand All @@ -234,6 +244,7 @@ impl Mightybuga_BSC {
btn_2,
btn_3,
light_sensor_array,
battery_sensor,
})
}
}

0 comments on commit a9b8f1f

Please sign in to comment.