天天看點

RVB2601應用開發實戰系列三: GUI圖形顯示

1. 前言

基于RVB2601的GUI程式是利用Lvgl開源元件實作在OLED螢幕上的字元和圖形顯示。開發者可以利用Lvgl元件在OLED螢幕上實作Label控件顯示功能。

建議在看本文之前,先詳細看下

RVB2601資源

。本例程名為ch2601_gui_demo,可以通過CDK直接從OCC拉取。

2. 硬體配置

2.1 顯示屏

RVB2601開發闆采用的是OLED顯示屏, 位于開發闆正面。

RVB2601應用開發實戰系列三: GUI圖形顯示

2.2 螢幕實體接口

CH2601開發闆采用單彩色圖形顯示面闆,螢幕分辨率128x64 pixel,螢幕背景顔色可選,該程式中采用的是一塊黃色背景的螢幕。螢幕控制器采用SSD1309,通過4 wire SPI接口與主晶片連接配接, 原理圖如下所示, 對應的pin引腳分别為PA27、PA28、PA29、PA30。 原理圖如下:

RVB2601應用開發實戰系列三: GUI圖形顯示

軟體通過對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後,打開工程可以看到以下目錄:

RVB2601應用開發實戰系列三: GUI圖形顯示

3.3 LVGL移植接口

Lvgl移植代碼位于app/src/lvgl_porting檔案夾内,其包含oled.c和oled.h。

RVB2601應用開發實戰系列三: GUI圖形顯示
  • 以下功能接口位于app/src/lvgl_porting/oled.c, 實作SPI管腳的初始化,主要針對CS, DATA, CLOCK, DATAIN管腳,同時實作了對不同管腳的讀寫操作。
1. static void oled_gpio_init()
2. {
3. //
4.     csi_gpio_pin_init(&pin_clk, PA28);
5.     csi_gpio_pin_dir(&pin_clk, GPIO_DIRECTION_OUTPUT);
6.     csi_gpio_pin_init(&pin_mosi, PA29);
7.     csi_gpio_pin_dir(&pin_mosi, GPIO_DIRECTION_OUTPUT);
8.     csi_gpio_pin_init(&pin_cs, PA27);
9.     csi_gpio_pin_dir(&pin_cs, GPIO_DIRECTION_OUTPUT);
10.     csi_gpio_pin_init(&pin_miso, PA30); //dc
11.     csi_gpio_pin_dir(&pin_miso, GPIO_DIRECTION_OUTPUT);
12. }
13. 
14. static void lcd_cs(uint8_t d)
15. {
16. if (d == 1) {
17.         csi_gpio_pin_write(&pin_cs, GPIO_PIN_HIGH);
18.     } else {
19.         csi_gpio_pin_write(&pin_cs, GPIO_PIN_LOW);
20.     }
21. }
22. 
23. static void lcd_dc(uint8_t d)
24. {
25. if (d == 1) {
26.         csi_gpio_pin_write(&pin_miso, GPIO_PIN_HIGH);
27.     } else {
28.         csi_gpio_pin_write(&pin_miso, GPIO_PIN_LOW);
29.     }
30. }
31. 
32. static void lcd_sclk(uint8_t d)
33. {
34. if (d == 1) {
35.         csi_gpio_pin_write(&pin_clk, GPIO_PIN_HIGH);
36.     } else {
37.         csi_gpio_pin_write(&pin_clk, GPIO_PIN_LOW);
38.     }
39. }
40. 
41. static void lcd_sdin(uint8_t d)
42. {
43. if (d == 1) {
44.         csi_gpio_pin_write(&pin_mosi, GPIO_PIN_HIGH);
45.     } else {
46.         csi_gpio_pin_write(&pin_mosi, GPIO_PIN_LOW);
47.     }
48. }
c      
  • 以下功能函數位于app/src/lvgl_porting/oled.c,通過SPI實作對螢幕的指令和資料寫操作。
1. void Write_Command(unsigned char Data)
2. {
3. unsigned char i;
4. 
5.     lcd_cs(0);
6.     lcd_dc(0);
7. for (i = 0; i < 8; i++) {
8.         lcd_sclk(0);
9.         lcd_sdin((Data & 0x80) >> 7);
10.         Data = Data << 1;
11.         lcd_sclk(1);
12.     }
13.     lcd_dc(1);
14.     lcd_cs(1);
15. }
16. 
17. void Write_Data(unsigned char Data)
18. {
19. unsigned char i;
20. 
21.     lcd_cs(0);
22.     lcd_dc(1);
23. for (i = 0; i < 8; i++) {
24.         lcd_sclk(0);
25.         lcd_sdin((Data & 0x80) >> 7);
26.         Data = Data << 1;
27.         lcd_sclk(1);
28.     }
29.     lcd_dc(1);
30.     lcd_cs(1);
31. }
c      
  • 以下功能函數位于app/src/lvgl_porting/oled.c檔案中,實作對螢幕的基本指令操作,例如設定螢幕行列位址,螢幕的亮度控制等。
