搜索
bottom↓
回复: 0

《DNK210使用指南 -SDK版 V1.0》第十六章 LCD显示实验

[复制链接]

出0入234汤圆

发表于 4 天前 | 显示全部楼层 |阅读模式
2.jpg
1)实验平台:正点原子DNK210开发板
2)购买链接:https://detail.tmall.com/item.htm?id=782801398750
3)全套实验源码+手册+视频下载地址:http://openedv.com/thread-348335-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子手把手教你学DNK210快速入门视频教程:https://www.bilibili.com/video/BV1kD421G7fu
6)正点原子FPGA交流群:132780729
1.png
3.png

第十六章 LCD显示实验


       本章将介绍初步介绍Kendryte K210使用官方SDK驱动的LCD。通过本章的学习,读者将学习到板载LCD的简单使用。
       本章分为如下几个小节:
       16.1 LCD模块介绍
       16.2 硬件设计
       16.3 程序设计
       16.4 运行验证

       16.1 LCD介绍
       DNK210板载一块2.4寸(此处的寸是代表英寸,下同)的TFT-LCD显示模块,显示分辨率为320*240,颜色数量高达262K。
       本章将介绍Kendryte K210使用8线SPI驱动开发板板载的2.4寸TFT-LCD显示屏。

       16.1.1 SPI简介
       SPI,Serial Peripheral interface,顾名思义,就是串行外围设备接口,是由原摩托罗拉公司在其MC68HCXX系列处理器上定义的。SPI是一种高速的全双工、同步、串行的通信总线,已经广泛应用在众多MCU、存储芯片、AD转换器和LCD之间。
       SPI通信跟IIC通信一样,通信总线上允许挂载一个主设备和一个或者多个从设备。为了跟从设备进行通信,一个主设备至少需要4跟数据线,分别为:
       MOSI(Master Out / Slave In):主数据输出,从数据输入,用于主机向从机发送数据。
       MISO(Master In / Slave Out):主数据输入,从数据输出,用于从机向主机发送数据。
       SCLK(Serial Clock):时钟信号,由主设备产生,决定通信的速率。
       CS(Chip Select):从设备片选信号,由主设备产生,低电平时选中从设备。
       多从机SPI通信网络连接如下图所示。

第十六章 LCD显示实验682.png
图16.1.1.1 多从机SPI通信网络图

       从上图可以知道,MOSI、MISO、SCLK引脚连接SPI总线上每一个设备,如果CS引脚为低电平,则从设备只侦听主机并与主机通信。SPI主设备一次只能和一个从设备进行通信。如果主设备要和另外一个从设备通信,必须先终止和当前从设备通信,否则不能通信。
       SPI通信有4种不同的模式,不同的从机可能在出厂时就配置为某种模式,这是不能改变的。通信双方必须工作在同一模式下,才能正常进行通信,所以可以对主机的SPI模式进行配置。SPI通信模式是通过配置CPOL(时钟极性)和CPHA(时钟相位)来选择的。
       CPOL,详称Clock Polarity,就是时钟极性,当主从机没有数据传输的时候即空闲状态,SCL线的电平状态,假如空闲状态是高电平,CPOL=1;若空闲状态时低电平,那么CPOL = 0。
       CPHA,详称Clock Phase,就是时钟相位,实质指的是数据的采样时刻。CPHA = 0表示数据的采样是从第1个边沿信号上即奇数边沿,具体是上升沿还是下降沿的问题,是由CPOL决定的。CPHA=1表示数据采样是从第2个边沿即偶数边沿。
       SPI的4种模式对比图,如下图所示。

