基于MDK的LCD显示实验

ARM 127浏览

基于MDKLCD显示实验

1实验目的

1)了解TFTLCD的基本工作原理和特点,掌握LCD的接口电路设计。

2)掌握S3C2410A处理器的LCD控制器的使用方法。

3)掌握LCD显示文本及图形的方法。

2实验设备

硬件:ARM实验平台,ULINK2仿真器,PC机,串口线。

软件:µVision IDE for ARM集成开发环境。

3实验内容

1)设置LCD显示方式为16bppR:G:B=5:6:5

    2)清除整个屏幕;显示彩色位图;画出多个矩形框;显示ASCII字符; 显示汉字字符。 

图 3-1 实验预期结果

4.接口电路原理 

1S3C2410A  LCD控制器介绍

LCD控制器用于传输显示数据和产生控制信号。支持屏幕水平和垂直滚动显示。数据的传送采用DMA(直接内存访问)方式。

 

图4-1-1 LCD控制器的内部结构框图

4-1-1中,REGBANK17个用于配置LCD控制器的可编程寄存器组和256×16的调色板存储器,用来设定LCD控制器;

LCDCDMA是一个专用的DMA通道,可以把保存在存储器的帧数据自动地传送到LCD控制器;VIDPRCS接收来自LCDCDMA的视频数据,并且将其变换为适当格式;

TMIEGEN 包含可编程逻辑用于支持不同 LCD驱动器对时序以及速率的需求,VFRAMEVLINEVCLKVM 等控制信号由TIMEGEN产生。

表4-1-1 S3C2410X LCD 控制器输出接口说明

输出接口信号

描述

VFRAME

垂直同步信号(TFT

VLINE

水平同步信号(TFT

VCLK

时钟信号

VD[23:0]

显示数据输出端口(STN/TFT/SEC TFT)

VM

数据使能信号(TFT)

LEND

行结束信号(TFT)

LCD_PWREN

LCD电源使能

LCDVF0

SECTFT信号OE

LCDVF1

SECTFT信号REV

LCDVF2

SEC TFT信号REVB

 

2)处理器与LCD接口电路原理


图4-1 LCD接口电路原理图

 

5.实验原理 

1)清屏及画矩形框原理

LCD的大小为:800×48016bpp无调色真彩显示,R:G:B=565。能表示65536种颜色0x0000~0xffff

BSWP=0,HWSWP=0时,像素点在内存中的表示方法如表所示:

  表5-1 像素点在内存中的表示方法

            数据位

  内存地址

D[15:0]

0x31000000

P1(第一个像素点)

0x31000002

P2

0x31000004

P3

 

实验中设置显示缓冲起始地址设置为0x31000000,结束地址为0x311BB800

结束地址计算方法为:起始地址+2×实际屏的象素大小,第二个2表示每个像素点占的两个字节数。

定义一个指向一维数组的指针变量: 

unsigned short int(*frameBuffer16BitTft800480)[1600];

该指针的值为0x31000000。通过该指针变量将二维数组元素的值存放在内存缓冲空间中。 


图5-1-1 实际LCD与内存缓冲冲空间对应关系示意图

1)向上述地址空间写入0x0000就实现了清屏操作。

2)向红色矩形框所经过的像素点位置写入0xf800就画出了红色矩形框。

2)显示彩色图片原理

ImagetoLCD将图片格式转换成C语言的数组类型(const unsigned char g_ucBitmap[768000])。

 

 

图 4-2-1 使用ImagetoLCD转换图片

定义一个指向一维数组的指针变量:

unsigned short int *pView[SCR_XSIZE_TFT_800480];

该指针的值为0x31000000。通过指针变量将数组元素的值存放在内存缓冲空间中,即可实现显示一幅图片。

3)显示字符原理

1)显示ASCII字符原理

8×16ASCII字模文件中,以16个字节表示一个英文字模信息。所有英文字模信息存放在一个一维数组g_ucAscii8x16[]中。

用英文字母的ASCII码值乘上16即定位出字模信息在一维字模库中的位置,然后输出字模信息到内存缓冲区即可在LCD上显示出英文字母。

以字母“A”为例:“A”的ASCII码值97,所以从g_ucAscii8x16[97×16]单元地址开始的16个字节内容存放着“A”的字模信息。字模信息如图5-3-1所示:

 

图5-3-1 8*16英文字模信息

