esp32c3 运行 Rust(四)
通过 I2C 点亮 SSD1306。
环境
-
OS: Ubuntu 20.04.4 LTS
-
Rust: rustc 1.62.0-nightly
-
IDE: VsCode
-
ESP32C3: ESP-C3-13-Kit 开发板
GPIO title GPIO5 SDA GPIO6 SCL -
SSD1306: 0.96 寸 OLED 模块
创建项目
使用如下命令创建 ssd1306 项目,并修改项目配置
cargo generate --git https://github.com/esp-rs/esp-idf-template cargo
创建细节参见 esp32c3 运行 Rust(〇) 中 创建项目 HelloWorld。
点亮 OLED
-
安装相关依赖
在
Cargo.toml
中添加相关依赖- embedded-hal 嵌入式系统的硬件抽象层
- esp-idf-hal ESP32[-XX] + ESP-IDF 的
embedded-hal
实现 - anyhow
# ... [dependencies] # ... esp-idf-sys = { version = "0.31.1", features = ["binstart"] } embedded-hal = "0.2.7" # 添加这行 esp-idf-hal = "0.36.0" # 添加这行 anyhow = "1.0.57" # 添加这行 # ...
-
导入依赖
use std::{ thread, time::Duration, }; use embedded_hal::blocking::i2c::Write; use esp_idf_hal::{i2c, peripherals::Peripherals, prelude::*}; use anyhow;
-
定义 OLED 地址
//... const SSD1306_ADDRESS: u8 = 0x3c; //...
-
设置 I2C 引脚
//... fn main() -> anyhow::Result<()> { //... let peripherals = Peripherals::take().unwrap(); let sda = peripherals.pins.gpio5; let scl = peripherals.pins.gpio6; //... }
-
设置 I2C
//... let i2c = peripherals.i2c0; let config = <i2c::config::MasterConfig as Default>::default().baudrate(100.kHz().into()); let mut i2c = i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins{sda, scl}, config)?; //...
-
初始化 SSD1306
//... i2c.write(SSD1306_ADDRESS, &[0, 0xae])?; // 关闭显示 i2c.write(SSD1306_ADDRESS, &[0, 0x00])?; // Set lower column address i2c.write(SSD1306_ADDRESS, &[0, 0x10])?; // Set higher column address i2c.write(SSD1306_ADDRESS, &[0, 0x40])?; // Set display start line i2c.write(SSD1306_ADDRESS, &[0, 0xB0])?; // Set page address i2c.write(SSD1306_ADDRESS, &[0, 0x81])?; // contrast control i2c.write(SSD1306_ADDRESS, &[0, 0x7f])?; // default contrast is 0x7f i2c.write(SSD1306_ADDRESS, &[0, 0xa1])?; // Set segment remap i2c.write(SSD1306_ADDRESS, &[0, 0xa6])?; // 设置显示模式为正常显示 i2c.write(SSD1306_ADDRESS, &[0, 0xa8])?; // Multiplex ratio i2c.write(SSD1306_ADDRESS, &[0, 0x3f])?; // Duty = 1/64 i2c.write(SSD1306_ADDRESS, &[0, 0xc8])?; // Use remapped COM scan direction i2c.write(SSD1306_ADDRESS, &[0, 0xd3])?; // Set display offset i2c.write(SSD1306_ADDRESS, &[0, 0x00])?; // No offset i2c.write(SSD1306_ADDRESS, &[0, 0xd5])?; // Set display clock division i2c.write(SSD1306_ADDRESS, &[0, 0x80])?; // divide ratio i2c.write(SSD1306_ADDRESS, &[0, 0xd9])?; // Set pre-charge period i2c.write(SSD1306_ADDRESS, &[0, 0xf1])?; i2c.write(SSD1306_ADDRESS, &[0, 0xda])?; // Set COM pins i2c.write(SSD1306_ADDRESS, &[0, 0x12])?; i2c.write(SSD1306_ADDRESS, &[0, 0xdb])?; // Set vcomh deselect level i2c.write(SSD1306_ADDRESS, &[0, 0x40])?; i2c.write(SSD1306_ADDRESS, &[0, 0x8d])?; // Set charge pump state i2c.write(SSD1306_ADDRESS, &[0, 0x14])?; // charge pump enabled i2c.write(SSD1306_ADDRESS, &[0, 0xaf])?; // 打开显示 i2c.write(SSD1306_ADDRESS, &[0, 0x20, 0x00])?; // 设置显示模式 //...
-
清屏
//... println!("clear display"); let mut empty = vec![0x40]; empty.extend_from_slice(&[0u8; 1024]); i2c.write(SSD1306_ADDRESS, &empty)?; //...
-
显示内容
//... i2c.write(SSD1306_ADDRESS, &[0x40, 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x00, // H 0x00, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x00, // e 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, // l 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, // l 0x00, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, // o 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, 0x00, // W 0x00, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, // o 0x00, 0x00, 0x7C, 0x08, 0x04, 0x00, 0x00, 0x00, // r 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, // l 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, 0x00, 0x00, // d 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, // ! ])?; //...
-
编译并上传
连接开发板,使用如下命令编译并上传
cargo espflash --release --monitor /dev/ttyUSB0
完整代码
use std::{thread, time::Duration};
use embedded_hal::i2c::blocking::I2c;
use esp_idf_hal::{i2c, peripherals::Peripherals, prelude::*};
use anyhow;
const SSD1306_ADDRESS: u8 = 0x3c;
fn main() -> anyhow::Result<()> {
esp_idf_sys::link_patches();
let peripherals = Peripherals::take().unwrap();
let sda = peripherals.pins.gpio5;
let scl = peripherals.pins.gpio6;
let i2c = peripherals.i2c0;
let config = <i2c::config::MasterConfig as Default>::default().baudrate(100.kHz().into());
let mut i2c = i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config)?;
println!("init SSD1306");
i2c.write(SSD1306_ADDRESS, &[0, 0xae])?; // 关闭显示
i2c.write(SSD1306_ADDRESS, &[0, 0x00])?; // Set lower column address
i2c.write(SSD1306_ADDRESS, &[0, 0x10])?; // Set higher column address
i2c.write(SSD1306_ADDRESS, &[0, 0x40])?; // Set display start line
i2c.write(SSD1306_ADDRESS, &[0, 0xB0])?; // Set page address
i2c.write(SSD1306_ADDRESS, &[0, 0x81])?; // contrast control
i2c.write(SSD1306_ADDRESS, &[0, 0x7f])?; // default contrast is 0x7f
i2c.write(SSD1306_ADDRESS, &[0, 0xa1])?; // Set segment remap
i2c.write(SSD1306_ADDRESS, &[0, 0xa6])?; // 设置显示模式为正常显示
i2c.write(SSD1306_ADDRESS, &[0, 0xa8])?; // Multiplex ratio
i2c.write(SSD1306_ADDRESS, &[0, 0x3f])?; // Duty = 1/64
i2c.write(SSD1306_ADDRESS, &[0, 0xc8])?; // Use remapped COM scan direction
i2c.write(SSD1306_ADDRESS, &[0, 0xd3])?; // Set display offset
i2c.write(SSD1306_ADDRESS, &[0, 0x00])?; // No offset
i2c.write(SSD1306_ADDRESS, &[0, 0xd5])?; // Set display clock division
i2c.write(SSD1306_ADDRESS, &[0, 0x80])?; // divide ratio
i2c.write(SSD1306_ADDRESS, &[0, 0xd9])?; // Set pre-charge period
i2c.write(SSD1306_ADDRESS, &[0, 0xf1])?;
i2c.write(SSD1306_ADDRESS, &[0, 0xda])?; // Set COM pins
i2c.write(SSD1306_ADDRESS, &[0, 0x12])?;
i2c.write(SSD1306_ADDRESS, &[0, 0xdb])?; // Set vcomh deselect level
i2c.write(SSD1306_ADDRESS, &[0, 0x40])?;
i2c.write(SSD1306_ADDRESS, &[0, 0x8d])?; // Set charge pump state
i2c.write(SSD1306_ADDRESS, &[0, 0x14])?; // charge pump enabled
i2c.write(SSD1306_ADDRESS, &[0, 0xaf])?; // 打开显示
i2c.write(SSD1306_ADDRESS, &[0, 0x20, 0x00])?; // 设置显示模式
println!("clear display");
let mut empty = vec![0x40];
empty.extend_from_slice(&[0u8; 1024]);
i2c.write(SSD1306_ADDRESS, &empty)?;
println!("Hello world!");
i2c.write(
SSD1306_ADDRESS,
&[ 0x40,
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x00, // H
0x00, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x00, // e
0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, // l
0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, // l
0x00, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, // o
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, 0x00, // W
0x00, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, // o
0x00, 0x00, 0x7C, 0x08, 0x04, 0x00, 0x00, 0x00, // r
0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, // l
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, 0x00, 0x00, // d
0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, // !
],
)?;
thread::sleep(Duration::from_millis(1000));
loop {
thread::sleep(Duration::from_millis(1000));
}
}