第十六章 LCD显示实验1193.png
图16.1.1.2 SPI的4种模式对比图

       模式0,CPOL=0,CPHA=0;空闲时,SCL处于低电平,数据采样在第1个边沿,即SCL由低电平到高电平的跳变,数据采样在上升沿,数据发送在下降沿。
       模式1,CPOL=0,CPHA=1;空闲时,SCL处于低电平,数据采样在第2个边沿,即SCL由高电平到低电平的跳变,数据采样在下升沿,数据发送在上降沿。
       模式2,CPOL=1,CPHA=0;空闲时,SCL处于高电平,数据采样在第1个边沿,即SCL由高电平到低电平的跳变,数据采样在下升沿,数据发送在上降沿。
       模式3,CPOL=1,CPHA=1;空闲时,SCL处于高电平,数据采样在第2个边沿,即SCL由低电平到高电平的跳变,数据采样在上升沿,数据发送在下降沿。
       Kendryte K210的SPI功能非常强大,最高支持8线全双工模式,串行外设接口有4组SPI接口,其中SPI0、SPI1、SPI3只能工作在MASTER模式,SPI2只能工作在SLAVE模式,他们有如下特性:
       1. 支持1/2/4/8线全双工模式
       2. SPI0、SPI1、SPI2可支持25MHz时钟
       3. SPI3最高可支持80MHz时钟
       4. 支持32位宽、32BYTE深的FIFO
       5. 独立屏蔽中断-主机冲突,发送FIFO溢出,发送FIFO空,接收FIFO满,接收FIFO下溢,接收FIFO溢出中断都可以被屏蔽独立
       6. 支持DMA功能
       7. 支持双沿的DDR传输模式
       我们选择使用SPI0外设接口,SPI时钟配置为15MHz,使用8线SPI模式,这使我们屏幕具有较快的刷新速度和显示效果,能够适用于摄像头显示、视频播放等场景。
       Kendryte K210官方SDK提供了多个操作SPI接口的函数,这里我们只讲述本实验用到的函数,这些函数介绍如下:

       1,spi_init函数
       该函数主要用于SPI的配置初始化,该函数原型及参数描述如下代码所示:
  1. void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format,size_t data_bit_length, uint32_t endian);
  2. /* SPI配总线号配置参数 */
  3. typedef enum _spi_device_num
  4. {
  5.     SPI_DEVICE_0,
  6.     SPI_DEVICE_1,
  7.     SPI_DEVICE_2,
  8.     SPI_DEVICE_3,
  9.     SPI_DEVICE_MAX,
  10. } spi_device_num_t;

  11. /* SPI工作模式配置参数 */
  12. typedef enum _spi_work_mode
  13. {
  14.     SPI_WORK_MODE_0,
  15.     SPI_WORK_MODE_1,
  16.     SPI_WORK_MODE_2,
  17.     SPI_WORK_MODE_3,
  18. } spi_work_mode_t;

  19. /* SPI帧格式配置参数 */
  20. typedef enum _spi_frame_format
  21. {
  22.     SPI_FF_STANDARD,
  23.     SPI_FF_DUAL,
  24.     SPI_FF_QUAD,
  25.     SPI_FF_OCTAL
  26. } spi_frame_format_t;
复制代码
       该函数共有五个配置参数,第一个为总线号,第二个为SPI工作模式,第三个是配置帧格式,第四个为数据长度,第五个是选择大小端模式,大端模式配置为1,小端模式配置为0。我们依次配置为:设备0、SPI工作模式0、8线模式、数据长度为8、小端模式,关于大小端模式的内容,大家可自行百度了解。

       2,spi_set_clk_rate t函数
       该函数用于设置SPI总线时钟,如下代码所示:
  1. uint32_t spi_set_clk_rate(spi_device_num_t spi_num, uint32_t spi_clk);
复制代码
       第一个参数是选择需要配置的总线号,第二个参数为设置的频率,我们配置SPI0时钟为15MHz即可。Kendryte K210的SPI0、SPI1、SPI2可支持25MHz时钟,SPI3支持80MHz时钟,这是在设备支持的理想情况下的最高时钟频率配置。但实际上我们要根据自己的设备情况而定,并不是越高越好。

       3,spi_init_non_standard函数
       该函数用来初始化SPI传输,该函数原型及参数描述如下所示:
  1. void spi_init_non_standard(spi_device_num_t spi_num, uint32_t instruction_length, uint32_t address_length, uint32_t wait_cycles, spi_instruction_address_trans_mode_t instruction_address_trans_mode);

  2. /* SPI数据传送模式配置参数 */
  3. typedef enum _spi_instruction_address_trans_mode
  4. {
  5.     SPI_AITM_STANDARD,
  6.     SPI_AITM_ADDR_STANDARD,
  7.     SPI_AITM_AS_FRAME_FORMAT
  8. } spi_instruction_address_trans_mode_t;
