STM32H742-ARM例程32-LCD

目录

实验平台

硬件:银杏科技GT7000双核心开发板-ARM-STM32H743XIH6,银杏科技iToolXE仿真器7寸液晶显示模块

软件:最新版本STM32CubeH7固件库STM32CubeMX v6.10.0,开发板环境MDK v5.35

显示器简介

显示器属于计算机的IO设备,即输入输出设备。常见的有CRT显示器、液晶显示器、LED点阵显示器及OLED显示器。液晶显示器,简称LCD(Liquid Crystal Display),相对于上一代CRT显示器(阴极射线管显示器),LCD显示器功耗低、体积小、承载的信息量大。

液晶显示器

LCD液晶屏(Liquid Crystal Display)使用了目前新的全彩显示技术,而且原理简单易懂。基本上,整个液晶显示技术的概念是利用液晶的物理特性:通电时导通,排列变得有秩序,使光线容易通过;不过通电时排列混乱,阻止光线通过。让液晶如闸门般的阻隔或让光线穿过。就技术面而言,液晶面板包含了两片相当精致的无钠玻璃素材,称为Substrates,中间夹着一层液晶。当光束通过这层液晶时,液晶本身会排排站立或扭转呈不规则状,因而阻隔或使光束顺利通过。

注意液晶本身是不发光的,所以需要有一个背光灯提供光源,光线经过一系列处理过程才到输出,所以输出的光线强度是要比光源的强度低很多的, 比较浪费能源(当然,比CRT显示器还是节能多了)。而且这些处理过程会导致显示方向比较窄,也就是它的视角较小,从侧面看屏幕会看不清它的显示内容。 另外,输出的色彩变换时,液晶分子转动也需要消耗一定的时间,导致屏幕的响应速度低。

LED和OLED显示器

LED屏幕: LED屏幕使用了背光源,通常是LED灯珠或荧光管,来照亮屏幕。这种背光照亮液晶屏或其他类型的面板,使其显示内容。因此,LED屏幕实际上是液晶显示器(LCD)和  LED背光的组合。液晶用来调控光的透过与阻挡,而LED背光提供亮度。

LED技术发展了几十年,从LED芯片到灯珠封装再达LED显示屏国内有着完整的产业链,而目技术成熟,产品也非常稳定,从户外应用的产品到室内的小间距产品,有很多种规格。

LED显示屏的一大优势是拼接后没有拼接痕迹,整个屏幕完整度非常好,所以在显示画面时全屏显示效果好,没视觉上的影响,而OLED显示屏则会有拼接缝隙,就像LCD拼接一样。

LED显示屏还有一个优势就是能用在室外显示,因为它支持防水防晒防潮三防的特点,同时亮度也高,即使是阳光直接照在屏幕上仍然可以正常显示。

OLED屏幕: OLED屏幕是自发光的,它的每个像素都是一个小型有机发光二极管。每个像素可以独立发光或关闭,不需要背光源。这意味着OLED屏幕能够实现像素级的精确控制,有更高的对比度和更鲜艳的颜色。

OLED屏幕在显示黑色像素时不会消耗能量,因为黑色像素是关闭的,这使得OLED屏幕在显示暗色场景时更节能。而LED屏幕则会持续消耗能量,因为背光必须保持亮度。

OLED屏幕中的有机材料在长时间内可能会受到损害,导致屏幕出现图像保持或烧屏(burn-in)问题。LED屏幕没有这个问题,更耐用。

在图像显示的细腻度、柔和度、对比度方面,OLED显示屏是很有优势的,它一点甚至比LCD屏还要好。OLED显示屏分辨率高,能达到4K显示,分辨率更高,清晰度也就更好,特别适合近距离情况下的使用,这是它的一大优势。

OLED显示屏的功耗非常低,因为它是自发光,不需要背光源,所以非常节能,而且具有环保的特性,如果需要长时间连续开机运行的话这会非常省电,直接降低使用成本。

由于OLED屏幕纤薄轻巧,更容易弯曲,所以大尺寸曲面屏多为OLED屏幕。

显示器基本参数

(1)像素:像素是组成图像的最基本单元要素,显示器的像素指它成像最小的点,即上文提到的一个基本显示单元。

(2)分辨率:一些嵌入式设备的显示器常常以"行像素值x列像素值"表示屏幕的分辨率。如分辨率800x480表示该显示器的每一行有800个像素点,每一列有480个像素点,也可理解为有800列,480行。

