[研电赛技术支持] 【GD32F303红枫派使用手册】第二十六讲 EXMC-液晶驱动实验

[复制链接]
 楼主| 聚沃科技 发表于 2024-6-26 09:20 | 显示全部楼层 |阅读模式
红枫派首图.png
26.1 实验内容
通过本实验主要学习以下内容:
• LCD显示原理
• EXMC NOR/SRAM模式时序和8080并口时序
• LCD显示控制
26.2 实验原理
使用MCUEXMC外设实现8080并口时序,和TFT-LCD控制器进行通信,控制LCD显示图片、字符、色块等。
26.2.1 TFT-LCD介绍
薄膜晶体管液晶显示器(英语:Thin film transistor liquid crystal display,常简称为TFT-LCD)是多数液晶显示器的一种,它使用薄膜晶体管技术改善影象品质。虽然TFT-LCD被统称为LCD,不过它是种主动式矩阵LCD,被应用在电视、平面显示器及投影机上。
简单说,TFT-LCD面板可视为两片玻璃基板中间夹着一层液晶,上层的玻璃基板是彩色滤光片、而下层的玻璃则有晶体管镶嵌于上。当电流通过晶体管产生电场变化,造成液晶分子偏转,藉以改变光线的偏极性,再利用偏光片决定像素的明暗状态。此外,上层玻璃因与彩色滤光片贴合,形成每个像素各包含红蓝绿三颜色,这些发出红蓝绿色彩的像素便构成了面板上的视频画面。
为了对TFT-LCD的显示进行控制,需要通过接口和液晶屏通信,但所谓与液晶屏通信,实际上还是与液晶屏驱动控制芯片在通信,而主控制器需要按控制芯片支持的通信进行交互,通常有UARTIICSPI8080MIPI等各类接口。另外需要注意的一点是:一般支持普通MCU接口的LCD驱动芯片,都需要内置GRAM(Graphics RAM), 至少能存储一个屏幕的数据。
这这里,我们使用了8080接口通过并行总线传输控制命令和数据,并通过往LCD液晶模组自带的GRAM更新数据实现屏幕的刷新。
GD32F3红枫派开发板TFT-LCD如下图所示,采用了ILI9488 LCD驱动器,分辨率320*480,支持多种通信接口,在GD32F303xx上,适合使用16-bit Parallel MCU Interface接口进行通信,开发板配套的LCD模块也采用了该接口设计和开发板进行连接。
图片1.png
26.2.2 LCD 8080并口时序介绍(16-bit Parallel MCU Interface
8080接口是由英特尔设计,是一种并行、异步、半双工通信协议,作用是用于外扩RAMROM,后面也用于LCD接口。并行接口又分为 8/16/24位 三种, 顾名思义,就是数据总线的位宽。
如下图所示是16-bit Parallel MCU Interface的接口和MCU的连接信号:
图片2.png
如下图所示是LCD驱动器 16BIT 8080并口读写时序:
○ CS拉低后,并口DATA IOWR的上升沿被采样;
可以理解为16线的SPI,而WR是写“CLK”RD是读“CLK”
但这里还多了D/C引脚用于选择传输命令或数据
图片3.png
图片4.png
• 8080接口的RGB颜色数据编码
像素信息用RGB三原色表示,所以向液晶屏传输的数据帧主要也就是传输的RGB颜色数据。
像素的颜色数据并不总是用 8R8G8B24位真彩色 表示,共有下面几种表示情况:
▪ 12-bits/pixel (R 4-bit, G 4-bit, B 4-bit), 4,096 Colors, 简称444;
▪ 16-bits/pixel (R 5-bit, G 6-bit, B 5-bit), 65,536 Colors, 简称565;
▪ 18-bits/pixel (R 6-bit, G 6-bit, B 6-bit), 262,144 Colors, 简称666;
▪ 24-bits/pixel (R 8-bit, G 8-bit, B 8-bit), 16,777,216 Colors, 简称888;
不同颜色表示方法和不同的总线位宽相组合,就会组合成多种RGB颜色数据编码。
综合显示效果、内存资源开销等,我们采取了RGB565像素格式,这样16BIT 8080每次传输就是一个像素点的像素值,传输数据就为像素颜色值。
26.2.3 EXMC外设和EXMC NOR/SRAM模式实现8080时序
这里我们使用EXMC中时序和接口类似的NOR/SRAM模式,来实现8080接口驱动TFT-LCD显示,EXMC外设可参考上文介绍东方红开发板使用手册 EXMC NOR/SRAM模式可参考上文介绍东方红开发板使用手册
这里我们使用SRAM模式异步模式A(扩展模式),时序如下图:
图片5.png
我们对比上面的时序和16-bit Data Bus 8080 LCD时序,发现一些信号的时序是类似的,我们可以将这些信号进行对应:
EXMC_NEx -> CSx
EXMC_NOE->RDx
EXMC_NWE->WR
EXMC_D[15:0]->DB[15:0]
EXMC_Ax->D/C
这里巧妙的是使用EXMC_Ax引脚实现D/C的数据/命令切换功能,所以我们只需要选择一个方便布线的EXMC_Ax引脚,然后在软件中对该引脚对应的EXMC逻辑地址进行操作就可以实现程序读写不同地址时,D/C引脚的状态切换,从而实现访问一个EXMC地址时是数据或命令类似,访问该地址位反向的任意地址就是另外一个类型。对于程序中逻辑地址的影响,除了Ax引脚的选择外还有NEx引脚的选择。NE[0]-NE[3]对应如下图的NOR/SRAM BANK下的Region0-Region3
图片6.png
26.3 硬件设计
在红枫派开发板设计中,我们使用EXMC_NE1引脚作为CSEXMC_A12引脚作为D/C,同时LCD触摸接口使用SPILCD_BL为背光控制引脚,这里的引脚选用了带PWM的引脚,可以实现LCD的背光亮度调节。
LCD在显示过程电源电流会有变化,为了稳定电源我们在3.3V5V接口上使用了1uf电容。
图片7.png
26.4 代码解析
26.4.1 CSxD/CBL相关功能定义和注册;
EXMC LCD驱动代码中存在和电路设计匹配的变更点,往往让开发者头大,需要详细阅读用户手册来进行配置调整、读写地址调整;而在我们的驱动文件bsp_lcd.c中定义注册背光引脚、AxNEx引脚,当硬件设计变更时只需要在这里调整,驱动就可以在新的硬件中正常使用。
  1. C
  2. //定义背光引脚的PWM通道和GPIO
  3. TIMER_CH_DEF(LCD_BL,TIMER12,0,TIMER_CH_PWM_HIGH,F,8,AF_PP,GPIO_TIMER12_REMAP);

  4. //定义使用的EXMC_Ax引脚
  5. #define EXMC_Ax  12
  6. GPIO_DEF(EXMC_Ax_GPIO,G,2,AF_PP,SET,NULL);

  7. //定义使用的EXMC_NEx引脚
  8. #define EXMC_NEx 1
  9. GPIO_DEF(EXMC_NEx_GPIO,D,7,AF_PP,SET,NULL);

  10. //LCD数据、命令地址转换
  11. #define EXMC_LCD_D  REG16(((uint32_t)(EXMC_BANK0_NORSRAM_REGIONx_ADDR(EXMC_NEx)))|BIT(EXMC_Ax)*2)
  12. #define EXMC_LCD_C  REG16(((uint32_t)(EXMC_BANK0_NORSRAM_REGIONx_ADDR(EXMC_NEx))))
26.4.2 gpioexmc初始化:
exmc使用了扩展模式,这样读和写的时序可以单独配置,因为LCD对读和写的要求时间是不同的,读的时候速率不能太高,如果使用一种参数类型就会为了满足读的要求而降低写的速率,影响最终刷屏的性能。这里主要调整读和写时的地址建立、数据建立时间,通常和硬件设计也有较大关系,这里红枫派开发板和配套LCD的电路可以在120M主频下,设置读数据建立5clk、地址建立1clk,写数据建立2clk,地址建立1clk
  1. C
  2. /*!
  3. * 说明     emxc LCD模式通用gpio初始化
  4. * 输入[1]  norsram_region: @EXMC_BANK0_NORSRAM_REGION0/EXMC_BANK0_NORSRAM_REGION1/EXMC_BANK0_NORSRAM_REGION2/EXMC_BANK0_NORSRAM_REGION3
  5. * 返回值   无
  6. */
  7. void driver_exmc_lcd_16bit_gpio_init(void)
  8. {
  9.     /* EXMC clock enable */
  10.     rcu_periph_clock_enable(RCU_EXMC);

  11.     /* GPIO clock enable */
  12.     rcu_periph_clock_enable(RCU_GPIOD);
  13.     rcu_periph_clock_enable(RCU_GPIOE);
  14.     rcu_periph_clock_enable(RCU_GPIOG);
  15.     rcu_periph_clock_enable(RCU_AF);   

  16.     /* configure EXMC_D[0~15]*/
  17.     /* PD14(EXMC_D0), PD15(EXMC_D1),PD0(EXMC_D2), PD1(EXMC_D3), PD8(EXMC_D13), PD9(EXMC_D14), PD10(EXMC_D15) */
  18.     gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0 | GPIO_PIN_1| GPIO_PIN_8 | GPIO_PIN_9 |
  19.                                                          GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);

  20.     /* PE7(EXMC_D4), PE8(EXMC_D5), PE9(EXMC_D6), PE10(EXMC_D7), PE11(EXMC_D8), PE12(EXMC_D9),
  21.        PE13(EXMC_D10), PE14(EXMC_D11), PE15(EXMC_D12) */
  22.     gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 |
  23.                                                          GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |
  24.                                                          GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);

  25. //    /* configure PE2(EXMC_Ax) */
  26. //    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_2);
  27.    
  28.     /* configure NOE and NWE */
  29.     gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_4 | GPIO_PIN_5);

  30. //    /* configure EXMC NEx */
  31. //    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_7);

  32.     gpio_compensation_config(GPIO_COMPENSATION_ENABLE);
  33.    
  34.     while(gpio_compensation_flag_get()==RESET);
  35. }

  36. /*!
  37. * 说明     emxc LCD模式初始化
  38. * 输入[1]  norsram_region: @EXMC_BANK0_NORSRAM_REGION0/EXMC_BANK0_NORSRAM_REGION1/EXMC_BANK0_NORSRAM_REGION2/EXMC_BANK0_NORSRAM_REGION3
  39. * 返回值   无
  40. */
  41. void driver_exmc_lcd_init(uint32_t norsram_region)
  42. {
  43.     exmc_norsram_parameter_struct nor_init_struct;
  44.     exmc_norsram_timing_parameter_struct nor_timing_read_init_struct;
  45.     exmc_norsram_timing_parameter_struct nor_timing_write_init_struct;

  46.     /* EXMC clock enable */
  47.     rcu_periph_clock_enable(RCU_EXMC);
  48.    
  49.     nor_init_struct.read_write_timing = &nor_timing_read_init_struct;
  50.       
  51.     nor_init_struct.write_timing = &nor_timing_write_init_struct;   
  52.    
  53.     exmc_norsram_struct_para_init(&nor_init_struct);
  54.    
  55.     /* config timing parameter */
  56.     nor_timing_read_init_struct.asyn_access_mode = EXMC_ACCESS_MODE_A;
  57.     nor_timing_read_init_struct.syn_data_latency = EXMC_DATALAT_2_CLK;
  58.     nor_timing_read_init_struct.syn_clk_division = EXMC_SYN_CLOCK_RATIO_2_CLK;
  59.     nor_timing_read_init_struct.bus_latency = 1;
  60.     nor_timing_read_init_struct.asyn_data_setuptime = 5;
  61.     nor_timing_read_init_struct.asyn_address_holdtime = 1;
  62.     nor_timing_read_init_struct.asyn_address_setuptime = 1;
  63.    
  64.     /* config timing parameter */
  65.     nor_timing_write_init_struct.asyn_access_mode = EXMC_ACCESS_MODE_A;
  66.     nor_timing_write_init_struct.syn_data_latency = EXMC_DATALAT_2_CLK;
  67.     nor_timing_write_init_struct.syn_clk_division = EXMC_SYN_CLOCK_RATIO_2_CLK;
  68.     nor_timing_write_init_struct.bus_latency = 1;
  69.     nor_timing_write_init_struct.asyn_data_setuptime = 2;
  70.     nor_timing_write_init_struct.asyn_address_holdtime = 1;
  71.     nor_timing_write_init_struct.asyn_address_setuptime = 1;   

  72.     /* config EXMC bus parameters */
  73.     nor_init_struct.norsram_region = norsram_region;
  74.     nor_init_struct.write_mode = EXMC_ASYN_WRITE;
  75.     nor_init_struct.extended_mode = ENABLE;
  76.     nor_init_struct.asyn_wait = DISABLE;
  77.     nor_init_struct.nwait_signal = DISABLE;
  78.     nor_init_struct.memory_write = ENABLE;
  79.     nor_init_struct.nwait_config = EXMC_NWAIT_CONFIG_BEFORE;
  80.     nor_init_struct.wrap_burst_mode = DISABLE;
  81.     nor_init_struct.nwait_polarity = EXMC_NWAIT_POLARITY_LOW;
  82.     nor_init_struct.burst_mode = DISABLE;
  83.     nor_init_struct.databus_width = EXMC_NOR_DATABUS_WIDTH_16B;
  84.     nor_init_struct.memory_type = EXMC_MEMORY_TYPE_SRAM;
  85.     nor_init_struct.address_data_mux = DISABLE;

  86.     exmc_norsram_init(&nor_init_struct);

  87.     /* enable the EXMC bank0 NORSRAM */
  88.     exmc_norsram_enable(norsram_region);  
  89. }