复制代码
       函数共有5个参数,分别配置SPI总线号、指令长度、数据长度、等待周期和传输模式,这里我们需要根据自己的需要配置不同的参数。

       4,spi_send_data_standard_dma函数
       该函数是SPI用DMA通道发送数据,该函数原型及参数描述如下所示:
  1. void spi_send_data_standard_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *cmd_buff, size_t cmd_len, const uint8_t *tx_buff, size_t tx_len);

  2. /* SPI数据传送模式配置参数 */
  3. typedef enum _dmac_channel_number
  4. {
  5.     DMAC_CHANNEL0 = 0,
  6.     DMAC_CHANNEL1 = 1,
  7.     DMAC_CHANNEL2 = 2,
  8.     DMAC_CHANNEL3 = 3,
  9.     DMAC_CHANNEL4 = 4,
  10.     DMAC_CHANNEL5 = 5,
  11.     DMAC_CHANNEL_MAX
  12. } dmac_channel_number_t;
复制代码
       通过DMA发送数据可以有效节省CPU的资源,得到更好的传输效果,函数共有7个参数,分别配置DMA通道号、SPI总线号、芯片片选引脚、传输的数据地址、数据长度和数据位宽。

       16.1.2 LCD模块介绍
       液晶显示器,即Liquid Crystal Display,利用了液晶导电后透光性可变的特性,配合显示器光源、彩色滤光片和电压控制等工艺,最终可以在液晶阵列上显示彩色的图像。目前液晶显示技术以TN、STN、TFT三种技术为主,TFT-LCD即采用了       TFT(Thin Film Transistor)技术的液晶显示器,也叫薄膜晶体管液晶显示器。
TFT-LCD与无源TN-LCD、STN-LCD的简单矩阵不同的是,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管(TFT),可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,因此大大提高了图像质量。TFT式显示器具有很多优点:高响应度,高亮度,高对比度等等。TFT式屏幕的显示效果非常出色,广泛应用于手机屏幕、笔记本电脑和台式机显示器上。
       由于液晶本身不会发光,加上液晶本身的特性等原因,使得液晶屏的成像角受限,我们从屏幕的的一侧可能无法看清液晶的显示内容。液晶显示器的成像角的大小也是评估一个液晶显示器优劣的指标,目前,规格较好的液晶显示器成像角一般在120°~160°之间。

       16.2 硬件设计

       16.2.1 例程功能

       1. 使用lcd模块初始化LCD,在LCD上显示一段字符串,并不断更换背景颜色

       16.2.2 硬件资源

       1. LCD
              LCD_RD - IO34
              LCD_BL - IO35
              LCD_CS - IO36
              LCD_RST - IO37
              LCD_RS - IO38
              LCD_WR - IO39
              LCD_D0~LCD_D7 - SPI0_D0~SPI0_D7

       16.2.3 原理图
       本章实验内容,需要使用到板载的LCD显示屏,正点原子DNK210开发板上的LCD显示屏连接原理图,如下图所示:

第十六章 LCD显示实验4880.png
图16.2.3.1 LCD显示屏连接原理图

       16.3 程序设计

       16.3.1 lcd驱动代码
       LCD驱动源码包括三个文件:lcd.c、lcd.h和lcdfont.h,因为涉及内容较多,我们只挑选部分讲解,我们先看lcd.h文件的内容。
       lcd.h主要就是一些管脚的宏定义和SPI配置的宏,还有RGB565颜色常量的定义,如下表所示:

