[文章]基于小凌派RK2206开发板-LCD液晶屏显示案例

阅读量0
0
4
一、简介
LCD的应用很广泛,简单如手表上的液晶显示屏,仪表仪器上的液晶显示器或者是电脑笔记本上的液晶显示器,都使用了LCD。在一般的办公设备上也很常见,如传真机,复印机,以及一些娱乐器材玩具等也常常见到LCD的足迹。
本小节使用的是ST7789V, 用于单片驱动262K色图像TFT-LCD, 包含 720(240*3色) x 320 线输出, 可以直接以SPI协议, 或者8位/9位/16位/18位并行连接外部控制器。ST7789V显示数据存储在片内240x320x18 bits内存中, 显示内存的读写不需要外部时钟驱动。
二、硬件电路设计
模块整体硬件电路如图1所示,电路中包含了电源电路、液晶接口以及小凌派-RK2206开发板连接的相关引脚。
图片1.png
                        图1 硬件电路图
其中,液晶屏ST7789V的相关引脚资源如图2所示。
图片2.png

图2 液晶屏ST7789V硬件资源示意图
其中,LCD液晶屏引脚功能描述,如下表1所示。
表1 LCD液晶屏引脚功能表
序号        LCD引脚        功能描述

序号
LCD引脚
功能描述
1
D/C
指令/数据选择端,L:指令,H:数据
2
RESET
复位信号线,低电平有效
3
SPI_MOSI
SPI数据输入信号线
4
SPI_CLK
SPI时钟信号线
5
SPI_CS
SPI片选信号线,低电平有效
6
GND
电源地引脚
7
5V
5V电源输入引脚
其中,LCD液晶屏与小凌派-RK2206开发板连接如图3所示。
图片3.png

图3 2.4寸液晶屏和小凌派-RK2206开发板连接图
三、软件设计
本章节将利用小凌派-RK2206开发板上的GPIO和SPI接口方式来点亮2.4寸液晶屏,并实现ASCII字符的显示及汉字的显示。
1. 主程序设计
如图4所示为LCD液晶屏主程序流程图,开机LiteOS系统初始化后,进入主程序。主程序首先进行GPIO和SPI总线初始化,然后配置LCD液晶屏设备,最后进入循环中。在循环中,主程序控制SPI对LCD液晶屏进行ASCII字符和汉字显示。
图片4.png

图4 主程序流程图
2. LCD初始化程序设计
LCD初始化程序主要分为GPIO和SPI总线初始化,配置LCD两部分。
其中,GPIO初始化首先用LzGpioInit()函数将GPIO0_PC3初始化为GPIO引脚,然后用LzGpioSetDir()将引脚设置为输出模式,最后调用LzGpioSetVal()输出低电平。
  1.      /* 初始化GPIO0_C3 */
  2.     LzGpioInit(LCD_PIN_RES);
  3.     LzGpioSetDir(LCD_PIN_RES, LZGPIO_DIR_OUT);
  4.     LzGpioSetVal(LCD_PIN_RES, LZGPIO_LEVEL_HIGH);

  5.     /* 初始化GPIO0_C6 */
  6.     LzGpioInit(LCD_PIN_DC);
  7.     LzGpioSetDir(LCD_PIN_DC, LZGPIO_DIR_OUT);
  8.     LzGpioSetVal(LCD_PIN_DC, LZGPIO_LEVEL_LOW);
复制代码
SPI初始化首先用SpiIoInit()函数将GPIO0_PC0复用为SPI0_CS0n_M1,GPIO0_PC1复用为SPI0_CLK_M1,GPIO0_PC2复用为SPI0_MOSI_M1。其次调用LzI2cInit()函数初始化SPI0端口。
  1.    LzSpiDeinit(LCD_SPI_BUS);

  2.     if (SpiIoInit(m_spiBus) != LZ_HARDWARE_SUCCESS) {
  3.         printf("%s, %d: SpiIoInit failed!n", __FILE__, __LINE__);
  4.         return __LINE__;
  5.     }
  6.     if (LzSpiInit(LCD_SPI_BUS, m_spiConf) != LZ_HARDWARE_SUCCESS) {
  7.         printf("%s, %d: LzSpiInit failed!n", __FILE__, __LINE__);
  8.         return __LINE__;
  9.     }