(3)色彩深度:色彩深度指显示器的每个像素点能表示多少种颜色,一般用"位"(bit)来表示。如单色屏的每个像素点能表示亮或灭两种状态(即实际上能显示2种颜色),用1个数据位就可以表示像素点的所有状态,所以它的色彩深度为1bit,其它常见的显示屏色深为16bit(2的16次方,RGB565)、24bit(2的24次方,RGB888)。

(4)点距:指两个相邻像素点之间的距离,它会影响画质的细腻度及观看距

离,相同尺寸的屏幕,若分辨率越高,则点距越小,画质越细腻。如现在有些手机的屏幕分辨率比电脑显示器的还大,这是手机屏幕点距小的原因;LED点阵显示屏的点距一般都比较大,所以适合远距离观看。

液晶控制原理

这个完整的显示屏由液晶显示面板、电容触摸面板以及PCB底板构成。图中的触摸面板带有触摸控制芯片,该芯片处理触摸信号并通过引出的信号线与外部器件通讯, 触摸面板中间是透明的,它贴在液晶面板上面,一起构成屏幕的主体,触摸面板与液晶面板引出的排线连接到PCB底板上,根据实际需要, PCB底板上可能会带有"液晶控制器芯片"。因为控制液晶面板需要比较多的资源, 所以大部分低级微控制器都不能直接控制液晶面板,需要额外配套一个专用液晶控制器来处理显示过程,外部微控制器只要把它希望显示的数据直接交给液晶控制器即可。 而不带液晶控制器的PCB底板 ,只有小部分的电源管理电路,液晶面板的信号线与外部微控制器相连,直接控制。STM32H743系列的芯片不需要额外的液晶控制器, 也就是说它把专用液晶控制器的功能集成到STM32H743芯片内部了,节约了额外的控制器成本。

液晶面板的控制信号

信号名称 说明
R[7:0] 红色数据
G[7:0] 绿色数据
B[7:0] 蓝色数据
CLK 像素同步时钟信号
HSYNC 水平同步信号
VSYNC 垂直同步信号
DE 数据使能信号

RGB

RGB信号线各有8根,分别用于表示液晶屏一个像素点的红、绿、蓝颜色分量。每条颜色数据线可以有多根,这决定了能显示多少种颜色。
RGB565(16位色) : 这是最常用的配置,尤其在MCU驱动LCD屏中。

R[4:0]: 5根红色数据线

G[5:0]: 6根绿色数据线(人眼对绿色更敏感)

B[4:0]: 5根蓝色数据线

总共 5+6+5 = 16根数据线,可表示 2^16 = 65,536 种颜色。
RGB888(24位真彩色)

R[7:0]: 8根红色数据线

G[7:0]: 8根绿色数据线

B[7:0]: 8根蓝色数据线

总共 8+8+8 = 24根数据线,可表示 2^24 ≈ 1677万 种颜色。

同步时钟信号CLK

液晶屏与外部使用同步通讯方式,以CLK信号作为同步时钟,在同步时钟的驱动下,每个时钟传输一个像素点数据。

水平同步信号HSYNC

水平同步信号HSYNC(Horizontal Sync)用于表示液晶屏一行像素数据的传输结束, 每传输完成液晶屏的一行像素数据时,HSYNC会发生电平跳变, 如分辨率为800x480的显示屏(800列,480行),传输一帧的图像HSYNC的电平会跳变480次。

垂直同步信号VSYNC

垂直同步信号VSYNC(Vertical Sync)用于表示液晶屏一帧像素数据的传输结束,每传输完成一帧像素数据时,VSYNC会发生电平跳变。 其中"帧"是图像的单位,一幅图像称为一帧,在液晶屏中,一帧指一个完整屏液晶像素点。人们常常用"帧/秒"来表示液晶屏的刷新特性, 即液晶屏每秒可以显示多少帧图像,如液晶屏以60帧/秒的速率运行时,VSYNC每秒钟电平会跳变60次。

数据使能信号DE

数据使能信号DE(Data Enable)用于表示数据的有效性,当DE信号线为高电平时,RGB信号线表示的数据有效。

LCD-TFT显示控制器(LTDC) 简介

LCD-TFT(液晶显示器------薄膜晶体管)显示器控制器提供并行数字 RGB(红色、绿色、 蓝色)以及水平同步、垂直同步、像素时钟和数据使能信号,这些信号直接输出到不同 LCD 和 TFT 面板的接口。STM32H750xx 的 LTDC 主要特性如下:

⚫ 24 位 RGB 并行像素输出;每像素 8 位数据(RGB888)

⚫ 2 个带有专用 FIFO 的显示层(FIFO 深度 64x64 位)

⚫ 支持查色表 (CLUT),每层高达 256 种颜色(256x24 位)

⚫ 可针对不同显示面板编程时序