1.png
表16.3.1.1 lcd模块提供的颜色常量

       lcd.h文件内容就介绍到这里了,接下来我们看lcd.c文件。
  1. /**
  2. * @brief       LCD初始化
  3. * @param       无
  4. * @retval      无
  5. */
  6. void lcd_init(void)
  7. {
  8.     uint8_t data;

  9.     /* Initialize DCX pin */
  10.     fpioa_set_function(LCD_DCX_PIN, FUNC_GPIOHS0 + LCD_DCX_GPIOHS_NUM);
  11.     gpiohs_set_drive_mode(LCD_DCX_GPIOHS_NUM, GPIO_DM_OUTPUT);
  12.     gpiohs_set_pin(LCD_DCX_GPIOHS_NUM, GPIO_PV_HIGH);
  13.    
  14.     /* Initialize RESET pin */
  15.     fpioa_set_function(LCD_RST_PIN, FUNC_GPIOHS0 + LCD_RST_GPIOHS_NUM);
  16.     gpiohs_set_drive_mode(LCD_RST_GPIOHS_NUM, GPIO_DM_OUTPUT);
  17.     gpiohs_set_pin(LCD_RST_GPIOHS_NUM, GPIO_PV_HIGH);

  18.     /* Initialize CSX pin */
  19.     fpioa_set_function(LCD_CSX_PIN, FUNC_SPI0_SS0 + LCD_SPI_CS_NUM);

  20.     /* Initialize WRX pin */
  21.     fpioa_set_function(LCD_WRX_PIN, FUNC_SPI0_SCLK);

  22.     /* Initialize SPI interface */
  23.     spi_init(LCD_SPI, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
  24.     spi_set_clk_rate(LCD_SPI, LCD_SPI_CLK_RATE);
  25.    
  26.     /* Hardware reset */
  27.     gpiohs_set_pin(LCD_RST_GPIOHS_NUM, GPIO_PV_LOW);
  28.     msleep(50);
  29.     gpiohs_set_pin(LCD_RST_GPIOHS_NUM, GPIO_PV_HIGH);
  30.     msleep(50);

  31.     /* Software reset */
  32.     lcd_write_command(0x01);
  33.     msleep(50);

  34.     /* Exit sleep */
  35.     lcd_write_command(0x11);
  36.     msleep(120);

  37.     /* Set pixel format */
  38.     lcd_write_command(0x3A);
  39.     data = 0x55;
  40.     lcd_write_data_8b(&data, 1);
  41.     msleep(10);

  42.     /* Set direction */
  43.     lcd_write_command(0x36);
  44.     data = 0xA0;
  45.     lcd_write_data_8b(&data, 1);
  46.    
  47.     /* Inversion display */
  48.     lcd_write_command(0x21);
  49.     msleep(10);
  50.    
  51.     /* Display on */
  52.     lcd_write_command(0x13);
  53.     msleep(10);
  54.     lcd_write_command(0x29);

  55.     /* Clear display */
  56.     lcd_clear(0xFFFF);
  57. }
复制代码
       首先介绍的是lcd初始化函数,函数的内容是配置SPI相关引脚,然后初始化SPI,设置SPI时钟,最后是用指令配置LCD。
       DNK210板载的TFT-LCD显示器使用的是ST7789驱动IC芯片,详细的ST7789初始化寄存器对应功能的指令可以参考:ST7789_DS.pdf这个文档 ,存放路径是:A盘硬件资料液晶资料。
  1. /**
  2. * @brief       SPI写命令
  3. * @param       cmd:7789指令
  4. * @retval      无
  5. */
  6. static void lcd_write_command(uint8_t cmd)
  7. {
  8.     gpiohs_set_pin(LCD_DCX_GPIOHS_NUM, GPIO_PV_LOW);
  9.     spi_init(LCD_SPI, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
  10.     spi_init_non_standard(LCD_SPI, 8, 0, 0, SPI_AITM_AS_FRAME_FORMAT);
  11.     spi_send_data_normal_dma(LCD_SPI_DMA_CH, LCD_SPI, LCD_SPI_CS_NUM, &cmd, 1, SPI_TRANS_CHAR);
  12. }
复制代码
       该函数用于写命令操作,我们先拉低RS引脚,选择命令,然后重新初始化SPI,这里我们需要配置为8位的发送指令模式。
  1. /**
  2. * @brief       SPI写数据(uint16_t类型)
  3. * @param       dat :数据地址
  4. * @param       len :数据长度
  5. * @retval      无
  6. */
  7. static void lcd_write_data_16b(uint16_t *dat, uint32_t len)
  8. {
  9.     gpiohs_set_pin(LCD_DCX_GPIOHS_NUM, GPIO_PV_HIGH);
  10.     spi_init(LCD_SPI, SPI_WORK_MODE_0, SPI_FF_OCTAL, 16, 0);
  11.     spi_init_non_standard(LCD_SPI, 16, 0, 0, SPI_AITM_AS_FRAME_FORMAT);
  12.     spi_send_data_normal_dma(LCD_SPI_DMA_CH, LCD_SPI, LCD_SPI_CS_NUM, dat, len, SPI_TRANS_SHORT);
  13. }
复制代码
       该函数用于写数据(uint16_t类型),TFT-LCD是以RGB565的格式显示,每个像素点占16位bit,为了方便使用所以我们常用此函数来写数据,函数执行过程和写指令差不多,不同的是写指令要将SPI的RS引脚拉高,然后SPI初始化为16bit的数据宽度。
  1. /**
  2. * @brief       设置显示区域
  3. * @param       x1,y1 :起点坐标
  4. * @param       x2,y2 :终点坐标
  5. * @retval      无
  6. */
  7. void lcd_set_area(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
  8. {
  9.     uint8_t data[4] = {0};

  10.     data[0] = (uint8_t)(x1 >> 8);
  11.     data[1] = (uint8_t)(x1);
  12.     data[2] = (uint8_t)(x2 >> 8);
  13.     data[3] = (uint8_t)(x2);
  14.     lcd_write_command(0x2A);
  15.     lcd_write_data_8b(data, 4);

  16.     data[0] = (uint8_t)(y1 >> 8);
  17.     data[1] = (uint8_t)(y1);
  18.     data[2] = (uint8_t)(y2 >> 8);
  19.     data[3] = (uint8_t)(y2);
  20.     lcd_write_command(0x2B);
  21.     lcd_write_data_8b(data, 4);

  22.     lcd_write_command(0x2C);
  23. }
复制代码
       该函数作用类似于重新设置一个显示窗口,用于定位到要写数据的位置,0x2A和0x2B这两个指令用于配置列地址和行地址,通过这两个指令可以找到要写的内存地址,用0x2C指令可以启用内存写功能,后面用写数据函数即可将数据写入内存中。
       为防止篇幅过长,功能函数这里就不再叙述,因为底层操作都是基于上面讲述的几个函数,源码有详细的功能介绍和参数的作用,大家可以直接参考代码源码进行学习。
       lcdfont.h文件主要存放着LCD字符集点阵数组,用于LCD显示各种字符串,目前的例程仅支持16*16大小的字符显示,如需显示其他大小的字符可自行扩展。

       16.3.2 main.c代码
       main.c中的代码如下所示:
  1. #define LCD_SPI_CLK_RATE 15000000

  2. int main(void)
  3. {
  4.     uint8_t x = 0;

  5.     sysctl_pll_set_freq(SYSCTL_PLL0, 800000000);
  6.     sysctl_pll_set_freq(SYSCTL_PLL1, 400000000);
  7.     sysctl_pll_set_freq(SYSCTL_PLL2, 45158400);
  8.     sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);
  9.     sysctl_set_power_mode(SYSCTL_POWER_BANK7, SYSCTL_POWER_V18);
  10.     sysctl_set_spi0_dvp_data(1);

  11.     lcd_init();
  12.     lcd_set_direction(DIR_YX_LRUD);
  13.    
  14.     while(1)
  15.     {
  16.         switch(x)
  17.         {
  18.             case 0:lcd_clear(WHITE);break;
  19.             case 1:lcd_clear(BLACK);break;
  20.             case 2:lcd_clear(BLUE);break;
  21.             case 3:lcd_clear(RED);break;
  22.             case 4:lcd_clear(MAGENTA);break;
  23.             case 5:lcd_clear(GREEN);break;
  24.             case 6:lcd_clear(CYAN);break;
  25.             case 7:lcd_clear(YELLOW);break;
  26.             case 8:lcd_clear(BRRED);break;
  27.             case 9:lcd_clear(GRAY);break;
  28.             case 10:lcd_clear(LIGHTGREY);break;
  29.             case 11:lcd_clear(BROWN);break;
  30.         }   

  31.         lcd_draw_string(10, 10, "ATK-DNK210", RED);
  32.         lcd_draw_string(10, 30, "LCD", RED);
  33.         lcd_draw_string(10, 50, "ATOM@ALIENTEK", RED);

  34.         if(++x == 12)
  35.         {
  36.             x=0;
  37.         }
  38.         
  39.         sleep(1);   
  40.     }      
  41. }
复制代码
       可以看到首先是配置系统时钟,然后使用lcd_init函数对LCD进行初始化,然后重新设置显示扫描方向,最好在一个循环中不断改变LCD的背景颜色,并在LCD上显示一段字符串。

       16.4 运行验证
       将DNK210开发板连接到电脑主机,通过VSCode将固件烧录到开发板中,可以看到LCD上显示了一段字符串,并不断地更换背景颜色,如下图所示:

第十六章 LCD显示实验10658.png
图16.4.1 LCD显示(白色背景)

第十六章 LCD显示实验10680.png
图16.4.2 LCD显示(蓝色背景)

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-10-16 16:05

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表