esp32笔记[10]-rust驱动ssd1306显示屏

摘要

使用rust(no-std)环境和esp-hal库实现SSD1306显示屏(128x64)显示bmp图片.

平台信息

  • esp32(模组:ESP32-WROOM-32D)
    • (xtensa lx6)(xtensa-esp32-none-elf)
  • rust

超链接

esp32笔记[7]-使用rust+zig开发入门

开源地址

完整代码请移步如下网址:
[https://gitcode.net/QS2002/sugarheart]

原理简介

rust的include_bytes!宏

Rust的include_bytes!宏可以用来将本地文件加载为字节数组。这个宏会在编译时将指定的文件读取为字节数组,并将其嵌入到生成的二进制文件中。这样,你就可以在程序运行时直接访问这个字节数组,而不需要再次读取文件。
需要注意的是,include_bytes!宏只能在编译时加载文件,因此无法用于动态加载文件。

bmp图片的各种颜色空间

  • RGB888
  • RGB565
  • Gray

BMP图片可以使用多种颜色空间来表示,其中包括RGB888、RGB565和Gray。以下是这些颜色空间的简要说明:

  1. RGB888

    • 也被称为24位RGB,因为每个颜色(红色、绿色和蓝色)分别使用8位来表示,总共24位。
    • 这为每种颜色提供了256个可能的阴影,因此总共可以表示1600多万种颜色。
    • 是真彩色的一种表示方式,它提供了丰富的颜色信息,适用于需要高质量颜色的应用。
  2. RGB565

    • 在这种颜色空间中,红色使用5位,绿色使用6位,蓝色使用5位来表示,总共16位。
    • 相比RGB888,RGB565使用的空间更少,这降低了存储和带宽要求,但代价是颜色精度降低。
    • 仍然可以表示相对较多的颜色(大约65,000种),对于许多应用来说足够接近真彩色。
  3. 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"]

效果

posted @ 2023-11-16 21:14  qsBye  阅读(460)  评论(0编辑  收藏  举报