复制代码
配置LCD主要是配置ST7789V的工作模式,具体代码如下所示:
  1. /* 重启lcd */
  2.     LCD_RES_Clr();
  3.     LOS_Msleep(100);
  4.     LCD_RES_Set();
  5.     LOS_Msleep(100);
  6.     LOS_Msleep(500);
  7.     lcd_wr_reg(0x11);
  8.     /* 等待LCD 100ms */
  9.     LOS_Msleep(100);
  10.     /* 启动LCD配置,设置显示和颜色配置 */
  11.     lcd_wr_reg(0X36);
  12.     if (USE_HORIZONTAL == 0)
  13.     {
  14.         lcd_wr_data8(0x00);
  15.     }
  16.     else if (USE_HORIZONTAL == 1)
  17.     {
  18.         lcd_wr_data8(0xC0);
  19.     }
  20.     else if (USE_HORIZONTAL == 2)
  21.     {
  22.         lcd_wr_data8(0x70);
  23.     }
  24.     else
  25.     {
  26.         lcd_wr_data8(0xA0);
  27.     }
  28.     lcd_wr_reg(0X3A);
  29.     lcd_wr_data8(0X05);
  30.     /* ST7789S帧刷屏率设置 */
  31.     lcd_wr_reg(0xb2);
  32.     lcd_wr_data8(0x0c);
  33.     lcd_wr_data8(0x0c);
  34.     lcd_wr_data8(0x00);
  35.     lcd_wr_data8(0x33);
  36.     lcd_wr_data8(0x33);
  37.     lcd_wr_reg(0xb7);
  38.     lcd_wr_data8(0x35);
  39.     /* ST7789S电源设置 */
  40.     lcd_wr_reg(0xbb);
  41.     lcd_wr_data8(0x35);
  42.     lcd_wr_reg(0xc0);
  43.     lcd_wr_data8(0x2c);
  44.     lcd_wr_reg(0xc2);
  45.     lcd_wr_data8(0x01);
  46.     lcd_wr_reg(0xc3);
  47.     lcd_wr_data8(0x13);
  48.     lcd_wr_reg(0xc4);
  49.     lcd_wr_data8(0x20);
  50.     lcd_wr_reg(0xc6);
  51.     lcd_wr_data8(0x0f);
  52.     lcd_wr_reg(0xca);
  53.     lcd_wr_data8(0x0f);
  54.     lcd_wr_reg(0xc8);
  55.     lcd_wr_data8(0x08);
  56.     lcd_wr_reg(0x55);
  57.     lcd_wr_data8(0x90);
  58.     lcd_wr_reg(0xd0);
  59.     lcd_wr_data8(0xa4);
  60.     lcd_wr_data8(0xa1);
  61.     /* ST7789S gamma设置 */
  62.     lcd_wr_reg(0xe0);
  63.     lcd_wr_data8(0xd0);
  64.     lcd_wr_data8(0x00);
  65.     lcd_wr_data8(0x06);
  66.     lcd_wr_data8(0x09);
  67.     lcd_wr_data8(0x0b);
  68.     lcd_wr_data8(0x2a);
  69.     lcd_wr_data8(0x3c);
  70.     lcd_wr_data8(0x55);
  71.     lcd_wr_data8(0x4b);
  72.     lcd_wr_data8(0x08);
  73.     lcd_wr_data8(0x16);
  74.     lcd_wr_data8(0x14);
  75.     lcd_wr_data8(0x19);
  76.     lcd_wr_data8(0x20);
  77.     lcd_wr_reg(0xe1);
  78.     lcd_wr_data8(0xd0);
  79.     lcd_wr_data8(0x00);
  80.     lcd_wr_data8(0x06);
  81.     lcd_wr_data8(0x09);
  82.     lcd_wr_data8(0x0b);
  83.     lcd_wr_data8(0x29);
  84.     lcd_wr_data8(0x36);
  85.     lcd_wr_data8(0x54);
  86.     lcd_wr_data8(0x4b);
  87.     lcd_wr_data8(0x0d);
  88.     lcd_wr_data8(0x16);
  89.     lcd_wr_data8(0x14);
  90.     lcd_wr_data8(0x21);
  91.     lcd_wr_data8(0x20);
  92.     lcd_wr_reg(0x29);
