-
Notifications
You must be signed in to change notification settings - Fork 8
/
ads1015-adc-display-bp.rs
169 lines (155 loc) · 5.02 KB
/
ads1015-adc-display-bp.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//! Measure the voltages with an ADS1015 analog/digital
//! converter and print them to an SSD1306 OLED display.
//!
//! You can see further explanations about this device and how this example
//! works here:
//!
//! https://blog.eldruin.com/ads1x1x-analog-to-digital-converter-driver-in-rust/
//!
//! This example is runs on the STM32F1 "BluePill" board using I2C1.
//!
//! ```
//! BP <-> ADS1015 <-> Display
//! GND <-> GND <-> GND
//! +5V <-> +5V <-> +5V
//! PB9 <-> SDA <-> SDA
//! PB8 <-> SCL <-> SCL
//! ```
//!
//! For example you can create a simple voltage divider with resistors.
//! The values do not matter much but it is nicer to understand if they are
//! all the same as the voltage will be divided equally.
//! I used 3 resistors of 20KOhm and the inputs of the ADC were connected
//! as follows:
//!
//! ```
//! ADS1015
//! +5V <-> A0
//! |
//! R3
//! | <-> A1
//! R2
//! | <-> A2
//! R1
//! |
//! GND <-> A3
//! ```
//!
//! You can see an image of this [here](https://github.com/eldruin/driver-examples/blob/master/media/ads1015-voltage-divider.jpg).
//!
//! With this setup we should get the reading for +5V on channel A0,
//! the reading for GND on channel A3 and A1 and A2 equally spaced in between
//! (within resistence tolerances).
//!
//! I get these values:
//! Channel 0: 1575
//! Channel 1: 1051
//! Channel 2: 524
//! Channel 3: 0
//!
//! We can calculate the relations and voltage that correspond to each channel if we
//! assume that 1575 corresponds to 5V.
//! Factor Voltage
//! Channel 0: 1575 / 1575 = 1 * 5V = 5V
//! Channel 1: 1051 / 1575 = 0.667 * 5V = 3.34V
//! Channel 2: 524 / 1575 = 0.333 * 5V = 1.66V
//! Channel 3: 0 / 1575 = 0 * 5V = 0V
//!
//! As you can see, the voltage was divided equally by all resistors.
//!
//! Run with:
//! `cargo embed --example ads1015-adc-display-bp --release`,
#![deny(unsafe_code)]
#![no_std]
#![no_main]
use ads1x1x::{channel as AdcChannel, Ads1x1x, FullScaleRange, SlaveAddr};
use core::fmt::Write;
use cortex_m_rt::entry;
use embedded_graphics::{
fonts::{Font6x8, Text},
pixelcolor::BinaryColor,
prelude::*,
style::TextStyleBuilder,
};
use nb::block;
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use ssd1306::{prelude::*, Builder, I2CDIBuilder};
use stm32f1xx_hal::{
delay::Delay,
i2c::{BlockingI2c, DutyCycle, Mode},
pac,
prelude::*,
};
#[entry]
fn main() -> ! {
rtt_init_print!();
rprintln!("ADS1015 example");
let cp = cortex_m::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();
let mut flash = dp.FLASH.constrain();
let rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.freeze(&mut flash.acr);
let mut afio = dp.AFIO.constrain();
let mut gpiob = dp.GPIOB.split();
let scl = gpiob.pb8.into_alternate_open_drain(&mut gpiob.crh);
let sda = gpiob.pb9.into_alternate_open_drain(&mut gpiob.crh);
let i2c = BlockingI2c::i2c1(
dp.I2C1,
(scl, sda),
&mut afio.mapr,
Mode::Fast {
frequency: 100_000.hz(),
duty_cycle: DutyCycle::Ratio2to1,
},
clocks,
1000,
10,
1000,
1000,
);
let mut gpioc = dp.GPIOC.split();
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
let mut delay = Delay::new(cp.SYST, clocks);
let manager = shared_bus::BusManagerSimple::new(i2c);
let interface = I2CDIBuilder::new().init(manager.acquire_i2c());
let mut disp: GraphicsMode<_> = Builder::new().connect(interface).into();
disp.init().unwrap();
let text_style = TextStyleBuilder::new(Font6x8)
.text_color(BinaryColor::On)
.build();
let mut adc = Ads1x1x::new_ads1015(manager.acquire_i2c(), SlaveAddr::default());
// need to be able to measure [0-5V]
adc.set_full_scale_range(FullScaleRange::Within6_144V)
.unwrap();
loop {
// Blink LED 0 to check that everything is actually running.
// If the LED 0 is off, something went wrong.
led.set_high();
delay.delay_ms(50_u16);
led.set_low();
delay.delay_ms(50_u16);
// Read voltage in all channels
let values = [
block!(adc.read(&mut AdcChannel::SingleA0)).unwrap_or(8091),
block!(adc.read(&mut AdcChannel::SingleA1)).unwrap_or(8091),
block!(adc.read(&mut AdcChannel::SingleA2)).unwrap_or(8091),
block!(adc.read(&mut AdcChannel::SingleA3)).unwrap_or(8091),
];
let mut lines: [heapless::String<32>; 4] = [
heapless::String::new(),
heapless::String::new(),
heapless::String::new(),
heapless::String::new(),
];
disp.clear();
for i in 0..values.len() {
write!(lines[i], "Channel {}: {}", i, values[i]).unwrap();
Text::new(&lines[i], Point::new(0, i as i32 * 16))
.into_styled(text_style)
.draw(&mut disp)
.unwrap();
}
disp.flush().unwrap();
}
}