26.4.3 LCD数据、命令读写:
LCD的命令、数据的读写都通过EXMC来实现,在读写EXMC的逻辑地址时对应的波形会发送到LCD上,命令/数据目前通过地址引脚控制,所以我们需要定义两个地址分别对应命令、数据地址,对这两个地址读和写就可以实现LCD读写数据、写命令功能。
  1. C
  2. /**
  3. * 说明       LCD写数据
  4. * 输入       data: 要写入的数据
  5. * 返回值      无
  6. */
  7. void bsp_lcd_wr_data(__IO uint16_t data)
  8. {
  9.     //delay_sysclk(1);            
  10.     EXMC_LCD_D = data;
  11. }

  12. /**
  13. * 说明       LCD写寄存器编号/地址函数
  14. * 输入       regno: 寄存器编号/地址
  15. * 返回值      无
  16. */
  17. void bsp_lcd_wr_regno(__IO uint16_t regno)
  18. {
  19.     //delay_sysclk(1);        
  20.     EXMC_LCD_C = regno;   /* 写入要写的寄存器序号 */
  21. }

  22. /**
  23. * 说明       LCD写寄存器
  24. * 输入       regno:寄存器编号/地址
  25. * 输入       data:要写入的数据
  26. * 返回值      无
  27. */
  28. void bsp_lcd_write_reg(__IO uint16_t regno,__IO uint16_t data)
  29. {
  30.     //delay_sysclk(1);     
  31.     EXMC_LCD_C = regno;   /* 写入要写的寄存器序号 */
  32.     //delay_sysclk(1);     
  33.     EXMC_LCD_D = data;    /* 写入数据 */
  34. }

  35. /**
  36. * 说明       LCD读数据
  37. * 输入       无
  38. * 返回值      读取到的数据
  39. */
  40. static uint16_t bsp_lcd_read_data(void)
  41. {
  42.     //delay_sysclk(1);
  43.     return EXMC_LCD_D;
  44. }
