0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

【GD32H757Z海棠派开发板使用手册】第十四讲 TFT-8080口液晶显示

聚沃科技 2024-09-19 09:21 次阅读

14.1实验内容

通过本实验主要学习以下内容:

  • LCD显示原理
  • EXMC NOR/SRAM模式时序和8080并口时序
  • LCD显示控制

14.2实验原理

使用MCU的EXMC外设实现8080并口时序,和TFT-LCD控制器进行通信,控制LCD显示图片、字符、色块等。

14.2.1TFT-LCD介绍

薄膜晶体管液晶显示器(英语:Thin film transistor liquid crystal display,常简称为TFT-LCD)是多数液晶显示器的一种,它使用薄膜晶体管技术改善影象品质。虽然TFT-LCD被统称为LCD,不过它是种主动式矩阵LCD,被应用在电视、平面显示器及投影机上。

简单说,TFT-LCD面板可视为两片玻璃基板中间夹着一层液晶,上层的玻璃基板是彩色滤光片、而下层的玻璃则有晶体管镶嵌于上。当电流通过晶体管产生电场变化,造成液晶分子偏转,藉以改变光线的偏极性,再利用偏光片决定像素的明暗状态。此外,上层玻璃因与彩色滤光片贴合,形成每个像素各包含红蓝绿三颜色,这些发出红蓝绿色彩的像素便构成了面板上的视频画面。

为了对TFT-LCD的显示进行控制,需要通过接口和液晶屏通信,但所谓与液晶屏通信,实际上还是与液晶屏驱动控制芯片在通信,而主控制器需要按控制芯片支持的通信进行交互,通常有UART、IIC、SPI、8080、MIPI等各类接口。另外需要注意的一点是:一般支持普通MCU接口的LCD驱动芯片,都需要内置GRAM(Graphics RAM),至少能存储一个屏幕的数据。

这这里,我们使用了8080接口通过并行总线传输控制命令和数据,并通过往LCD液晶模组自带的GRAM更新数据实现屏幕的刷新。

GD32H757海棠派开发板TFT-LCD如下图所示,采用了ILI9488 LCD驱动器,分辨率320*480,支持多种通信接口,在GD32H757上,适合使用16-bit Parallel MCU Interface接口进行通信,开发板配套的LCD模块也采用了该接口设计和开发板进行连接。

wKgZomZ7bSqAZt66AAR42Jm9V_o961.png

14.2.2LCD 8080并口时序介绍(16-bit Parallel MCU Interface)

8080接口是由英特尔设计,是一种并行、异步、半双工通信协议,作用是用于外扩RAM、ROM,后面也用于LCD接口。并行接口又分为8位/16位/24位 三种,顾名思义,就是数据总线的位宽。

  • 如下图所示是16-bit Parallel MCU Interface的接口和MCU的连接信号
wKgZomZ7bTaANeiMAACBuF9C9ek658.png
  • 如下图所示是LCD驱动器16BIT 8080并口读写时序:
  • CS拉低后,并口DATA IO在WR的上升沿被采样;
  • 可以理解为16线的SPI,而WR是写“CLK”,RD是读“CLK”;
  • 但这里还多了D/C引脚用于选择传输命令或数据
wKgaomZ7bU6AB535AAIC0zOeKaw118.pngwKgZomZ7bVSAAKVDAAHJ9-R-G2w527.png

  • 8080接口的RGB颜色数据编码
  • 像素信息用RGB三原色表示,所以向液晶屏传输的数据帧主要也就是传输的RGB颜色数据。
  • 像素的颜色数据并不总是用 8R8G8B的24位真彩色 表示,共有下面几种表示情况:
  • 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每次传输就是一个像素点的像素值,传输数据就为像素颜色值。

14.2.3EXMC外设和EXMC NOR/SRAM模式实现8080时序

  • 这里我们使用EXMC中时序和接口类似的NOR/SRAM模式,来实现8080接口驱动TFT-LCD显示。
  • 这里我们使用SRAM模式异步模式A(扩展模式),时序如下图:
wKgZomZ7bWaAbtWzAACeFGwmKV0242.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。

wKgaomZ7bXGAS9FaAADKryj292U804.png

14.3硬件设计

在红枫派开发板设计中,我们使用EXMC_NE1引脚作为CS,EXMC_A12引脚作为D/C,同时LCD触摸接口使用SPI,LCD_BL为背光控制引脚,这里的引脚选用了带PWM的引脚,可以实现LCD的背光亮度调节。