⚫ 可编程背景色

⚫ 可编程 HSync、VSync 和数据使能(DE)信号的极性

⚫ 每层有多达 8 种颜色格式可供选择:ARGB8888、RGB888、RGB565、ARGB1555、ARGB4444、L8(8 位 Luminance 或 CLUT)、AL44(4 位 alpha+4 位 luminance)和 AL88(8 位 alpha+8位 luminance)

⚫ 每通道的低位采用伪随机抖动输出(红色、绿色、蓝色的抖动宽度为 2 位)

⚫ 使用 alpha 值(每像素或常数)在两层之间灵活混合

⚫ 色键(透明颜色)

⚫ 可编程窗口位置和大小

⚫ 支持薄膜晶体管 (TFT) 彩色显示器

⚫ AXI 主接口支持 16 个双字的突发

⚫ 高达 4 个可编程中断事件

LTDC 控制器主要包含:信号线、图像处理单元、AXI 接口、配置和状态寄存器以及时钟部分,其框图如下所示:

LCD的DE同步模式和HV同步模式

通常,STM32H7都是用SDRAM作为LCD的显存,LTDC控制器会从SDRAM读取数据刷新到LCD显示屏上。刷新模式有DE同步模式和HV同步模式两种。一般大分辨率显示屏用DE同步模式,小分辨率的显示屏用HV同步模式。

DE同步模式

DE模式需要LCD_DE和LCD_CLK信号来控制刷新。比如一个800x480分辨率的裸屏,在DE有效信号的时候(高电平或低电平),就有800个LCD_CLK输出时钟来确认行中800个点。每个时钟有效的时候,从显存读取一次RGB数据。因为存在回扫信号,所以DE是个方波。一个周期的LCD_DE信号,裸屏就扫描一行。扫描480行后,又从第一行扫描开始。这个规律由裸屏的驱动IC所决定的。

HV同步模式

HV模式需要LCD_CLK时钟信号,行同步信号LCD_HSYNC和场同步信号LCD_VSYNC来控制刷新。比如一个480x272分辨率的裸屏,有一个行同步信号LCD_HSYNC产生时(高电平或者低电平脉冲),就有480个LCD_CLK输出时钟来确认行中480个点。每个时钟有效的时候,从显存读取一次RGB数据。再来一个行同步信号LCD_HSYNC产生时(高电平或者低电平脉冲),切换到下一行,继续行同步和时钟输出,扫描272行后,发送一个场同步信号LCD_VSYNC,又重新从第一行扫描开始。

LTDC的时序配置

LTDC的时序控制就是下面几个参数的设置,这几个参数都可以通过寄存器进行配置。

⚫ HSYNC width水平同步宽度设置,以LCD_CLK的像素时钟输出为单位。

⚫ HBP(horizontal back porch period)水平后沿周期设置,以LCD_CLK的像素时钟输出为单位。

⚫ Active width有效宽度设置,以LCD_CLK的像素时钟输出为单位。以480272分辨率为例,Active width = 480。
⚫ HFP(horizontal front porch period)水平前沿周期设置,以LCD_CLK的像素时钟输出为单位。
⚫ VSYNC width垂直同步宽度设置,以LCD_CLK的像素时钟输出为单位。
⚫ VBP(vertical back porch period)垂直后沿周期设置,以LCD_CLK的像素时钟输出为单位。
⚫ Active height有效高度设置,以LCD_CLK的像素时钟输出为单位。以480
272分辨率为例,Active height = 272。

⚫ VFP(vertical front porch period)垂直前沿周期设置,以LCD_CLK的像素时钟输出为单位。

窗口

可为每个层定位和调整大小,各个层必须位于有效显示区域内。

窗口位置和大小通过左上和右下的 X/Y 位置以及包含同步、后沿大小和有效数据区域的内部时序发生器配置。

可编程层位置和大小定义了一行中的第一个/最后一个可见像素和窗口中的第一个/最后一个可见行。它允许显示完整的图像帧,也允许只显示图像帧的一部分。

⚫层中的第一个和最后一个可见像素通过配置 LTDC_LxWHPCR 寄存器中WHSTPOS[11:0] 和WHSPPOS[11:0] 进行设置。

⚫层中的第一个和最后一个可见行通过配置 LTDC_LxWVPCR 寄存器中的 WVSTPOS[10:0] 和 WVSPPOS[10:0] 进行设置。

LTDC层混合

LTDC除了图层1和图层2两个硬件图层以外,还有一个背景层。由于背景层的刷新不需要显存空间,所以可以用这个图层验证LTDC时序配置是否有问题。