1. void Set_Start_Column(unsigned char d)
2. {
3.     Write_Command(0x00 + d % 16); // Set Lower Column Start Address for Page Addressing Mode
4. //   Default => 0x00
5.     Write_Command(0x10 + d / 16); // Set Higher Column Start Address for Page Addressing Mode
6. //   Default => 0x10
7. }
8. 
9. void Set_Addressing_Mode(unsigned char d)
10. {
11.     Write_Command(0x20); // Set Memory Addressing Mode
12.     Write_Command(d);    //   Default => 0x02
13. //     0x00 => Horizontal Addressing Mode
14. //     0x01 => Vertical Addressing Mode
15. //     0x02 => Page Addressing Mode
16. }
17. 
18. void Set_Column_Address(unsigned char a, unsigned char b)
19. {
20.     Write_Command(0x21); // Set Column Address
21.     Write_Command(a);    //   Default => 0x00 (Column Start Address)
22.     Write_Command(b);    //   Default => 0x7F (Column End Address)
23. }
24. 
25. void Set_Page_Address(unsigned char a, unsigned char b)
26. {
27.     Write_Command(0x22); // Set Page Address
28.     Write_Command(a);    //   Default => 0x00 (Page Start Address)
29.     Write_Command(b);    //   Default => 0x07 (Page End Address)
30. }
31. 
32. void Set_Start_Line(unsigned char d)
33. {
34.     Write_Command(0x40 | d); // Set Display Start Line
35. //   Default => 0x40 (0x00)
36. }
37. 
38. void Set_Contrast_Control(unsigned char d)
39. {
40.     Write_Command(0x81); // Set Contrast Control for Bank 0
41.     Write_Command(d);    //   Default => 0x7F
42. }
43. 
44. void Set_Segment_Remap(unsigned char d)
45. {
46.     Write_Command(d); // Set Segment Re-Map
47. //   Default => 0xA0
48. //     0xA0 => Column Address 0 Mapped to SEG0
49. //     0xA1 => Column Address 0 Mapped to SEG127
50. }
51. 
52. void Set_Entire_Display(unsigned char d)
53. {
54.     Write_Command(d); // Set Entire Display On / Off
55. //   Default => 0xA4
56. //     0xA4 => Normal Display
57. //     0xA5 => Entire Display On
58. }
59. 
60. void Set_Inverse_Display(unsigned char d)
61. {
62.     Write_Command(d); // Set Inverse Display On/Off
63. //   Default => 0xA6
64. //     0xA6 => Normal Display
65. //     0xA7 => Inverse Display On
66. }
67. 
68. void Set_Multiplex_Ratio(unsigned char d)
69. {
70.     Write_Command(0xA8); // Set Multiplex Ratio
71.     Write_Command(d);    //   Default => 0x3F (1/64 Duty)
72. }
73. 
74. void Set_Display_On_Off(unsigned char d)
75. {
76.     Write_Command(d); // Set Display On/Off
77. //   Default => 0xAE
78. //     0xAE => Display Off
79. //     0xAF => Display On
80. }
81. 
82. void Set_Start_Page(unsigned char d)
83. {
84.     Write_Command(0xB0 | d); // Set Page Start Address for Page Addressing Mode
85. //   Default => 0xB0 (0x00)
86. }
87. 
88. void Set_Common_Remap(unsigned char d)
89. {
90.     Write_Command(d); // Set COM Output Scan Direction
91. //   Default => 0xC0
92. //     0xC0 => Scan from COM0 to 63
93. //     0xC8 => Scan from COM63 to 0
94. }
95. 
96. void Set_Display_Offset(unsigned char d)
97. {
98.     Write_Command(0xD3); // Set Display Offset
99.     Write_Command(d);    //   Default => 0x00
100. }
101. 
102. void Set_Display_Clock(unsigned char d)
103. {
104.     Write_Command(0xD5); // Set Display Clock Divide Ratio / Oscillator Frequency
105.     Write_Command(d);    //   Default => 0x70
106. //     D[3:0] => Display Clock Divider
107. //     D[7:4] => Oscillator Frequency
108. }
109. 
110. void Set_Low_Power(unsigned char d)
111. {
112.     Write_Command(0xD8); // Set Low Power Display Mode
113.     Write_Command(d);    //   Default => 0x04 (Normal Power Mode)
114. }
115. 
116. void Set_Precharge_Period(unsigned char d)
117. {
118.     Write_Command(0xD9); // Set Pre-Charge Period
119.     Write_Command(d); //   Default => 0x22 (2 Display Clocks [Phase 2] / 2 Display Clocks [Phase 1])
120. //     D[3:0] => Phase 1 Period in 1~15 Display Clocks
121. //     D[7:4] => Phase 2 Period in 1~15 Display Clocks
122. }
123. 
124. void Set_Common_Config(unsigned char d)
125. {
126.     Write_Command(0xDA); // Set COM Pins Hardware Configuration
127.     Write_Command(d);    //   Default => 0x12
128. //     Alternative COM Pin Configuration
129. //     Disable COM Left/Right Re-Map
130. }
131. 
132. void Set_NOP()
133. {
134.     Write_Command(0xE3); // Command for No Operation
135. }
136. 
137. void Set_Command_Lock(unsigned char d)
138. {
139.     Write_Command(0xFD); // Set Command Lock
140.     Write_Command(d);    //   Default => 0x12
141. //     0x12 => Driver IC interface is unlocked from entering command.
142. //     0x16 => All Commands are locked except 0xFD.
143. }
c      
  • 該功能函數位于app/src/lvgl_porting/oled.c檔案中,實作對螢幕的初始化。