wKgaombrfAuADy4qAAL5lZT3t2g080.png

14.4代码解析

14.4.1CSx、D/C、BL相关功能定义和注册;

在EXMC LCD驱动代码中存在和电路设计匹配的变更点,往往让开发者头大,需要详细阅读用户手册来进行配置调整、读写地址调整;而在我们的驱动文件bsp_8080_lcd.c中定义注册背光引脚、Ax、NEx引脚,当硬件设计变更时只需要在这里调整,驱动就可以在新的硬件中正常使用。

C
//用户配置定义区
#define BACK_LIGHT_DUTY 80

TIMER_CH_DEF(LCD_8080_BL,TIMER3,1,TIMER_CH_PWM_HIGH,D,13,AF_PP,GPIO_AF_2);

#define EXMC_Ax 12
AFIO_DEF(EXMC_Ax_GPIO,G,2,AF_PP,GPIO_AF_12);

#define EXMC_NEx 1
AFIO_DEF(EXMC_NEx_GPIO,G,9,AF_PP,GPIO_AF_12);

GPIO_DEF(LCD_8080_RST,D,12,OUT_PP,RESET,NULL);
//驱动内部定义区
#define EXMC_LCD_D REG16(((uint32_t)(EXMC_BANK0_NORSRAM_REGIONx_ADDR(EXMC_NEx)))|BIT(EXMC_Ax)*2)
#define EXMC_LCD_C REG16(((uint32_t)(EXMC_BANK0_NORSRAM_REGIONx_ADDR(EXMC_NEx))))

14.4.2gpio和exmc初始化:

exmc使用了扩展模式,这样读和写的时序可以单独配置,因为LCD对读和写的要求时间是不同的,读的时候速率不能太高,如果使用一种参数类型就会为了满足读的要求而降低写的速率,影响最终刷屏的性能。这里主要调整读和写时的地址建立、数据建立时间,通常和硬件设计也有较大关系。

C
static void driver_exmc_lcd_16bit_gpio_init(void)
{
/* EXMC clock enable */
rcu_periph_clock_enable(RCU_EXMC);

/* EXMC enable */
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_GPIOD);
rcu_periph_clock_enable(RCU_GPIOE);
rcu_periph_clock_enable(RCU_GPIOF);
rcu_periph_clock_enable(RCU_GPIOG);

/* configure GPIO D[0-15] */
gpio_af_set(GPIOD, GPIO_AF_12, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8 | GPIO_PIN_9 |
GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8 | GPIO_PIN_9 |
GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8 | GPIO_PIN_9 |
GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);

gpio_af_set(GPIOE, GPIO_AF_12, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 |
GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 |
GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 |
GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);

/* configure NOE NWE */
gpio_af_set(GPIOD, GPIO_AF_12, GPIO_PIN_4 | GPIO_PIN_5);
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_4 | GPIO_PIN_5);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_4 | GPIO_PIN_5);
}