复制代码
3. LCD的点数据设计
ST7789V采用SPI通信方式,数据传输协议如下:
4-Line Serial Interface => 16-bit/pixel(RGB 5-6-5-bit input),65K-Color,3Ah="05h"
数据传输时序图如图5所示。
图片5.png

图5 ST7789V液晶屏SPI数据传输时序图
也就是每个像素占用2个字节,RGB为5+6+5。因此,往LCD液晶屏发送某一个像素信息的程序如下所示:
  1. static void lcd_write_bus(uint8_t dat)
  2. {
  3.     LzSpiWrite(LCD_SPI_BUS, 0, &dat, 1);
  4. }

  5. static void lcd_wr_data(uint16_t dat)
  6. {
  7.     lcd_write_bus(dat >> 8);
  8.     lcd_write_bus(dat);
  9. }

  10. static void lcd_wr_reg(uint8_t dat)
  11. {
  12.     LCD_DC_Clr();
  13.     lcd_write_bus(dat);
  14.     LCD_DC_Set();
  15. }

  16. static void lcd_address_set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
  17. {
  18.     /* 列地址设置 */
  19.     lcd_wr_reg(0x2a);
  20.     lcd_wr_data(x1);
  21.     lcd_wr_data(x2);
  22.     /* 行地址设置 */
  23.     lcd_wr_reg(0x2b);
  24.     lcd_wr_data(y1);
  25.     lcd_wr_data(y2);
  26.     /* 储存器写 */
  27.     lcd_wr_reg(0x2c);
  28. }

  29. static void lcd_wr_data(uint16_t dat)
  30. {
  31.     lcd_write_bus(dat >> 8);
  32.     lcd_write_bus(dat);
  33. }

  34. void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)
  35. {
  36.     /* 设置光标位置 */
  37.     lcd_address_set(x, y, x, y);
  38.     lcd_wr_data(color);
  39. }