1. static void oled_initialize()
2. {
3.     Set_Command_Lock(0x12);           // Unlock Driver IC (0x12/0x16)
4.     Set_Display_On_Off(0xAE);         // Display Off (0xAE/0xAF)
5.     Set_Display_Clock(0xA0);          // Set Clock as 116 Frames/Sec
6.     Set_Multiplex_Ratio(0x3F);        // 1/64 Duty (0x0F~0x3F)
7.     Set_Display_Offset(0x00);         // Shift Mapping RAM Counter (0x00~0x3F)
8.     Set_Start_Line(0x00);             // Set Mapping RAM Display Start Line (0x00~0x3F)
9.     Set_Low_Power(0x04);              // Set Normal Power Mode (0x04/0x05)
10.     Set_Addressing_Mode(0x02);        // Set Page Addressing Mode (0x00/0x01/0x02)
11.     Set_Segment_Remap(0xA1);          // Set SEG/Column Mapping (0xA0/0xA1)
12.     Set_Common_Remap(0xC8);           // Set COM/Row Scan Direction (0xC0/0xC8)
13.     Set_Common_Config(0x12);          // Set Alternative Configuration (0x02/0x12)
14.     Set_Contrast_Control(Brightness); // Set SEG Output Current
15.     Set_Precharge_Period(0x82);       // Set Pre-Charge as 8 Clocks & Discharge as 2 Clocks
16.     Set_VCOMH(0x34);                  // Set VCOM Deselect Level
17.     Set_Entire_Display(0xA4);         // Disable Entire Display On (0xA4/0xA5)
18.     Set_Inverse_Display(0xA6);        // Disable Inverse Display On (0xA6/0xA7)
19. 
20.     Fill_RAM(0x00); // Clear Screen
21. 
22.     Set_Display_On_Off(0xAF); // Display On (0xAE/0xAF)
23. }
c      
  • 該功能函數位于app/src/main.c檔案中,實作在螢幕固定處畫一個label, 顯示一串字元串。
1. static void gui_label_create(void)
2. {
3. lv_obj_t *p = lv_label_create(lv_scr_act(), NULL);
4.     lv_label_set_long_mode(p, LV_LABEL_LONG_BREAK);
5.     lv_label_set_align(p, LV_LABEL_ALIGN_CENTER);
6.     lv_obj_set_pos(p, 0, 4);
7.     lv_obj_set_size(p, 128, 60);
8.     lv_label_set_text(p, "THEAD RISC-V\nGUI\nDEMO");
9. }
c      

3.4. 編譯運作

編譯通過後,點選下載下傳,下載下傳成功後複位運作。可看屏上顯示"THEAD RISC-V\nGUI\nDEMO" 字元串。

RVB2601應用開發實戰系列三: GUI圖形顯示

4. 總結

本例程介紹了如何通過SPI接口來實作對OLED螢幕的圖形顯示。後續還有更多的開發例程,敬請期待!

繼續閱讀