esp32笔记[10]-rust驱动ssd1306显示屏
摘要
使用rust(no-std)环境和esp-hal库实现SSD1306显示屏(128x64)显示bmp图片.
平台信息
- esp32(模组:ESP32-WROOM-32D)
-
- (xtensa lx6)(xtensa-esp32-none-elf)
- rust
超链接
开源地址
完整代码请移步如下网址:
[https://gitcode.net/QS2002/sugarheart]
原理简介
rust的include_bytes!宏
Rust的include_bytes!宏可以用来将本地文件加载为字节数组。这个宏会在编译时将指定的文件读取为字节数组,并将其嵌入到生成的二进制文件中。这样,你就可以在程序运行时直接访问这个字节数组,而不需要再次读取文件。
需要注意的是,include_bytes!宏只能在编译时加载文件,因此无法用于动态加载文件。
bmp图片的各种颜色空间
- RGB888
- RGB565
- Gray
BMP图片可以使用多种颜色空间来表示,其中包括RGB888、RGB565和Gray。以下是这些颜色空间的简要说明:
-
RGB888:
- 也被称为24位RGB,因为每个颜色(红色、绿色和蓝色)分别使用8位来表示,总共24位。
- 这为每种颜色提供了256个可能的阴影,因此总共可以表示1600多万种颜色。
- 是真彩色的一种表示方式,它提供了丰富的颜色信息,适用于需要高质量颜色的应用。
-
RGB565:
- 在这种颜色空间中,红色使用5位,绿色使用6位,蓝色使用5位来表示,总共16位。
- 相比RGB888,RGB565使用的空间更少,这降低了存储和带宽要求,但代价是颜色精度降低。
- 仍然可以表示相对较多的颜色(大约65,000种),对于许多应用来说足够接近真彩色。
-
Gray:
- 灰度色彩空间仅使用亮度信息,不使用色度信息。
- 图像中的每个像素只有一个通道,表示从黑色(0)到白色(255)的亮度。
- 适用于那些不关注颜色的应用,如一些文本或图标,或者用于黑白照片。
BMP图片格式简介:
BMP(Bitmap)是一种图像文件格式。它的设计相对简单,不采用任何压缩技术,因此通常占用较多的存储空间。
BMP文件的基本组成包括:位图文件头(Bitmap File Header)、位图信息头(Bitmap Info Header)和颜色表(Color Table)或称为调色板(Palette)。之后的数据就是实际的像素数据。
使用Rust结构体描述BMP图片数据结构:
在Rust中,我们可以使用结构体来描述BMP的数据结构。以下是一个非常基础的描述,它涵盖了BMP文件头和位图信息头。
#[derive(Debug)]
pub struct BitmapFileHeader {
pub signature: [u8; 2], // "BM"
pub file_size: u32,
pub reserved1: u16,
pub reserved2: u16,
pub offset_data: u32, // 通常为54
}
#[derive(Debug)]
pub struct BitmapInfoHeader {
pub size: u32, // 通常为40
pub width: i32,
pub height: i32,
pub planes: u16, // 必须为1
pub bit_count: u16, // 位数,如1、4、8、16、24、32等
pub compression: u32, // 0表示不压缩
pub size_image: u32, // 实际像素数据的大小
pub x_pixels_per_meter: i32,
pub y_pixels_per_meter: i32,
pub colors_used: u32,
pub colors_important: u32,
}
例如,对于24位的BMP图像,每个像素由三个字节表示,分别代表红、绿、蓝三种颜色。
ssd1306的128x64显示屏简介
SSD1306是一款OLED显示屏驱动芯片,它驱动的显示屏通常为128x64分辨率。这种显示屏被广泛应用于各种嵌入式系统和可穿戴设备中,如智能手表、手机、车载电子产品等。
OLED即有机发光二极管,这种显示屏技术具有自发光的特性,每一个像素都可以独立发光,因此色彩鲜艳,对比度高,视角广。
此外,由于SSD1306驱动的OLED显示屏是自发光的,所以它在显示黑色时像素是不发光的,这样就可以实现非常低的功耗。同时,SSD1306还具有内置的对比度控制、显示RAM和振荡器,进一步减少了外部组件和功耗。
总的来说,SSD1306的128x64 OLED显示屏具有高对比度、宽视角、低功耗、快速响应等优点,适用于需要高品质图像和长续航的各种应用场景。
实现
核心代码
/*
备注:
- 使用no-std,没有常规的main函数
- 串口波特率115200
- 不要占用SPI FLASH的GPIO(6,7,8,9,10,11)
目标平台:
- esp32s1(xtensa lx6)(xtensa-esp32-none-elf)
依赖:
- esp32-hal(0.16.0)
- esp-backtrace(0.9.0)
- esp-println(0.7.0)
- critical_section(1.1.2)
- embedded-svc(0.26.1)
- embedded-io(0.6.1)
- ssd1306(0.8.4)
- embedded_graphics(0.8.1)
- tinybmp(0.5.0)
编译及烧录命令:
- cargo-offline run
- (优先使用)cargo build --release
- cargo-offline build --release
- cargo-offline build --example main --release
*/
#![no_std]
#![no_main]
#![allow(unused_imports)]
#![allow(unused_parens)]
#![allow(unused_variables)]
#![allow(unused_unsafe)]
#![allow(dead_code)]
#![allow(unused_mut)]
#![feature(c_variadic)]
#![feature(const_mut_refs)]
#![feature(type_alias_impl_trait)]
use ssd1306::{
prelude::*,
I2CDisplayInterface,
Ssd1306,
mode::BufferedGraphicsMode,
mode::BasicMode,
};//ssd1306相关
use embedded_graphics::{
mono_font::{
ascii::{FONT_6X10, FONT_9X18_BOLD},
MonoTextStyleBuilder,
},
pixelcolor::BinaryColor,
prelude::*,
text::{Alignment, Text},
pixelcolor::Rgb565,
pixelcolor::Gray2,
pixelcolor::Rgb888,
image::Image,
};// ssd1306相关
use tinybmp::Bmp;// ssd1306相关
fn main()->!{
// 省略其他代码
// 配置ssd1306
let mut oled_sda = io.pins.gpio21.into_push_pull_output();
let mut oled_scl = io.pins.gpio22.into_push_pull_output();
let i2c = I2C::new(
peripherals.I2C0,
oled_sda,
oled_scl,
100u32.kHz(),
&clocks,
);
let interface = I2CDisplayInterface::new(i2c);
// 定义display变量
let mut display =
Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
.into_buffered_graphics_mode();
match display.init(){
Ok(_)=>{
println!("init ssd1306 ok!");
ssd1306_display(2,&mut display);
}
Err(_)=>{
println!("init ssd1306 failed!");
}
}
// 省略其他代码
}
// ssd1306显示封装
pub fn ssd1306_display(mode: u8, _display: &mut Ssd1306<I2CInterface<I2C<I2C0>>, DisplaySize128x64, BufferedGraphicsMode<DisplaySize128x64>>){
if(mode == 1){
// 显示文字logo
let text_style = MonoTextStyleBuilder::new()
.font(&FONT_6X10)
.text_color(BinaryColor::On)
.build();
let text_style_big = MonoTextStyleBuilder::new()
.font(&FONT_9X18_BOLD)
.text_color(BinaryColor::On)
.build();
Text::with_alignment(
"sugardraw",
_display.bounding_box().center() + Point::new(0, 0),
text_style_big,
Alignment::Center,
)
.draw(_display)
.unwrap();
Text::with_alignment(
"Chip: ESP32",
_display.bounding_box().center() + Point::new(0, 14),
text_style,
Alignment::Center,
)
.draw(_display)
.unwrap();
// 写入缓存到显示屏
_display.flush().unwrap();
// 清除显示屏缓存
_display.clear(BinaryColor::Off).unwrap();
}
else if(mode == 2){
// 显示bmp图片
let sugardraw_bmp_result = Bmp::<Rgb888>::from_slice(include_bytes!("./data/sugardraw_128x64.bmp"));
match sugardraw_bmp_result {
Ok(sugardraw_bmp) => {
let im: Image<Bmp<Rgb888>> = Image::new(&sugardraw_bmp, Point::new(0, 0));// 左上为原点,左边参数为纵轴,右边参数为横轴
im.draw(&mut _display.color_converted()).unwrap();
_display.flush().unwrap();
}
Err(error) => {
println!("Failed to load BMP image");
}
}
}
}// end ssd1306_display
编译配置
Cargo.toml
[dependencies.ssd1306]
version = "0.8.4"
[dependencies.tinybmp]
version = "0.5.0"
[dependencies.embedded-graphics]
version = "0.8.1"
.cargo/config.toml
[target.xtensa-esp32-none-elf]
runner = "espflash flash --monitor"
[build]
rustflags = [
"-C", "link-arg=-nostartfiles",
"-C", "link-arg=-Wl,-Tlinkall.x",
]
target = "xtensa-esp32-none-elf"
[unstable]
build-std = ["core","alloc"]