void driver_exmc_lcd_init(uint32_t norsram_region)
{

#define LCD_READ_DATA_SETTIME_NS 50
#define LCD_READ_ADDR_SETTIME_NS 10

#define LCD_WRITE_DATA_SETTIME_NS 20
#define LCD_WRITE_ADDR_SETTIME_NS 10

uint32_t ahb_clk=0;
exmc_norsram_parameter_struct nor_init_struct;
exmc_norsram_timing_parameter_struct nor_timing_read_init_struct;
exmc_norsram_timing_parameter_struct nor_timing_write_init_struct;

mpu_region_init_struct mpu_init_struct;
mpu_region_struct_para_init(&mpu_init_struct);

mpu_config(EXMC_BANK0_NORSRAM_REGIONx_ADDR(norsram_region),MPU_REGION_SIZE_64MB,MPU_AP_FULL_ACCESS,MPU_ACCESS_BUFFERABLE,MPU_ACCESS_NON_CACHEABLE,MPU_ACCESS_NON_SHAREABLE,MPU_INSTRUCTION_EXEC_NOT_PERMIT,MPU_TEX_TYPE0);

/* EXMC clock enable */
rcu_periph_clock_enable(RCU_EXMC);

driver_exmc_lcd_16bit_gpio_init();

nor_init_struct.read_write_timing = &nor_timing_read_init_struct;
nor_init_struct.write_timing = &nor_timing_write_init_struct;
exmc_norsram_struct_para_init(&nor_init_struct);
nor_init_struct.read_write_timing = &nor_timing_read_init_struct;
nor_init_struct.write_timing = &nor_timing_write_init_struct;

SystemCoreClockUpdate();
ahb_clk=rcu_clock_freq_get(CK_AHB);
/* config timing parameter */
nor_timing_read_init_struct.asyn_access_mode = EXMC_ACCESS_MODE_A;
nor_timing_read_init_struct.syn_data_latency = EXMC_DATALAT_2_CLK;
nor_timing_read_init_struct.syn_clk_division = EXMC_SYN_CLOCK_RATIO_2_CLK;
nor_timing_read_init_struct.bus_latency = 1;
nor_timing_read_init_struct.asyn_data_setuptime = LCD_READ_DATA_SETTIME_NS/(float)(1000000000.0f/ahb_clk);
nor_timing_read_init_struct.asyn_address_holdtime = 1;
nor_timing_read_init_struct.asyn_address_setuptime = LCD_READ_ADDR_SETTIME_NS/(float)(1000000000.0f/ahb_clk);

/* config timing parameter */
nor_timing_write_init_struct.asyn_access_mode = EXMC_ACCESS_MODE_A;
nor_timing_write_init_struct.syn_data_latency = EXMC_DATALAT_2_CLK;
nor_timing_write_init_struct.syn_clk_division = EXMC_SYN_CLOCK_RATIO_2_CLK;
nor_timing_write_init_struct.bus_latency = 1;
nor_timing_write_init_struct.asyn_data_setuptime = LCD_WRITE_DATA_SETTIME_NS/(float)(1000000000.0f/ahb_clk);
nor_timing_write_init_struct.asyn_address_holdtime = 1;
nor_timing_write_init_struct.asyn_address_setuptime =LCD_WRITE_ADDR_SETTIME_NS/(float)(1000000000.0f/ahb_clk);

/* config EXMC bus parameters */
nor_init_struct.norsram_region = norsram_region;
nor_init_struct.write_mode = EXMC_ASYN_WRITE;
nor_init_struct.extended_mode = ENABLE;
nor_init_struct.asyn_wait = DISABLE;
nor_init_struct.nwait_signal = DISABLE;
nor_init_struct.memory_write = ENABLE;
nor_init_struct.nwait_config = EXMC_NWAIT_CONFIG_BEFORE;
// nor_init_struct.wrap_burst_mode = DISABLE;
nor_init_struct.nwait_polarity = EXMC_NWAIT_POLARITY_LOW;
nor_init_struct.burst_mode = DISABLE;
nor_init_struct.databus_width = EXMC_NOR_DATABUS_WIDTH_16B;
nor_init_struct.memory_type = EXMC_MEMORY_TYPE_SRAM;
nor_init_struct.address_data_mux = DISABLE;

exmc_norsram_init(&nor_init_struct);

/* enable the EXMC bank0 NORSRAM */
exmc_norsram_enable(norsram_region);
}

14.4.3LCD数据、命令读写:

LCD的命令、数据的读写都通过EXMC来实现,在读写EXMC的逻辑地址时对应的波形会发送到LCD上,命令/数据目前通过地址引脚控制,所以我们需要定义两个地址分别对应命令、数据地址,对这两个地址读和写就可以实现LCD读写数据、写命令功能。

C
/**
* 说明 LCD写数据
* 输入 data: 要写入的数据
* 返回值 无
*/
void bsp_8080_lcd_wr_data(__IO uint16_t data)
{
// delay_sysclk(1);
EXMC_LCD_D = data;
}

/**
* 说明 LCD写寄存器编号/地址函数
* 输入 regno: 寄存器编号/地址
* 返回值 无
*/
void bsp_8080_lcd_wr_regno(__IO uint16_t regno)
{
// delay_sysclk(1);
EXMC_LCD_C = regno; /* 写入要写的寄存器序号 */
}

/**
* 说明 LCD写寄存器
* 输入 regno:寄存器编号/地址
* 输入 data:要写入的数据
* 返回值 无
*/
void bsp_8080_lcd_write_reg(__IO uint16_t regno,__IO uint16_t data)
{
// delay_sysclk(1);
EXMC_LCD_C = regno; /* 写入要写的寄存器序号 */
// delay_sysclk(1);
EXMC_LCD_D = data; /* 写入数据 */
}

/**
* 说明 LCD读数据
* 输入 无
* 返回值 读取到的数据
*/
static uint16_t bsp_8080_lcd_read_data(void)
{
// delay_sysclk(1);
return EXMC_LCD_D;
}