26.4.4 LCD初始化
LCD初始化序列通常LCD驱动器厂家会提供相关寄存器配置,为了兼容不同的LCD,可以读取LCD ID后执行不同的驱动芯片初始化,初始化过程的寄存器配置就通过25.4.3章节实现的命令、数据读写接口实现:
  1. C
  2. /**
  3. * 说明       初始化LCD
  4. *   [url=home.php?mod=space&uid=536309]@NOTE[/url]      该初始化函数可以初始化各种型号的LCD(详见本.c文件最前面的描述)
  5. *
  6. * 输入       无
  7. * 返回值      无
  8. */
  9. uint32_t bsp_lcd_init(void)
  10. {
  11.    
  12.     bsp_lcd_port_init();


  13.     bsp_lcd_backlight_duty_set(BACK_LIGHT_DUTY);
  14.    
  15.     bsp_lcd_backlight_on();          /* 点亮背光 */   
  16.    
  17.     /* LCD的画笔颜色和背景色 */
  18.     bsp_lcd_parameter.g_point_color = WHITE;    /* 画笔颜色 */
  19.     bsp_lcd_parameter.g_back_color  = BLACK;    /* 背景色 */   
  20.    
  21.     delay_ms(1);     /* 初始化FSMC后,必须等待一定时间才能开始初始化 */

  22.     /* 尝试9341 ID的读取 */
  23.     bsp_lcd_wr_regno(0XD3);
  24.     bsp_lcd_parameter.id = bsp_lcd_read_data();  /* dummy read */
  25.     bsp_lcd_parameter.id = bsp_lcd_read_data();  /* 读到0X00 */
  26.     bsp_lcd_parameter.id = bsp_lcd_read_data();  /* 读取0X93 */
  27.     bsp_lcd_parameter.id <<= 8;
  28.     bsp_lcd_parameter.id |= bsp_lcd_read_data(); /* 读取0X41 */


  29.     if (bsp_lcd_parameter.id == 0X9488)
  30.     {
  31.         lcd_ex_ili9488_reginit();   /* 执行ILI9388初始化 */
  32.     }     
  33.     else if (bsp_lcd_parameter.id == 0X9341)
  34.     {
  35.         lcd_ex_ili9341_reginit();   /* 执行ILI9341初始化 */
  36.     }else{
  37.         return DRV_ERROR;
  38.     }

  39.     bsp_lcd_display_dir(0); /* 默认为竖屏 */
  40.     bsp_lcd_clear(WHITE);
  41.    
  42.     return DRV_SUCCESS;
  43. }

  44. /**
  45. * [url=home.php?mod=space&uid=247401]@brief[/url]       ILI9488寄存器初始化代码
  46. * @param       无
  47. * @retval      无
  48. */
  49. void lcd_ex_ili9488_reginit(void)
  50. {
  51.     //************* Start Initial Sequence **********//
  52.     bsp_lcd_wr_regno(0XF7);            
  53.     bsp_lcd_wr_data(0xA9);         
  54.     bsp_lcd_wr_data(0x51);         
  55.     bsp_lcd_wr_data(0x2C);         
  56.     bsp_lcd_wr_data(0x82);

  57.     bsp_lcd_wr_regno(0XEC);            
  58.     bsp_lcd_wr_data(0x00);         
  59.     bsp_lcd_wr_data(0x02);         
  60.     bsp_lcd_wr_data(0x03);         
  61.     bsp_lcd_wr_data(0x7A);

  62.     bsp_lcd_wr_regno(0xC0);         
  63.     bsp_lcd_wr_data(0x13);         
  64.     bsp_lcd_wr_data(0x13);         
  65.         
  66.     bsp_lcd_wr_regno(0xC1);         
  67.     bsp_lcd_wr_data(0x41);         
  68.         
  69.     bsp_lcd_wr_regno(0xC5);         
  70.     bsp_lcd_wr_data(0x00);         
  71.     bsp_lcd_wr_data(0x28);         
  72.     bsp_lcd_wr_data(0x80);
  73.         
  74.     bsp_lcd_wr_regno(0xB1);   //Frame rate 70HZ         
  75.     bsp_lcd_wr_data(0xB0);
  76.     bsp_lcd_wr_data(0x11);        
  77.         
  78.     bsp_lcd_wr_regno(0xB4);         
  79.     bsp_lcd_wr_data(0x02);           
  80.         
  81.     bsp_lcd_wr_regno(0xB6); //RGB/MCU Interface Control        
  82.     bsp_lcd_wr_data(0x02);   //MCU        
  83.     bsp_lcd_wr_data(0x22);

  84.     bsp_lcd_wr_regno(0xB7);         
  85.     bsp_lcd_wr_data(0xc6);

  86.     bsp_lcd_wr_regno(0xBE);         
  87.     bsp_lcd_wr_data(0x00);
  88.     bsp_lcd_wr_data(0x04);        
  89.         
  90.     bsp_lcd_wr_regno(0xE9);         
  91.     bsp_lcd_wr_data(0x00);

  92.     bsp_lcd_wr_regno(0xF4);         
  93.     bsp_lcd_wr_data(0x00);
  94.     bsp_lcd_wr_data(0x00);
  95.     bsp_lcd_wr_data(0x0f);        
  96.         
  97.     bsp_lcd_wr_regno(0xE0);         
  98.     bsp_lcd_wr_data(0x00);         
  99.     bsp_lcd_wr_data(0x04);         
  100.     bsp_lcd_wr_data(0x0E);         
  101.     bsp_lcd_wr_data(0x08);         
  102.     bsp_lcd_wr_data(0x17);         
  103.     bsp_lcd_wr_data(0x0A);         
  104.     bsp_lcd_wr_data(0x40);         
  105.     bsp_lcd_wr_data(0x79);         
  106.     bsp_lcd_wr_data(0x4D);         
  107.     bsp_lcd_wr_data(0x07);         
  108.     bsp_lcd_wr_data(0x0E);         
  109.     bsp_lcd_wr_data(0x0A);         
  110.     bsp_lcd_wr_data(0x1A);         
  111.     bsp_lcd_wr_data(0x1D);         
  112.     bsp_lcd_wr_data(0x0F);         
  113.         
  114.     bsp_lcd_wr_regno(0xE1);         
  115.     bsp_lcd_wr_data(0x00);         
  116.     bsp_lcd_wr_data(0x1B);         
  117.     bsp_lcd_wr_data(0x1F);         
  118.     bsp_lcd_wr_data(0x02);         
  119.     bsp_lcd_wr_data(0x10);         
  120.     bsp_lcd_wr_data(0x05);         
  121.     bsp_lcd_wr_data(0x32);         
  122.     bsp_lcd_wr_data(0x34);         
  123.     bsp_lcd_wr_data(0x43);         
  124.     bsp_lcd_wr_data(0x02);         
  125.     bsp_lcd_wr_data(0x0A);         
  126.     bsp_lcd_wr_data(0x09);         
  127.     bsp_lcd_wr_data(0x33);         
  128.     bsp_lcd_wr_data(0x37);         
  129.     bsp_lcd_wr_data(0x0F);


  130.     bsp_lcd_wr_regno(0xF4);      
  131.     bsp_lcd_wr_data(0x00);
  132.     bsp_lcd_wr_data(0x00);
  133.     bsp_lcd_wr_data(0x0f);        
  134.         
  135.     bsp_lcd_wr_regno(0x36);         
  136.     bsp_lcd_wr_data(0x08);         
  137.         
  138.     bsp_lcd_wr_regno(0x3A);  //Interface Mode Control        
  139.     bsp_lcd_wr_data(0x55);  //0x66 18bit; 0x55 16bit                        
  140.         
  141.     bsp_lcd_wr_regno(0x20);         
  142.     bsp_lcd_wr_regno(0x11);         
  143.     delay_ms(120);         
  144.     bsp_lcd_wr_regno(0x29);         
  145.     delay_ms(50);

  146. }