背景层仅支持单色设置,固定颜色格式RGB888(LTDC_HandleTypeDef hltdc)我们这里将背景设置为白色:

hltdc.Init.Backcolor.Blue = 255

hltdc.Init.Backcolor.Green = 255

hltdc.Init.Backcolor.Red = 255

对于图层1和图层2来说,支持如下8种颜色格式:

⚫ARGB8888

⚫RGB888

⚫ RGB565

⚫ ARGB1555

⚫ ARGB4444

⚫ L8(8 位 Luminance 或 CLUT)

⚫ AL44(4 位 alpha + 4 位 luminance)

⚫ AL88(8 位 alpha + 8 位 luminance)

实现Alpha混合的关键是要有一个变量可以设置各种透明度。对此,STM32H7准备了两个Alpha供使用:

一个是常数Alpha(0x00表示完全透明,0xFF表示完全不透明),所有颜色格式都可以使用。

另一个是像素Alpha,也就是ARGB8888,ARGB1555,ARGB4444等颜色格式的Alpha通道数值,也就是我们为图层每个位置绘制的实际颜色值。

STM32H7的参考手册给出了具体的混合公式:

BC = BF1 x C + BF2 x Cs

混合后的颜色= 混合系数1 x 当前层颜色 + 混合系数2 x 底层混合后的颜色

STM32CubeMX生成工程

我们参考前面章节STM32H743-结合CubeMX新建HAL库MDK工程,打开CubeMX软件,重复步骤不再展示。我们来看配置LTDC部分配置如下图所示:

注:本章实验我们使用的是7寸普清屏,分辨率为800*480,如果使用高清屏修改对应参数即可

实验代码

1.主函数

c 复制代码
int main(void)
{
    MPU_Config();
    SCB_EnableICache();
    SCB_EnableDCache();
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_LTDC_Init();
    MX_FMC_Init();
    MX_SDMMC1_SD_Init();
    MX_USART6_UART_Init();
    BSP_SDRAM_Init();                                       
    uart6.initialize(115200);
    uart6.printf("\x0c");
    uart6.printf("\033[1;32;40m");     
    uart6.printf("Hello,I am GT7000!\r\n");

    //帧缓冲区地址映射二维数组
    for(int i = 0;i < LCD_HEIGHT;i ++)address_sdram[i] = LCD_SDRAM_ADDRESS + (i * LCD_WIDTH) * 2;
    LCD_ON;                                 //背光开
    demo();                 
    while (1)
    {

    }
}

2.弹球demo函数

c 复制代码
void demo(void)
{
    int bg = RED;                                                                                                   //背景色
    int colo[7] = {RED, BLUE, YELLOW, GREEN, 0x7BEF,0x0000,0x03E0}; //颜色列表
    int x=35,y=35,xs=1,ys=2;                                                                            //圆心开始坐标,xy速度分量
    int oldx,oldy,co=0,i,j;
    int r=30;                                                                                                               //圆半径
    clear_screen(bg);                                                                                               //设置屏幕背景颜色
    draw_circle(x, y, r, RED, 1);                                                                       //画圆
    while(1){
        oldx = x;
        oldy = y;
        x = x + xs;
        y = y + ys;
        if((x+r)>=LCD_WIDTH || (x-r)<=0){
          xs=-1*xs; 
          x = x + 2*xs;
          co++;
          if(co==7)co=0;}
        if((y+r)>=LCD_HEIGHT || (y-r)<=0){
          ys=-1*ys;
          y = y + 2*ys;
          co++;
          if(co==7)co=0;}
            draw_circle(x, y, r, colo[co], 1);                                                      //画圆        
        for(j = oldx-r-2;j < oldx+r+2;j ++){  
            for(i = oldy-r-2;i < oldy+r+2;i ++){
                if(j<=0 || j>=LCD_WIDTH || i<=0 || i>=LCD_HEIGHT)continue;
                    if( (int)(x-j)*(x-j) + (int)(y-i)*(y-i) > (int)r*r  ){
                        *(volatile unsigned short int *) (address_sdram[i] + (j << 1)) = bg;
                    }
             }
        }
        HAL_Delay(10);                                                                                              //延时
    }
}

3.LTDC驱动配置