14.4.4LCD初始化

LCD初始化序列通常LCD驱动器厂家会提供相关寄存器配置,为了兼容不同的LCD,可以读取LCD ID后执行不同的驱动芯片初始化:

C
/**
* 说明 初始化LCD
* @note 该初始化函数可以初始化各种型号的LCD(详见本.c文件最前面的描述)
*
* 输入 无
* 返回值 无
*/
uint32_t bsp_8080_lcd_init(void)
{

bsp_8080_lcd_port_init();

driver_gpio_general_init(&LCD_8080_RST);

driver_gpio_pin_reset(&LCD_8080_RST);
delay_ms(10);
driver_gpio_pin_set(&LCD_8080_RST);

delay_ms(10);
bsp_8080_lcd_backlight_duty_set(BACK_LIGHT_DUTY);

bsp_8080_lcd_backlight_on(); /* 点亮背光 */

/* LCD的画笔颜色和背景色 */
bsp_8080_lcd_parameter.g_point_color = WHITE; /* 画笔颜色 */
bsp_8080_lcd_parameter.g_back_color = BLACK; /* 背景色 */

delay_ms(1); /* 初始化FSMC后,必须等待一定时间才能开始初始化 */

/* 尝试9341 ID的读取 */
bsp_8080_lcd_wr_regno(0XD3);
bsp_8080_lcd_parameter.id = bsp_8080_lcd_read_data(); /* dummy read */
bsp_8080_lcd_parameter.id = bsp_8080_lcd_read_data(); /* 读到0X00 */
bsp_8080_lcd_parameter.id = bsp_8080_lcd_read_data(); /* 读取0X93 */
bsp_8080_lcd_parameter.id <<= 8;
bsp_8080_lcd_parameter.id |= bsp_8080_lcd_read_data(); /* 读取0X41 */


if (bsp_8080_lcd_parameter.id == 0X9488)
{
lcd_ex_ili9488_reginit(); /* 执行ILI9388初始化 */
}
else if (bsp_8080_lcd_parameter.id == 0X9341)
{
lcd_ex_ili9341_reginit(); /* 执行ILI9341初始化 */
}else{
bsp_8080_lcd_parameter.id = 0X9488;
bsp_8080_lcd_display_dir(0); /* 默认为竖屏 */
bsp_8080_lcd_scan_dir(DFT_SCAN_DIR); /* 默认扫描方向 */
return DRV_ERROR;
}

bsp_8080_lcd_display_dir(0); /* 默认为竖屏 */
bsp_8080_lcd_scan_dir(DFT_SCAN_DIR); /* 默认扫描方向 */
bsp_8080_lcd_clear(WHITE);

return DRV_SUCCESS;
}

/**
* @brief ILI9488寄存器初始化代码
* @param 无
* @retval 无
*/
void lcd_ex_ili9488_reginit(void)
{
//************* Start Initial Sequence **********//
bsp_lcd_wr_regno(0XF7);
bsp_lcd_wr_data(0xA9);
bsp_lcd_wr_data(0x51);
bsp_lcd_wr_data(0x2C);
bsp_lcd_wr_data(0x82);

bsp_lcd_wr_regno(0XEC);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x02);
bsp_lcd_wr_data(0x03);
bsp_lcd_wr_data(0x7A);

bsp_lcd_wr_regno(0xC0);
bsp_lcd_wr_data(0x13);
bsp_lcd_wr_data(0x13);

bsp_lcd_wr_regno(0xC1);
bsp_lcd_wr_data(0x41);

bsp_lcd_wr_regno(0xC5);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x28);
bsp_lcd_wr_data(0x80);

bsp_lcd_wr_regno(0xB1); //Frame rate 70HZ
bsp_lcd_wr_data(0xB0);
bsp_lcd_wr_data(0x11);

bsp_lcd_wr_regno(0xB4);
bsp_lcd_wr_data(0x02);

bsp_lcd_wr_regno(0xB6); //RGB/MCU Interface Control
bsp_lcd_wr_data(0x02); //MCU
bsp_lcd_wr_data(0x22);

bsp_lcd_wr_regno(0xB7);
bsp_lcd_wr_data(0xc6);

bsp_lcd_wr_regno(0xBE);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x04);

bsp_lcd_wr_regno(0xE9);
bsp_lcd_wr_data(0x00);

bsp_lcd_wr_regno(0xF4);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x0f);