26.4.5 LCD画点函数实现
LCD在任意点显示想要的颜色值,需要设置显示光标到目标位置,然后就可以从该光标进行颜色数据写入,颜色信息将显示到LCD的指定坐标上。
  1. C
  2. /**
  3. * 说明       画点
  4. * 输入       x,y: 坐标
  5. * 输入       color: 点的颜色(32位颜色,方便兼容LTDC)
  6. * 返回值      无
  7. */
  8. void bsp_lcd_draw_point(uint16_t x, uint16_t y, uint32_t color)
  9. {
  10.     bsp_lcd_set_cursor(x, y);       /* 设置光标位置 */
  11.     EXMC_LCD_C = bsp_lcd_parameter.wramcmd;    /* 开始写入GRAM */
  12.     EXMC_LCD_D = color;
  13. }
26.4.6 窗口设置和色块填充
LCD可以设置需显示的窗口,设置窗口后可以连续的写数据,像素信息会从窗口起始坐标开始自动递增和换行显示颜色。通过图块设置函数可以显示图片,移植到GUI等;这里我们通过DMAMEM TO MEM模式可以降低色块填充过程的CPU占用率,同时提升刷屏速率。
  1. C
  2. /**
  3. * 说明       在指定区域内填充指定颜色块
  4. * 输入       (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex - sx + 1) * (ey - sy + 1)
  5. * 输入       color: 要填充的颜色数组首地址
  6. * 返回值      无
  7. */
  8. void bsp_lcd_color_fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color)
  9. {
  10.     uint16_t height, width;
  11. //    uint32_t i;
  12.     width = ex - sx + 1;            /* 得到填充的宽度 */
  13.     height = ey - sy + 1;           /* 高度 */
  14.    
  15.     bsp_lcd_set_window(sx,sy,width,height);
  16.     EXMC_LCD_C = bsp_lcd_parameter.wramcmd;
  17.     driver_dma_mem_to_exmclcd_start((void*)&EXMC_LCD_D,&color[0],DMA_Width_16BIT,height*width);     
  18. //    for(uin32_t i = 0; i < height*width; i++)
  19. //    {
  20. //        EXMC_LCD_D = color[i];     
  21. //    }
  22. }
