写点什么

RVB2601 应用开发实战系列三: GUI 图形显示

发布于: 2 小时前
RVB2601应用开发实战系列三: GUI图形显示

关键词:RISC-V 开发板、RVB2601、WiFi&BLE,低功耗,玄铁 E906,AliOS Things,RISC-V  MCU,上手 好用,控制,开关


1. 前言

基于 RVB2601 的 GUI 程序是利用 Lvgl 开源组件实现在 OLED 屏幕上的字符和图形显示。开发者可以利用 Lvgl 组件在 OLED 屏幕上实现 Label 控件显示功能。


建议在看本文之前,先详细看下RVB2601资源。本例程名为 ch2601_gui_demo,可以通过 CDK 直接从 OCC 拉取。


2. 硬件配置

2.1 显示屏

RVB2601 开发板采用的是 OLED 显示屏, 位于开发板正面。


2.2 屏幕物理接口

CH2601 开发板采用单彩色图形显示面板,屏幕分辨率 128x64 pixel,屏幕背景颜色可选,该程序中采用的是一块黄色背景的屏幕。屏幕控制器采用 SSD1309,通过 4 wire SPI 接口与主芯片连接, 原理图如下所示, 对应的 pin 引脚分别为 PA27、PA28、PA29、PA30。 原理图如下:

软件通过对 SPI 进行读写操作来实现对 OLED 屏上的像素进行点操作,从而实现整个屏的点亮操作。


3. GUI 软件开发

3.1 LVGL 介绍

LVGL 全称 Light and Versatile Graphics Library,是一个自由的,开源的 GUI 库,具有界面精美,资源消耗小,可移植度高, 响应式布局等特点, 全库采用纯 c 语言开发.

主要特性如下.

  • 具有非常丰富的内置控件,像 buttons, charts, lists, sliders, images 等

  • 高级图形效果:动画,反锯齿,透明度,平滑滚动

  • 支持多种输入设备,像 touchpad, mouse, keyboard, encoder 等

  • 支持多语言的 UTF-8 编码

  • 支持多个和多种显示设备,例如同步显示在多个彩色屏或单色屏上

  • 完全自定制的图形元素

  • 硬件独立于任何微控制器或显示器

  • 可以缩小到最小内存 (64 kB Flash, 16 kB RAM)

  • 支持操作系统、外部储存和 GPU(非必须)

  • 仅仅单个帧缓冲设备就可以呈现高级视觉特效

  • 使用 C 编写以获得最大兼容性(兼容 C++)

  • 支持 PC 模拟器

  • 为加速 GUI 设计,提供教程,案例和主题,支持响应式布局

  • 提供了在线和离线文档

  • 基于自由和开源的 MIT 协议

  • 支持 MicroPython


3.2 例程下载

打开 CDK,点击 HOME 图标,查找 ch2601_gui_demo 后,打开工程可以看到以下目录:


3.3 LVGL 移植接口

Lvgl 移植代码位于 app/src/lvgl_porting 文件夹内,其包含 oled.c 和 oled.h。


  • 以下功能接口位于 app/src/lvgl_porting/oled.c, 实现 SPI 管脚的初始化,主要针对 CS, DATA, CLOCK, DATAIN 管脚,同时实现了对不同管脚的读写操作。