2)显示汉字原理

 汉字输入进计算机后由两个字节表示(国标码)。而字模库采用了Hzk24h(24×24),汉字字模信息存放在一个一维数组g_auc_hzk24[]中,以72个字节表示一个字模信息。

程序中定义数组code[2]存放汉字国标码。

字库中汉字字模信息的定位方法(也即国标码到字形码的转换公式):

字模信息在数组中的位置=( (code[0]-0xA1-15) *94 + (code[1]-0xA1) )*72。

以字母“你”为例:从g_ucAscii8x16[( (code[0]-0xA1-15) *94 + (code[1]-0xA1) )*72]单元地址开始的72个字节内容存放着“你”的字模信息。字模信息如图5-3-2所示:

 

 

图5-3-2 16*16汉字字模信息

 

5.软件部分

   实验整体流程图如图5-1所示:

图5-1 程序整体流程图

1)初始化部分说明

1LCD控制器的接口与通用IO端口CIO端口D复用引脚,所以首先配置端口C和端口D的控制寄存器使引脚用作为功能输出。

2)配置LCD控制寄存器LCDCON1~LCDCON5,显示缓冲地址寄存器LCDSADDR1LCDSADDR2

2)操作像素点说明

操作像素点时只需调用如下函数:

void _PutTft16Bit_800480(UINT32T x,UINT32T y,UINT32T c)

{

    if(x<SCR_XSIZE_TFT_800480 && y<SCR_YSIZE_TFT_800480)

    frameBuffer16BitTft800480[y][x]=(c&0xffff);

 }

函数输入:像素点坐标xy;像素点颜色c。对LCD的操作均通过该函数实现。

函数功能:对指定坐标处的LCD像素缓冲地址写入特定颜色。

3)显示图像算法分析

利用ImagetoLCD将图片格式转换成C语言的数组类型是unsigned char[]。数据是按字节存放,二个字节存放一位像素信息。

图像显示子程序流程图如图5-3-1所示:

     图5-3-1 图像显示子程序流程图

for (i = 0; i < LCD_YSIZE_TFT_800480; i++)

{

   for (j = 0; j < LCD_XSIZE_TFT_800480; j++)

    {

       bcolor=((*(pBuffer+1)) << 8) + ((*(pBuffer)));

  _PutTft16Bit_800480( j, i, (UINT16T)bcolor);

   pBuffer += 2;

    }

程序中:pBuffer指向数组首地址;bcolor为像素颜色;ij为像素坐标。

4)画矩形框算法说明

画矩形框时根据矩形框的端点坐标画出4条首尾相接的直线即可。

5)字符显示算法分析

1)英文字符显示

首先定位出英文字符在字模库中的位置,并将字模信息输出到LCD显示缓冲。

英文字符显示子程序流程图流程图如图5-5-1a)中 所示:

图5-5-1 英文字符显示子程序流程图

2)汉字字符显示

首先定位出汉字字符在字模库中的位置,并将字模信息输出到LCD显示缓冲。

汉字字符显示子程序流程图流程图如图5-5-1b)所示:

6.实验结果

   实验结果如图6-1所示:

 

图6-1 实验结果

7.附录:

1)初始化程序

void Lcd_port_init(void)