26.4.7 字符显示和LCD Printf
实现上述功能后,通过字库信息结合打点函数就可以实现字符的显示,我们同时实现了在lcd上打印信息,以printf的形式更轻易便捷的输出信息到LCD上。
  1. C
  2. /**
  3. * 说明       LCD打印
  4. * 输入       ...和printf相同用法,自动换行
  5. * 返回值      无
  6. */
  7. void bsp_lcd_printf(const char * sFormat, ...)
  8. {
  9.     char printf_buffer[64];
  10.     char* p=printf_buffer;
  11.     uint16_t len=0,count=0;
  12.     va_list ParamList;
  13.     va_start(ParamList, sFormat);   
  14.     vsprintf(printf_buffer,sFormat, ParamList);     
  15.     va_end(ParamList);

  16.     len=strlen(printf_buffer);   

  17.     while( ( ((*p <= '~') && (*p >= ' ')) || (*p =='\r') || (*p =='\n') ) && (count<len) )   /* 判断是不是非法字符! */
  18.     {
  19.         if((*p =='\r'))
  20.         {
  21.             bsp_lcd_pritnf_parameter.x_now = bsp_lcd_pritnf_parameter.x_start;
  22.         }        
  23.         else if((*p =='\n'))
  24.         {
  25.             bsp_lcd_pritnf_parameter.y_now += bsp_lcd_pritnf_parameter.size;
  26.             bsp_lcd_fill(bsp_lcd_pritnf_parameter.x_now,bsp_lcd_pritnf_parameter.y_now,bsp_lcd_pritnf_parameter.x_end,bsp_lcd_pritnf_parameter.y_now+bsp_lcd_pritnf_parameter.size,bsp_lcd_pritnf_parameter.back_color);            
  27.         }
  28.         else if( (bsp_lcd_pritnf_parameter.x_now + bsp_lcd_pritnf_parameter.size/2) > bsp_lcd_pritnf_parameter.x_end)
  29.         {
  30.             bsp_lcd_pritnf_parameter.x_now = bsp_lcd_pritnf_parameter.x_start;
  31.             bsp_lcd_pritnf_parameter.y_now += bsp_lcd_pritnf_parameter.size;
  32.             bsp_lcd_fill(bsp_lcd_pritnf_parameter.x_now,bsp_lcd_pritnf_parameter.y_now,bsp_lcd_pritnf_parameter.x_end,bsp_lcd_pritnf_parameter.y_now+bsp_lcd_pritnf_parameter.size,bsp_lcd_pritnf_parameter.back_color);                        
  33.         }
  34.         else if ( (bsp_lcd_pritnf_parameter.y_now+bsp_lcd_pritnf_parameter.size) > bsp_lcd_pritnf_parameter.y_end)
  35.         {
  36.             bsp_lcd_pritnf_parameter.x_now = bsp_lcd_pritnf_parameter.x_start;
  37.             bsp_lcd_pritnf_parameter.y_now = bsp_lcd_pritnf_parameter.y_start;            
  38.             bsp_lcd_fill(bsp_lcd_pritnf_parameter.x_start,bsp_lcd_pritnf_parameter.y_start,bsp_lcd_pritnf_parameter.x_end,bsp_lcd_pritnf_parameter.y_end,bsp_lcd_pritnf_parameter.back_color);
  39.         }

  40.         if((*p !='\r')&&(*p !='\n'))
  41.         {
  42.             bsp_lcd_show_char(bsp_lcd_pritnf_parameter.x_now, bsp_lcd_pritnf_parameter.y_now, *p, bsp_lcd_pritnf_parameter.size, 0, bsp_lcd_pritnf_parameter.point_color,bsp_lcd_pritnf_parameter.back_color);
  43.             bsp_lcd_pritnf_parameter.x_now += bsp_lcd_pritnf_parameter.size / 2;            
  44.         }
  45.         

  46.         p++;
  47.         count++;
  48.     }

  49. }
26.5 实验结果
复位后显示聚沃和GD LOG图片,大字显示LCD ID,刷屏时间、聚沃相关链接地址等。在下方设置了一个printf区窗口,循环打印亮度信息和系统tic信息。左右波动摇杆可以调节LCD亮度。

本教程由GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网,GD32MCU技术交流群:859440462

您需要登录后才可以回帖 登录 | 注册

本版积分规则

170

主题

190

帖子

13

粉丝
快速回复 在线客服 返回列表 返回顶部