static void oled_gpio_init(){    //    csi_gpio_pin_init(&pin_clk, PA28);    csi_gpio_pin_dir(&pin_clk, GPIO_DIRECTION_OUTPUT);    csi_gpio_pin_init(&pin_mosi, PA29);    csi_gpio_pin_dir(&pin_mosi, GPIO_DIRECTION_OUTPUT);    csi_gpio_pin_init(&pin_cs, PA27);    csi_gpio_pin_dir(&pin_cs, GPIO_DIRECTION_OUTPUT);    csi_gpio_pin_init(&pin_miso, PA30); //dc    csi_gpio_pin_dir(&pin_miso, GPIO_DIRECTION_OUTPUT);}static void lcd_cs(uint8_t d){    if (d == 1) {        csi_gpio_pin_write(&pin_cs, GPIO_PIN_HIGH);    } else {        csi_gpio_pin_write(&pin_cs, GPIO_PIN_LOW);    }}static void lcd_dc(uint8_t d){    if (d == 1) {        csi_gpio_pin_write(&pin_miso, GPIO_PIN_HIGH);    } else {        csi_gpio_pin_write(&pin_miso, GPIO_PIN_LOW);    }}static void lcd_sclk(uint8_t d){    if (d == 1) {        csi_gpio_pin_write(&pin_clk, GPIO_PIN_HIGH);    } else {        csi_gpio_pin_write(&pin_clk, GPIO_PIN_LOW);    }}static void lcd_sdin(uint8_t d){    if (d == 1) {        csi_gpio_pin_write(&pin_mosi, GPIO_PIN_HIGH);    } else {        csi_gpio_pin_write(&pin_mosi, GPIO_PIN_LOW);    }}
复制代码


  • 以下功能函数位于 app/src/lvgl_porting/oled.c,通过 SPI 实现对屏幕的命令和数据写操作。

void Write_Command(unsigned char Data){    unsigned char i;    lcd_cs(0);    lcd_dc(0);    for (i = 0; i < 8; i++) {        lcd_sclk(0);        lcd_sdin((Data & 0x80) >> 7);        Data = Data << 1;        lcd_sclk(1);    }    lcd_dc(1);    lcd_cs(1);}void Write_Data(unsigned char Data){    unsigned char i;    lcd_cs(0);    lcd_dc(1);    for (i = 0; i < 8; i++) {        lcd_sclk(0);        lcd_sdin((Data & 0x80) >> 7);        Data = Data << 1;        lcd_sclk(1);    }    lcd_dc(1);    lcd_cs(1);}
复制代码


  • 以下功能函数位于 app/src/lvgl_porting/oled.c 文件中,实现对屏幕的基本命令操作,例如设置屏幕行列地址,屏幕的亮度控制等。

void Set_Start_Column(unsigned char d){    Write_Command(0x00 + d % 16); // Set Lower Column Start Address for Page Addressing Mode                                  //   Default => 0x00    Write_Command(0x10 + d / 16); // Set Higher Column Start Address for Page Addressing Mode                                  //   Default => 0x10}void Set_Addressing_Mode(unsigned char d){    Write_Command(0x20); // Set Memory Addressing Mode    Write_Command(d);    //   Default => 0x02                         //     0x00 => Horizontal Addressing Mode                         //     0x01 => Vertical Addressing Mode                         //     0x02 => Page Addressing Mode}void Set_Column_Address(unsigned char a, unsigned char b){    Write_Command(0x21); // Set Column Address    Write_Command(a);    //   Default => 0x00 (Column Start Address)    Write_Command(b);    //   Default => 0x7F (Column End Address)}void Set_Page_Address(unsigned char a, unsigned char b){    Write_Command(0x22); // Set Page Address    Write_Command(a);    //   Default => 0x00 (Page Start Address)    Write_Command(b);    //   Default => 0x07 (Page End Address)}void Set_Start_Line(unsigned char d){    Write_Command(0x40 | d); // Set Display Start Line                             //   Default => 0x40 (0x00)}void Set_Contrast_Control(unsigned char d){    Write_Command(0x81); // Set Contrast Control for Bank 0    Write_Command(d);    //   Default => 0x7F}void Set_Segment_Remap(unsigned char d){    Write_Command(d); // Set Segment Re-Map                      //   Default => 0xA0                      //     0xA0 => Column Address 0 Mapped to SEG0                      //     0xA1 => Column Address 0 Mapped to SEG127}void Set_Entire_Display(unsigned char d){    Write_Command(d); // Set Entire Display On / Off                      //   Default => 0xA4                      //     0xA4 => Normal Display                      //     0xA5 => Entire Display On}void Set_Inverse_Display(unsigned char d){    Write_Command(d); // Set Inverse Display On/Off                      //   Default => 0xA6                      //     0xA6 => Normal Display                      //     0xA7 => Inverse Display On}void Set_Multiplex_Ratio(unsigned char d){    Write_Command(0xA8); // Set Multiplex Ratio    Write_Command(d);    //   Default => 0x3F (1/64 Duty)}void Set_Display_On_Off(unsigned char d){    Write_Command(d); // Set Display On/Off                      //   Default => 0xAE                      //     0xAE => Display Off                      //     0xAF => Display On}void Set_Start_Page(unsigned char d){    Write_Command(0xB0 | d); // Set Page Start Address for Page Addressing Mode                             //   Default => 0xB0 (0x00)}void Set_Common_Remap(unsigned char d){    Write_Command(d); // Set COM Output Scan Direction                      //   Default => 0xC0                      //     0xC0 => Scan from COM0 to 63                      //     0xC8 => Scan from COM63 to 0}void Set_Display_Offset(unsigned char d){    Write_Command(0xD3); // Set Display Offset    Write_Command(d);    //   Default => 0x00}void Set_Display_Clock(unsigned char d){    Write_Command(0xD5); // Set Display Clock Divide Ratio / Oscillator Frequency    Write_Command(d);    //   Default => 0x70                         //     D[3:0] => Display Clock Divider                         //     D[7:4] => Oscillator Frequency}void Set_Low_Power(unsigned char d){    Write_Command(0xD8); // Set Low Power Display Mode    Write_Command(d);    //   Default => 0x04 (Normal Power Mode)}void Set_Precharge_Period(unsigned char d){    Write_Command(0xD9); // Set Pre-Charge Period    Write_Command(d); //   Default => 0x22 (2 Display Clocks [Phase 2] / 2 Display Clocks [Phase 1])                      //     D[3:0] => Phase 1 Period in 1~15 Display Clocks                      //     D[7:4] => Phase 2 Period in 1~15 Display Clocks}void Set_Common_Config(unsigned char d){    Write_Command(0xDA); // Set COM Pins Hardware Configuration    Write_Command(d);    //   Default => 0x12                         //     Alternative COM Pin Configuration                         //     Disable COM Left/Right Re-Map}void Set_NOP(){    Write_Command(0xE3); // Command for No Operation}void Set_Command_Lock(unsigned char d){    Write_Command(0xFD); // Set Command Lock    Write_Command(d);    //   Default => 0x12                         //     0x12 => Driver IC interface is unlocked from entering command.                         //     0x16 => All Commands are locked except 0xFD.}
复制代码


  • 该功能函数位于 app/src/lvgl_porting/oled.c 文件中,实现对屏幕的初始化。

static void oled_initialize(){    Set_Command_Lock(0x12);           // Unlock Driver IC (0x12/0x16)    Set_Display_On_Off(0xAE);         // Display Off (0xAE/0xAF)    Set_Display_Clock(0xA0);          // Set Clock as 116 Frames/Sec    Set_Multiplex_Ratio(0x3F);        // 1/64 Duty (0x0F~0x3F)    Set_Display_Offset(0x00);         // Shift Mapping RAM Counter (0x00~0x3F)    Set_Start_Line(0x00);             // Set Mapping RAM Display Start Line (0x00~0x3F)    Set_Low_Power(0x04);              // Set Normal Power Mode (0x04/0x05)    Set_Addressing_Mode(0x02);        // Set Page Addressing Mode (0x00/0x01/0x02)    Set_Segment_Remap(0xA1);          // Set SEG/Column Mapping (0xA0/0xA1)    Set_Common_Remap(0xC8);           // Set COM/Row Scan Direction (0xC0/0xC8)    Set_Common_Config(0x12);          // Set Alternative Configuration (0x02/0x12)    Set_Contrast_Control(Brightness); // Set SEG Output Current    Set_Precharge_Period(0x82);       // Set Pre-Charge as 8 Clocks & Discharge as 2 Clocks    Set_VCOMH(0x34);                  // Set VCOM Deselect Level    Set_Entire_Display(0xA4);         // Disable Entire Display On (0xA4/0xA5)    Set_Inverse_Display(0xA6);        // Disable Inverse Display On (0xA6/0xA7)    Fill_RAM(0x00); // Clear Screen    Set_Display_On_Off(0xAF); // Display On (0xAE/0xAF)}
复制代码


  • 该功能函数位于 app/src/main.c 文件中,实现在屏幕固定处画一个 label, 显示一串字符串。

static void gui_label_create(void){    lv_obj_t *p = lv_label_create(lv_scr_act(), NULL);    lv_label_set_long_mode(p, LV_LABEL_LONG_BREAK);    lv_label_set_align(p, LV_LABEL_ALIGN_CENTER);    lv_obj_set_pos(p, 0, 4);    lv_obj_set_size(p, 128, 60);    lv_label_set_text(p, "THEAD RISC-V\nGUI\nDEMO");}
复制代码


3.4. 编译运行

编译通过后,点击下载,下载成功后复位运行。可看屏上显示"THEAD RISC-V\nGUI\nDEMO" 字符串。

4. 总结

本例程介绍了如何通过 SPI 接口来实现对 OLED 屏幕的图形显示。后续还有更多的开发例程,敬请期待!


本文转自平头哥芯片开放社区(occ),更多详情请点击https://occ.t-head.cn/store/board?channelName=1

用户头像

还未添加个人签名 2021.08.24 加入

还未添加个人简介

评论

发布
暂无评论
RVB2601应用开发实战系列三: GUI图形显示