复制代码
4. LCD的ASCII字符显示设计
预先将规定字号的ASCII字符的LCD液晶屏像素信息存放于在lcd_font.h源代码文件中。该表格依照ASCII的数值来存放像素信息。例如:空格的ASCII数值是0x0,则程序将像素放到第一行像素中,如下源代码所示。
  1. /* 12*6的ASCII码显示 */
  2. const unsigned char ascii_1206[][12] =
  3. {
  4.     {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*" ",0*/
  5.     {0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00}, /*"!",1*/
  6.     {0x14, 0x14, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*""",2*/
  7.     {0x00, 0x00, 0x0A, 0x0A, 0x1F, 0x0A, 0x0A, 0x1F, 0x0A, 0x0A, 0x00, 0x00}, /*"#",3*/
  8. {0x00, 0x04, 0x0E, 0x15, 0x05, 0x06, 0x0C, 0x14, 0x15, 0x0E, 0x04, 0x00}, /*"$",4*/
  9. .......
  10. };

  11. /* 16*8的ASCII码显示 */
  12. const unsigned char ascii_1608[][16] =
  13. {
  14.     {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*" ",0*/
  15.     {0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00}, /*"!",1*/
  16.     {0x00, 0x48, 0x6C, 0x24, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*""",2*/
  17. {0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x7F, 0x12, 0x12, 0x12, 0x7F, 0x12, 0x12, 0x12, 0x00, 0x00}, /*"#",3*/
  18. ......
  19. };

  20. /* 24*12的ASCII码显示 */
  21. const unsigned char ascii_2412[][48] =
  22. {
  23.     {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*" ",0*/
  24.     {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"!",1*/
  25. {0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x60, 0x06, 0x30, 0x03, 0x98, 0x01, 0x88, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*""",2*/
  26. ......
  27. };
复制代码
当需要将某一个字号的ASCII字符投射到LCD液晶屏时,程序根据字号大小找到对应的字号的ASCII字符像素表,然后根据ASCII字符的数值找到对应的像素行,最后将该像素行数据依次通过SPI总线发送给LCD液晶屏。如下源代码所示。
  1. void lcd_show_char(uint16_t x, uint16_t y, uint8_t num, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
  2. {
  3.     uint8_t temp,sizex,t,m = 0;
  4.     uint16_t i;
  5.     uint16_t TypefaceNum;//一个字符所占字节大小
  6.     uint16_t x0 = x;
  7.    
  8.     sizex = sizey/2;
  9.     TypefaceNum = (sizex/8 + ((sizex%8)?1:0)) * sizey;

  10.     /* 得到偏移后的值 */
  11.     num = num-' ';
  12.     /* 设置光标位置 */
  13.     lcd_address_set(x, y, x+sizex-1, y+sizey-1);
  14.    
  15.     for (i = 0; i < TypefaceNum; i++)
  16.     {
  17.         if (sizey == 12)
  18.         {
  19.             /* 调用6x12字体 */
  20.             temp = ascii_1206[num][i];
  21.         }
  22.         else if (sizey == 16)
  23.         {
  24.             /* 调用8x16字体 */
  25.             temp = ascii_1608[num][i];
  26.         }
  27.         else if (sizey == 24)
  28.         {
  29.             /* 调用12x24字体 */
  30.             temp = ascii_2412[num][i];
  31.         }
  32.         else if (sizey == 32)
  33.         {
  34.             /* 调用16x32字体 */
  35.             temp = ascii_3216[num][i];
  36.         }
  37.         else
  38.         {
  39.             return;
  40.         }
  41.         
  42.         for (t = 0; t < 8; t++)
  43.         {
  44.             if (!mode)
  45.             {/* 非叠加模式 */
  46.                 if (temp & (0x01 << t))
  47.                 {
  48.                     lcd_wr_data(fc);
  49.                 }
  50.                 else
  51.                 {
  52.                     lcd_wr_data(bc);
  53.                 }
  54.                
  55.                 m++;
  56.                 if (m%sizex == 0)
  57.                 {
  58.                     m = 0;
  59.                     break;
  60.                 }
  61.             }
  62.             else
  63.             {/* 叠加模式 */
  64.                 if (temp & (0x01 << t))
  65.                 {
  66.                     /* 画一个点 */
  67.                     lcd_draw_point(x, y, fc);
  68.                 }
  69.                
  70.                 x++;
  71.                 if ((x - x0) == sizex)
  72.                 {
  73.                     x = x0;
  74.                     y++;
  75.                     break;
  76.                 }
  77.             }
  78.         }
  79.     }            
  80. }
复制代码

5. LCD的汉字显示设计
同上原理,程序将某一个特定字号的汉字信息存放于一个数据结构体数组中。该数据结构体包含字体编码Index和像素数据Msk。具体原代码如下所示。
  1. /* 定义中文字符 12*12 */
  2. typedef struct
  3. {
  4.     unsigned char Index[2];
  5.     unsigned char Msk[24];
  6. } typFNT_GB12;

  7. /* 定义中文字符 16*16 */
  8. typedef struct
  9. {
  10.     unsigned char Index[2];
  11.     unsigned char Msk[32];
  12. } typFNT_GB16;

  13. /* 定义中文字符 24*24 */
  14. typedef struct
  15. {
  16.     unsigned char Index[2];
  17.     unsigned char Msk[72];
  18. } typFNT_GB24;
  19. ......
复制代码
通过汉字像素软件将对应的汉字和像素存放于lcd_font.h文件中。具体源代码如下所示。
  1. const typFNT_GB12 tfont12[] =
  2. {
  3.     "小", 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x24, 0x01, 0x24, 0x02, 0x22, 0x02, 0x22, 0x04,
  4.     0x21, 0x04, 0x20, 0x00, 0x20, 0x00, 0x38, 0x00, /*"小"*/
  5.    
  6.     "凌", 0x40, 0x00, 0xF9, 0x03, 0x42, 0x00, 0xFC, 0x07, 0x10, 0x01, 0x28, 0x02, 0xE0, 0x01, 0x14, 0x01,
  7.     0xAA, 0x00, 0x41, 0x00, 0xB0, 0x01, 0x0C, 0x06, /*"凌"*/
  8.    
  9.     "派", 0x00, 0x03, 0xF2, 0x00, 0x14, 0x02, 0xD0, 0x01, 0x51, 0x01, 0x52, 0x05, 0x50, 0x03, 0x50, 0x01,
  10.     0x54, 0x01, 0x52, 0x02, 0xD1, 0x02, 0x48, 0x04, /*"派"*/
  11.    
  12. };

  13. const typFNT_GB16 tfont16[] =
  14. {
  15.     "小", 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x88, 0x08, 0x88, 0x10, 0x88, 0x20,
  16.     0x84, 0x20, 0x84, 0x40, 0x82, 0x40, 0x81, 0x40, 0x80, 0x00, 0x80, 0x00, 0xA0, 0x00, 0x40, 0x00, /*"小",0*/
  17.    
  18.     "凌", 0x00, 0x02, 0x02, 0x02, 0xC4, 0x1F, 0x04, 0x02, 0x00, 0x02, 0xE0, 0x7F, 0x88, 0x08, 0x48, 0x11,
  19.     0x24, 0x21, 0x87, 0x0F, 0xC4, 0x08, 0x24, 0x05, 0x04, 0x02, 0x04, 0x05, 0xC4, 0x08, 0x30, 0x30, /*"凌",1*/
  20.    
  21.     "派", 0x00, 0x10, 0x04, 0x3C, 0xE8, 0x03, 0x28, 0x00, 0x21, 0x38, 0xA2, 0x07, 0xA2, 0x04, 0xA8, 0x44,
  22.     0xA8, 0x24, 0xA4, 0x14, 0xA7, 0x08, 0xA4, 0x08, 0xA4, 0x10, 0x94, 0x22, 0x94, 0x41, 0x88, 0x00, /*"派",2*/
  23.    
  24. };
  25. ......
复制代码
当程序需要将某一个特定字号的汉字投射到LCD液晶屏时,程序就根据对应的字号查找对应字号的tfontXX数组,并将对应的像素行数据发送给LCD液晶屏。具体源代码如下所示。
  1. void lcd_show_chinese(uint16_t x, uint16_t y, uint8_t *s, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
  2. {
  3.     uint8_t buffer[128];
  4.     uint32_t buffer_len = 0;
  5.     uint32_t len = strlen(s);

  6.     memset(buffer, 0, sizeof(buffer));
  7.     /* utf8格式汉字转化为ascii格式 */
  8. chinese_utf8_to_ascii(s, strlen(s), buffer, &buffer_len);

  9.     for (uint32_t i = 0; i < buffer_len; i += 2, x += sizey)
  10.     {
  11.         if (sizey == 12)
  12.         {
  13.             lcd_show_chinese_12x12(x, y, &buffer[i], fc, bc, sizey, mode);
  14.         }
  15.         else if (sizey == 16)
  16.         {
  17.             lcd_show_chinese_16x16(x, y, &buffer[i], fc, bc, sizey, mode);
  18.         }
  19.         else if (sizey == 24)
  20.         {
  21.             lcd_show_chinese_24x24(x, y, &buffer[i], fc, bc, sizey, mode);
  22.         }
  23.         else if (sizey == 32)
  24.         {
  25.             lcd_show_chinese_32x32(x, y, &buffer[i], fc, bc, sizey, mode);
  26.         }
  27.         else
  28.         {
  29.             return;
  30.         }
  31. }
  32. }
复制代码
四、编译过程
1、打开sdk下面路径的文件
/vendor/lockzhiner/rk2206/samples/b4_lcd/lcd_example.c
注意:Gitee已有相关源代码,请大家根据上述的需求修改相关源代码。
网址:https://gitee.com/Lockzhiner-Ele ... 2206/samples/b4_lcd
2、修改编译脚本
修改 vendor/lockzhiner/rk2206/sample 路径下 BUILD.gn 文件,指定 lcd_example 参与编译。
"./b4_lcd:lcd_example",
修改 device/lockzhiner/rk2206/sdk_liteos 路径下 Makefile 文件,添加 -llcd_example 参与编译。
hardware_LIBS = -lhal_iothardware -lhardware -llcd_example
3、编译固件
  1. hb set -root .
  2. hb set
  3. hb build -f
复制代码


回帖

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
链接复制成功,分享给好友