bsp_lcd_wr_regno(0xE0);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x04);
bsp_lcd_wr_data(0x0E);
bsp_lcd_wr_data(0x08);
bsp_lcd_wr_data(0x17);
bsp_lcd_wr_data(0x0A);
bsp_lcd_wr_data(0x40);
bsp_lcd_wr_data(0x79);
bsp_lcd_wr_data(0x4D);
bsp_lcd_wr_data(0x07);
bsp_lcd_wr_data(0x0E);
bsp_lcd_wr_data(0x0A);
bsp_lcd_wr_data(0x1A);
bsp_lcd_wr_data(0x1D);
bsp_lcd_wr_data(0x0F);

bsp_lcd_wr_regno(0xE1);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x1B);
bsp_lcd_wr_data(0x1F);
bsp_lcd_wr_data(0x02);
bsp_lcd_wr_data(0x10);
bsp_lcd_wr_data(0x05);
bsp_lcd_wr_data(0x32);
bsp_lcd_wr_data(0x34);
bsp_lcd_wr_data(0x43);
bsp_lcd_wr_data(0x02);
bsp_lcd_wr_data(0x0A);
bsp_lcd_wr_data(0x09);
bsp_lcd_wr_data(0x33);
bsp_lcd_wr_data(0x37);
bsp_lcd_wr_data(0x0F);


bsp_lcd_wr_regno(0xF4);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x0f);

bsp_lcd_wr_regno(0x36);
bsp_lcd_wr_data(0x08);

bsp_lcd_wr_regno(0x3A); //Interface Mode Control
bsp_lcd_wr_data(0x55); //0x66 18bit; 0x55 16bit

bsp_lcd_wr_regno(0x20);
bsp_lcd_wr_regno(0x11);
delay_ms(120);
bsp_lcd_wr_regno(0x29);
delay_ms(50);

}

14.4.5LCD画点函数实现

LCD在任意点显示想要的颜色值,需要设置显示光标到目标位置,然后就可以从该光标进行颜色数据写入,颜色信息将显示到LCD的指定坐标上。

C
/**
* 说明 画点
* 输入 x,y: 坐标
* 输入 color: 点的颜色(32位颜色,方便兼容LTDC)
* 返回值 无
*/
void bsp_8080_lcd_draw_point(uint16_t x, uint16_t y, uint32_t color)
{
if(x>bsp_8080_lcd_parameter.width || y>bsp_8080_lcd_parameter.height)
{
return;
}

if(bsp_8080_lcd_parameter.display_mode == LCD_MODE)
{
bsp_8080_lcd_set_cursor(x, y); /* 设置光标位置 */
EXMC_LCD_C = bsp_8080_lcd_parameter.wramcmd; /* 开始写入GRAM */
EXMC_LCD_D = color;
}else
{
*(__IO uint16_t*)(((uint32_t)(bsp_8080_lcd_parameter.display_ram)) + 2*((bsp_8080_lcd_parameter.width*y) + x)) = color;
}
}

14.4.6窗口设置和色块填充

LCD可以设置需显示的窗口,设置窗口后可以连续的写数据,像素信息会从窗口起始坐标开始自动递增和换行显示颜色。通过图块设置函数可以显示图片,移植到GUI等;这里我们通过DMA的MEM TO MEM模式可以降低色块填充过程的CPU占用率,同时提升刷屏速率。

C
/**
* 说明 在指定区域内填充指定颜色块
* 输入 (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex - sx + 1) * (ey - sy + 1)
* 输入 color: 要填充的颜色数组首地址
* 返回值 无
*/
void bsp_8080_lcd_color_fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color)
{
uint16_t height, width;
if(sx>bsp_8080_lcd_parameter.width || ex>bsp_8080_lcd_parameter.width || sy>bsp_8080_lcd_parameter.height || ey>bsp_8080_lcd_parameter.height)
{
return;
}
// uint32_t i;
width = ex - sx + 1; /* 得到填充的宽度 */
height = ey - sy + 1; /* 高度 */


if(bsp_8080_lcd_parameter.display_mode == LCD_MODE)
{
bsp_8080_lcd_set_window(sx,sy,width,height);
EXMC_LCD_C = bsp_8080_lcd_parameter.wramcmd;
driver_dma_mem_to_exmclcd_start((void*)&EXMC_LCD_D,&color[0],DMA_Width_16BIT,height*width);
// for(uin32_t i = 0; i < height*width; i++)
// {
// EXMC_LCD_D = color[i];
// }
}
else
{
for(uint16_t y = sy; y <= ey; y++)
{
for(uint16_t x = sx; x <= ex; x++)
{
bsp_8080_lcd_parameter.display_ram[y*width+x]=color[(y-sy)*width+(x-sx)];
}
}
}

}