{

 

    rGPCUP=0xffffffff;                                          // Disable Pull-up register                                       

    rGPCCON=0xaaaaaaaa;  // Initialize VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND

rGPDUP=0xffffffff;                                          // Disable Pull-up register

    rGPDCON=0xaaaaaaaa;                                         // Initialize VD[23:8]

    uart_printf(" Initializing GPIO ports..........n");

 

frameBuffer16BitTft800480=(UINT16T(*)[SCR_XSIZE_TFT_800480])LCDFRAMEBUFFER;    rLCDCON1=(CLKVAL_TFT_800480<<8)|(MVAL_USED<<7)|(3<<5)|(12<<1)|0;

                                                         //rLCDCON1=rLCDCON1&0xFFFFFE7E;

                                                         // TFT LCD panel,16bpp TFT,ENVID=off  

                                             //HCLK=100Mhz VCLK=50Mhz ,

  rLCDCON2=(VBPD_800480<<24)|(LINEVAL_TFT_800480<<14)|(VFPD_800480<<6)|(VSPW_800480);

  rLCDCON3=(HBPD_800480<<19)|(HOZVAL_TFT_800480<<8)|(HFPD_800480);

  rLCDCON4=(MVAL<<8)|(HSPW_800480);

  rLCDCON5=(1<<11)|(1<<9)|(1<<8);                    //FRM5:6:5,HSYNC and VSYNC are inverted

    rLCDSADDR1=(((UINT32T)frameBuffer16BitTft800480>>22)<<21)|M5D((UINT32T)frameBuffer16BitTft800480>>1);                                           //设定显示数据缓存区的的开始地址

    rLCDSADDR2=M5D( ((UINT32T)frameBuffer16BitTft800480+(SCR_XSIZE_TFT_800480*LCD_YSIZE_TFT_800480*2))>>1 );                                     //显示数据缓存区的结束地址

    rLCDSADDR3=(((SCR_XSIZE_TFT_800480-LCD_XSIZE_TFT_800480)/1)<<11)|(LCD_XSIZE_TFT_800480/                                                //虚拟屏幕为2*实际屏幕大小

    rLCDINTMSK|=(3);                               // MASK LCD Sub Interrupt

    rLPCSEL&=(~7);                                 // Disable LPC3600

    rTPAL=0;     

}

 

2)显示位图程序

void BitmapViewTft16Bit_800480(UINT8T *pBuffer)

{

    UINT32T i, j;

UINT16T bcolor;

for (i = 0; i < LCD_YSIZE_TFT_800480; i++)

{

   for (j = 0; j < LCD_XSIZE_TFT_800480; j++)     {

      bcolor=((*(pBuffer+1)) << 8) + ((*(pBuffer)));

 _PutTft16Bit_800480( j, i, (UINT16T)bcolor);

 pBuffer += 2;  //&pView[400]=0x31000640

    

    }

}

   

}

 

3)显示汉字程序

void Lcd_DspHz24(UINT16T x0, UINT16T y0, UINT16T ForeColor, UINT8T *s)  //24*24

{

INT16T i,j,k,x,y,xx;

UINT8T qm,wm;

INT32T ulOffset;

INT8T hzbuf[72];

 

for(i = 0; i < strlen((const char*)s); i++)

{

if(((UINT8T)(*(s+i))) < 161)

{

break;

}

else

{

   qm = *(s+i) - 176;                         

        wm = *(s+i + 1) - 161; //字形在字库文件中的定位

             ulOffset = (INT32T)(qm * 94 + wm) * 72;

            for (j = 0; j < 72; j ++)

            {

             hzbuf[j] = g_auc_hzk24[ulOffset + j];

             }

            for(y = 0; y < 24; y++)

            { 

 for(x = 0; x < 24; x++) 

              {

                      k = x % 8;

        if (hzbuf[y * 3 + x / 8]  & (0x80 >> k))

        {

        xx = x0 + x + i*12;                //一个汉字占两个字节

        _PutTft16Bit_800480( xx, y + y0, (UINT16T)ForeColor);

        }

      }

            }

    i++;

          }

      }     

}

 

 

4)显示英文字符程序

void Lcd_DspAscII8x16(UINT16T x0, UINT16T y0, UINT16T ForeColor, UINT8T * s)

{

INT16T i,j,k,x,y,xx;

UINT8T qm;

INT32T ulOffset;

INT8T ywbuf[16];

    

for(i = 0; i < strlen((const char*)s); i++)

{

if((UINT8T)*(s+i) >= 161) {

return;

}

else

{

         qm = *(s+i);

             ulOffset = (INT32T)(qm) * 16;  //16个字节

             for (j = 0; j < 16; j ++)

             {

             ywbuf[j] = g_ucAscii8x16[ulOffset + j];

             }

 

             for(y = 0; y < 16; y++)

             {

                for(x = 0; x < 8; x++) 

                {

                    k = x % 8;

        if (ywbuf[y]  & (0x80 >> k))

        {

        xx = x0 + x + i*8;

        _PutTft16Bit_800480( xx, y + y0, (UINT16T)ForeColor);

        }

    }

             }

          }

      }

}

 

 

5)像素点操作程序

void _PutTft16Bit_800480(UINT32T x,UINT32T y,UINT32T c)

{

    if(x<SCR_XSIZE_TFT_800480 && y<SCR_YSIZE_TFT_800480)

    frameBuffer16BitTft800480[y][x]=(c&0xffff);

  

}