c 复制代码
void MX_LTDC_Init(void)
{
    LTDC_LayerCfgTypeDef pLayerCfg = {0};
    hltdc.Instance = LTDC;
    hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
    hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
    hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
    hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
    hltdc.Init.HorizontalSync = 19;
    hltdc.Init.VerticalSync = 2;
    hltdc.Init.AccumulatedHBP = 159;
    hltdc.Init.AccumulatedVBP = 22;
    hltdc.Init.AccumulatedActiveW = 1183;
    hltdc.Init.AccumulatedActiveH = 622;
    hltdc.Init.TotalWidth = 1343;
    hltdc.Init.TotalHeigh = 634;
    hltdc.Init.Backcolor.Blue = 255;
    hltdc.Init.Backcolor.Green = 255;
    hltdc.Init.Backcolor.Red = 255;
    if (HAL_LTDC_Init(&hltdc) != HAL_OK)
    {
        Error_Handler();
    }
    pLayerCfg.WindowX0 = 0;
    pLayerCfg.WindowX1 = 1024;
    pLayerCfg.WindowY0 = 0;
    pLayerCfg.WindowY1 = 600;
    pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
    pLayerCfg.Alpha = 0xff;
    pLayerCfg.Alpha0 = 0;
    pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
    pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
    pLayerCfg.FBStartAdress = 0xC0000000;
    pLayerCfg.ImageWidth = 1024;
    pLayerCfg.ImageHeight = 600;
    pLayerCfg.Backcolor.Blue = 255;
    pLayerCfg.Backcolor.Green = 255;
    pLayerCfg.Backcolor.Red = 255;
    if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
    {
        Error_Handler();
    }

}

4.显示画面相关操作函数

c 复制代码
#include "mygui.h"
#include "ltdc.h"

//--------------------- Function Prototype ----------------------//
void clear_screen(int color);
int set_pixel(int x, int y, int color);
int fill_rect(int x0, int y0, int x1, int y1,int color);
int draw_circle(int x, int y, int r, int color, int fill);

//--------------------------- Variable --------------------------// 
int address_sdram[LCD_HEIGHT] = {0};
//清屏函数
void clear_screen(int color)
{
	int i,j;
	for(j = 0;j < LCD_WIDTH;j ++){
		for(i = 0;i < LCD_HEIGHT;i ++){
			*(volatile unsigned short int *) (address_sdram[i] + (j << 1)) = color;
		}
	}
}
//画点函数
int set_pixel(int x, int y, int color) {
	if(x<0 || x>LCD_WIDTH || y<0 || y>LCD_HEIGHT)return 0;
	*(volatile unsigned short int *) (address_sdram[y] + (x << 1)) = color;
	return 0;
}
//边界 修改颜色函数
int fill_rect(int x0, int y0, int x1, int y1,int color) {
  int x;
  for (; y0 <= y1; y0++) {
    for (x = x0; x <= x1; x++) {
      set_pixel(x, y0, color);
    }
  }
  return 0;
}
//画圆函数
int draw_circle(int x, int y, int r, int color, int fill) {
	int i,j;
	if(x<0 || x>LCD_WIDTH || y<0 || y>LCD_HEIGHT)return 0;
	
	for(j = x-r;j < x+r;j ++){
		for(i = y-r;i < y+r;i ++){
			if(fill == 1){
				if( (int)(x-j)*(x-j) + (int)(y-i)*(y-i) <= (int)r*r  ){
					*(volatile unsigned short int *) (address_sdram[i] + (j << 1)) = color;
				}
			}
			else{
				if( (x-i)*(x-i) + (y-j)*(y-j) >= (r-2)*(r) && (x-i)*(x-i) + (y-j)*(y-j) <= (r+1)*(r) ){
					*(volatile unsigned short int *) (address_sdram[i] + (j << 1)) = color;
				}
			}
		}
	}
	return 0;
}

实验现象

屏幕有一个小球在屏幕中来回弹,触碰到边界时小球颜色改变。

normal video

相关推荐
傻童:CPU4 小时前
C语言需要掌握的基础知识点之树
c语言·1024程序员节
zhilin_tang5 小时前
对比select和epoll两种多路复用机制
linux·c语言·架构
weixin_516865266 小时前
STM32H750寄存器操作(硬件I2C)
stm32·1024程序员节
heisd_16 小时前
什么是状态机编程和模块化编程
单片机·嵌入式硬件
成长痕迹7 小时前
【ARM与X86架构对比】
arm开发·架构
liujing102329297 小时前
stm32_关于乐鑫ESP8266-07S WIFI模组烧录安信可科技的MQTT固件流程
科技·stm32·嵌入式硬件
wufeng无峰7 小时前
麒麟系统拔掉鼠标键盘再插上,鼠标键盘没反应
计算机外设·麒麟系统
科技每日热闻7 小时前
双模新战力!EVNIA弈威双核电竞显示器27M2N5800Z秒切战局,帧取先机!
计算机外设
恶猫7 小时前
FastGestures v2.2.51 鼠标、触控板、屏手势软件
计算机外设·鼠标·手势·触控板·屏手势·手势操作