14.4.7字符显示和LCD Printf

实现上述功能后,通过字库信息结合打点函数就可以实现字符的显示,我们同时实现了在lcd上打印信息,以printf的形式更轻易便捷的输出信息到LCD上。

C
/**
* 说明 LCD打印
* 输入 ...和printf相同用法,自动换行
* 返回值 无
*/
void bsp_8080_lcd_printf(const char * sFormat, ...)
{
#define PRINTF_MAX_LEN 100
char printf_buffer[PRINTF_MAX_LEN];
char* p=printf_buffer;
uint16_t len=0,count=0;
va_list ParamList;
va_start(ParamList, sFormat);
vsprintf(printf_buffer,sFormat, ParamList);
va_end(ParamList);

len=strlen(printf_buffer);

while( ( ((*p <= '~') && (*p >= ' ')) || (*p =='\r') || (*p =='\n') ) && (count {
if((*p =='\r'))
{
bsp_8080_lcd_pritnf_parameter.x_now = bsp_8080_lcd_pritnf_parameter.x_start;
}
else if((*p =='\n'))
{
bsp_8080_lcd_pritnf_parameter.y_now += bsp_8080_lcd_pritnf_parameter.size;
bsp_8080_lcd_fill(bsp_8080_lcd_pritnf_parameter.x_now,bsp_8080_lcd_pritnf_parameter.y_now,bsp_8080_lcd_pritnf_parameter.x_end,bsp_8080_lcd_pritnf_parameter.y_now+bsp_8080_lcd_pritnf_parameter.size,bsp_8080_lcd_pritnf_parameter.back_color);
}
else if( (bsp_8080_lcd_pritnf_parameter.x_now + bsp_8080_lcd_pritnf_parameter.size/2) > bsp_8080_lcd_pritnf_parameter.x_end)
{
bsp_8080_lcd_pritnf_parameter.x_now = bsp_8080_lcd_pritnf_parameter.x_start;
bsp_8080_lcd_pritnf_parameter.y_now += bsp_8080_lcd_pritnf_parameter.size;
bsp_8080_lcd_fill(bsp_8080_lcd_pritnf_parameter.x_now,bsp_8080_lcd_pritnf_parameter.y_now,bsp_8080_lcd_pritnf_parameter.x_end,bsp_8080_lcd_pritnf_parameter.y_now+bsp_8080_lcd_pritnf_parameter.size,bsp_8080_lcd_pritnf_parameter.back_color);
}
else if ( (bsp_8080_lcd_pritnf_parameter.y_now+bsp_8080_lcd_pritnf_parameter.size) > bsp_8080_lcd_pritnf_parameter.y_end)
{
bsp_8080_lcd_pritnf_parameter.x_now = bsp_8080_lcd_pritnf_parameter.x_start;
bsp_8080_lcd_pritnf_parameter.y_now = bsp_8080_lcd_pritnf_parameter.y_start;
bsp_8080_lcd_fill(bsp_8080_lcd_pritnf_parameter.x_start,bsp_8080_lcd_pritnf_parameter.y_start,bsp_8080_lcd_pritnf_parameter.x_end,bsp_8080_lcd_pritnf_parameter.y_end,bsp_8080_lcd_pritnf_parameter.back_color);
}

if((*p !='\r')&&(*p !='\n'))
{
bsp_8080_lcd_show_char(bsp_8080_lcd_pritnf_parameter.x_now, bsp_8080_lcd_pritnf_parameter.y_now, *p, bsp_8080_lcd_pritnf_parameter.size, 0, bsp_8080_lcd_pritnf_parameter.point_color,bsp_8080_lcd_pritnf_parameter.back_color);
bsp_8080_lcd_pritnf_parameter.x_now += bsp_8080_lcd_pritnf_parameter.size / 2;
}
p++;
count++;
}

}

14.4.8主函数

主函数如下所示,进入主函数后,首先进行驱动初始化,包括串口、LED、以及8080接口LCD初始化,之后显示log图片以及字符串信息,进入主循环后,循环显示当前系统tick。

C
int main(void)
{
uint64_t tick_temp=0;
uint16_t frames_speed=0;

driver_init(); /* 延时和公共驱动部分初始化 */
bsp_uart_init(&BOARD_UART); /* 打印串口初始化 */

bsp_led_group_init(); /* 初始化LED组 */
bsp_led_on(&LED1);
bsp_led_off(&LED2);

delay_ms(100);
printf("TFT 8080 LCD examples.\r\n");

bsp_8080_lcd_init(); /* 初始化LCD */

//计算刷整屏速度
tick_temp=driver_tick;
bsp_8080_lcd_clear(WHITE);
frames_speed=driver_tick-tick_temp;

//显示log图片
bsp_8080_lcd_color_fill(60,0,233,99,(uint16_t*)gd_log_picture);

//设置打印窗口
bsp_8080_lcd_printf_init(10,109,bsp_8080_lcd_parameter.width-1,369,FONT_ASCII_24_12,WHITE,BLUE);

//打印到LCD
bsp_8080_lcd_printf("GD32H757ZMT6\r\n");
bsp_8080_lcd_printf("EXMC LCD Brush Test\r\n");
bsp_8080_lcd_printf("LCD ID:%04X\r\n", bsp_8080_lcd_parameter.id);
bsp_8080_lcd_printf("* Suzhou Juwo Electronic\r\n");
bsp_8080_lcd_printf("* web: www.gd32bbs.com\r\n");
bsp_8080_lcd_printf("* B station: 475462605\r\n");
bsp_8080_lcd_printf("* QQ Group: 859440462\r\n");
bsp_8080_lcd_printf("* Taobao: juwo.taobao.com\r\n");
bsp_8080_lcd_printf("* Official ID: gd32bbs\r\n");
bsp_8080_lcd_printf("frames brush:%d ms\r\n", frames_speed);

//重新设置新的打印窗口
bsp_8080_lcd_printf_init(0,370,bsp_8080_lcd_parameter.width-1,bsp_8080_lcd_parameter.height-1,FONT_ASCII_12_6,BLUE,~BLUE);

//将摇杆采集结果处理控制LCD亮度
bsp_8080_lcd_backlight_duty_set(90);
while (1)
{
bsp_8080_lcd_printf(" ");
//打印系统tick到LCD
bsp_8080_lcd_printf("* system tic is %lld \r\n",driver_tick);
delay_ms(200);
}
}

14.5实验结果

复位后显示聚沃和GD LOG图片,大字显示LCD ID,刷屏时间、聚沃相关链接地址等。在下方设置了一个printf区窗口,循环打印亮度信息和系统tic信息。

教程GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6022

    文章

    44375

    浏览量

    628245
  • mcu
    mcu
    +关注

    关注

    146

    文章

    16653

    浏览量

    347710
  • 嵌入式
    +关注

    关注

    5044

    文章

    18810

    浏览量

    298408
  • 开发板
    +关注

    关注

    25

    文章

    4765

    浏览量

    96142
  • GD32
    +关注

    关注

    7

    文章

    400

    浏览量

    23970
收藏 人收藏

    评论

    相关推荐

    GD32H757Z海棠开发板使用手册第十三讲 SDIO-SD卡读写实验

    通过本实验主要学习以下内容: •USB协议基本原理 •GD32H7xx USBHS的使用 •虚拟键盘的协议原理及使用
    的头像 发表于 06-06 11:26 1497次阅读
    【<b class='flag-5'>GD32H757Z</b><b class='flag-5'>海棠</b><b class='flag-5'>派</b><b class='flag-5'>开发板</b><b class='flag-5'>使用手册</b>】<b class='flag-5'>第十</b>三讲 SDIO-SD卡读写实验

    液晶显示模块使用手册-中文PDF

    液晶显示模块使用手册-中文PDF 
    发表于 10-10 10:13

    点阵字符型液晶显示模块 使用手册LCD1602

    点阵字符型液晶显示模块 使用手册
    发表于 05-25 13:57

    迅为iMX6ULL开发板使用手册资料下载

    的知识点,它都有!《嵌入式Linux开发指南》+《开发板使用手册》+《裸机使用手册》链接:https://pan.baidu.com/s/1Xat4C-cDa2Gi1UwNckNRTw
    发表于 12-02 14:13

    点阵字符型液晶显示模块使用手册

    点阵字符型液晶显示模块使用手册有点阵字符型液晶显示模块的基本特点,MDLS字符型液晶显示模块特性,MDLS字符型液晶显示模块指令集,MDLS
    发表于 11-01 10:39 11次下载
    点阵字符型<b class='flag-5'>液晶显示</b>模块<b class='flag-5'>使用手册</b>

    第十四讲 555定时器

    第十四讲 555定时器 5.5.1 555定时器的电路结构及其功能 一、结构框图(图5.5.1 双极型)1.
    发表于 03-30 16:20 3802次阅读
    <b class='flag-5'>第十四讲</b> 555定时器

    YL-51开发板使用手册

    YL-51开发板使用手册,YL-51开发板使用手册YL-51开发板使用手册YL-51
    发表于 05-10 16:31 21次下载

    字符型液晶显示模块使用手册

    电子发烧友网站提供《字符型液晶显示模块使用手册.pdf》资料免费下载
    发表于 10-08 09:29 0次下载
    字符型<b class='flag-5'>液晶显示</b>模块<b class='flag-5'>使用手册</b>

    RA8835液晶显示模块使用手册

    电子发烧友网站提供《RA8835液晶显示模块使用手册.pdf》资料免费下载
    发表于 01-02 10:03 0次下载

    GD32H757Z海棠开发板使用手册】第八讲 ADC-规则组多通道采样实验

    通过本实验主要学习以下内容: ADC的简介 GD32FH757 ADC工作原理 DMA和DMAMUX的原理 规则组多通道循环采样
    的头像 发表于 05-14 09:39 386次阅读
    【<b class='flag-5'>GD32H757Z</b><b class='flag-5'>海棠</b><b class='flag-5'>派</b><b class='flag-5'>开发板</b><b class='flag-5'>使用手册</b>】第八讲 ADC-规则组多通道采样实验

    GD32H757Z海棠开发板使用手册】第九讲 USART-printf打印实验

    通过本实验主要学习以下内容: •串口简介 •GD32H757工作原理 •使用printf打印信息
    的头像 发表于 05-15 11:39 422次阅读
    【<b class='flag-5'>GD32H757Z</b><b class='flag-5'>海棠</b><b class='flag-5'>派</b><b class='flag-5'>开发板</b><b class='flag-5'>使用手册</b>】第九讲 USART-printf打印实验

    GD32H757Z海棠开发板使用手册第十一讲 SPI-SPI NOR FLASH读写实验

    通过本实验主要学习以下内容: •SPI简介 •GD32H7 SPI简介 •SPI NOR FLASH——GD25Q128ESIGR简介 •使用GD32H7 SPI接口实现对GD25Q1
    的头像 发表于 06-04 11:42 532次阅读
    【<b class='flag-5'>GD32H757Z</b><b class='flag-5'>海棠</b><b class='flag-5'>派</b><b class='flag-5'>开发板</b><b class='flag-5'>使用手册</b>】<b class='flag-5'>第十</b>一讲 SPI-SPI NOR FLASH读写实验

    GD32F303红枫开发板使用手册】第二十讲 SPI-SPI NAND FLASH读写实验

    通过本实验主要学习以下内容: •SPI通信协议,参考19.2.1东方红开发板使用手册GD32F303 SPI操作方式,参考19.2.2东方红开发板
    的头像 发表于 06-20 09:50 521次阅读
    【<b class='flag-5'>GD</b>32F303红枫<b class='flag-5'>派</b><b class='flag-5'>开发板</b><b class='flag-5'>使用手册</b>】第二十讲 SPI-SPI NAND FLASH读写实验

    【北京迅为】iTOP-i.MX6开发板使用手册第四部分固件编译第十四章非设备树Android4.4系统编译

    【北京迅为】iTOP-i.MX6开发板使用手册第四部分固件编译第十四章非设备树Android4.4系统编译
    的头像 发表于 09-12 15:43 129次阅读
    【北京迅为】iTOP-i.MX6<b class='flag-5'>开发板</b><b class='flag-5'>使用手册</b>第四部分固件编译<b class='flag-5'>第十四</b>章非设备树Android4.4系统编译

    GD32H757Z海棠开发板使用手册第十五讲 TFT-8080电阻屏屏触摸实验

    通过本实验主要学习以下内容: LCD触控原理 SPI外设功能
    的头像 发表于 09-19 09:30 58次阅读
    【<b class='flag-5'>GD32H757Z</b><b class='flag-5'>海棠</b><b class='flag-5'>派</b><b class='flag-5'>开发板</b><b class='flag-5'>使用手册</b>】<b class='flag-5'>第十</b>五讲 <b class='flag-5'>TFT-8080</b>电阻屏屏触摸实验