ARM基本接口之LCD实验

  实验名称:LCD显示实验

实验目的:

1. 了解LCD显示的基本原理

2. 掌握LCD显示汉字和英文的方法原理

3. 掌握LCD显示图形的方法

 

实验过程(含步骤):

1. 过程:这次LCD显示实验是组内的燕同学提出的想法,起初大家感觉挺不错的,同时也想满足一下她,但是在实验中展示出来的效果并不是理想中的,并且我们也是和另外一个组合作的,但毕竟机器只有一台,实际参与的人并不多,也不可能多。在机器中还不能做到随心所欲,有些想实现的功能还没来得及实现,画面不够想象中唯美,但实验的基本要求是做到了。虽然可能没有其他某些组的好看啥的,但我们自始自终都是在为开始的设想努力,如此而已。

2. 代码如下:

 

/*Main.c */

#include "def.h"

#include "2410lib.h"

#include "option.h"

#include "2410addr.h"

#include "interrupt.h"

#include "lcdlib.h"

 

/*STN,反射式LCD器件,功耗小,在比较暗的环境中清晰度很差,需配备外部明光源*/

/*难做出高分辨率的产品,适于显示小尺寸黑白数字,字符,手表,时钟,电话,传真机*/

//#define STN_LCD

/*TFT,“背透”与“反射”结合,耗电和成本较高,反应快,在液晶的背部设置特殊光管*/

/*显示品质好,适用于电脑,手机,液晶电视等*/

#define TFT_8_0

 

int length=800;//目标机屏幕长800像素

int width=600;/目标机屏幕宽600像素

 

void (*PutPixel)(U32,U32,U32);

void Lcd_Disp_Char(void);

void Lcd_Disp_Grap(void);

void print_Circle(int r,int x,int y,int color);

/********************************************************************

// Function name	: Main

// Description	    : JXARM9-2410 LCD显示实验主程序

//                    实现功能:显示设计的画面

// Return type	: void

// Argument         : void

*********************************************************************/

void Main(void)

{

/* 配置系统时钟 */

    ChangeClockDivider(2,1);

    U32 mpll_val = 0 ;

    mpll_val = (92<<12)|(1<<4)|(1);

    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);

    

    /* 初始化端口 */

    Port_Init();

    

    /* 初始化串口 */

    Uart_Init(0,115200);

    Uart_Select(0);

    

    /* 打印提示信息 */

PRINTF("\n---LCD测试程序---\n");

PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");

 

/* LCD初始化 */

    Lcd_Port_Init();

//#ifdef STN_LCD

//    Lcd_Init(MODE_CSTN_8BIT);

//    Glib_Init(MODE_CSTN_8BIT);

//    Lcd_CstnOnOff(1);

//    

//    Glib_ClearScr(0xff, MODE_CSTN_8BIT);

//#else

#ifdef TFT_8_0

rGPCCON &= ~(3<<8);

rGPCCON |= (2<<8);

/*主要:设置16bpp TFT模式,RGB5:6:5格式*/

 Lcd_Init(MODE_TFT_16BIT_800600);//具体函数在末尾

Glib_Init(MODE_TFT_16BIT_800600);//根据所传参数确定函数指针PutPixel使用哪个函数

 Glib_ClearScr(0xffff, MODE_TFT_16BIT_800600);//清屏

Lcd_PowerEnable(0, 1);/*STN-LCD/TFT-LCD的电源控制信号PWERN使能和控制信号极性*/

    Lcd_EnvidOnOff(1); /*允许视频和LCD控制信号输出*/

 

    #endif

//#endif

//#define LCD_DISP_CHAR

#ifdef  LCD_DISP_CHAR	//改

#else

Lcd_Disp_Grap();/*河流颜色渐变*/

Lcd_Disp_Char();/*“心怀沧月”的中文显示*/

Glib_disp_ascii16x8(3*length/4,width/10,"Our Picture",0x0);/*“Out Picture”英文显示*/

Glib_Line(length/14,(7*width)/10,length/5,width/4,0x0);/*山的线条1*/

Glib_Line(length/5,width/4,2*length/7,(7*width)/10,0x0);/*山的线条2*/

Glib_Line(33*length/140,(4*width)/10,2*length/7,width/5,0x0);/*山的线条3*/

Glib_Line(2*length/7,width/5,52*length/140,(7*width)/10,0x0);/*山的线条4*/

Glib_Line(87*length/140,(7*width)/10,105*length/140,width/5,0x0);/*山的线条5*/

Glib_Line(105*length/140,width/5,11*length/14,7*width/20,0x0);/*山的线条6*/

Glib_Line(10*length/14,(7*width)/10,12*length/14,15*width/100,0x0);/*山的线条7*/

Glib_Line(length,(7*width)/10,12*length/14,15*width/100,0x0);/*山的线条8*/

Glib_Line(0,(7*width)/10,length,7*width/10,0x0);/*山的线条9*/

print_Circle(3*width/25,length/2,(3*width)/20,0xFFB0);/**/

while(1);

#endif

  //  }

}    

 

void Lcd_Disp_Char(void)//{

/* 显示字符串 */

 	Glib_disp_hzk16(30,10,"心", 0x0);

 	Glib_disp_hzk16(30,60,"怀", 0x0);

 	Glib_disp_hzk16(30,110,"沧", 0x0);

 	Glib_disp_hzk16(30,160,"月", 0x0);

}

/*在屏幕纵轴方向颜色渐变*/

void Lcd_Disp_Grap(void)

{

int i,j;

int a=0x0010;

int color=0x07e0;

    for(j=600;j>7*width/10;j--){  //从600到420方向进行填色

  	  for(i=0;i<800;i++){	//屏幕横轴为800像素

    (*PutPixel)(i,j,color);

    }

  if(j%5==0){	//每5行进行一次颜色渐变

    	color=a;

    	a=a+0x0020;

   }

}

}

/*	    

Delay (100);   	   

   

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

  	  for(i=0;i<600;i++)	//刷屏参考

    (*PutPixel)(j,i,0x07e0);

   

Delay (100);   	   

*/

/*八分法画圆*/

void print_Circle(int r,int x,int y,int color){

int a,b;

a=0;b=r;//初始化起点为(0,r)

while(2*b*b>=r*r-100){//以纵坐标b来限制变化范围为八分之一的弧*/

/*八个对称域,只要画出八分之一弧,利用对称性就可以画出整个圆*/

Glib_Line(x+a,y-b,x,y,color);

Glib_Line(x-a,y-b,x,y,color);

Glib_Line(x-a,y+b,x,y,color);

Glib_Line(x+a,y+b,x,y,color);

Glib_Line(x+b,y-a,x,y,color);

Glib_Line(x-b,y-a,x,y,color);

Glib_Line(x-b,y+a,x,y,color);

Glib_Line(x+b,y+a,x,y,color);

a++;//横坐标往前试探性+1

if(a*a+b*b-r*r>=0){//若在圆外

a--;b--;//回退到上一个点(a,b)的下方(a,b-1)处

}

}

}

 

 

/*glib.c*/

#include "def.h"

#include "lcdlib.h"

#include "glib.h"

#include "lcd.h"

#include "hzk16.h"

#include "ascii.h"

 

void (*PutPixel)(U32,U32,U32);

 

void Glib_Init(int type)

{

    switch(type)

    {

    case MODE_STN_1BIT:

    	PutPixel=_PutStn1Bit;

    	break;

    

    case MODE_CSTN_12BIT:

    	PutPixel=_PutCstn12Bit;

    	break;   

    case MODE_TFT_8BIT_240320:

    	PutPixel=_PutTft8Bit_240320;   

    	break;   

    case MODE_TFT_16BIT_240320:

    	PutPixel=_PutTft16Bit_240320;

    	break;   

    case MODE_TFT_1BIT_640480:

    	PutPixel=_PutTft1Bit_640480;

    	break;   

    

//--------------------------------------

    case MODE_TFT_1BIT_800600:

    	PutPixel=_PutTft1Bit_800600;

    	break;   

    case MODE_TFT_8BIT_800600:

    	PutPixel=_PutTft8Bit_800600;

    	break;   

    case MODE_TFT_16BIT_800600:

    	PutPixel=_PutTft16Bit_800600;

    	break;   

//--------------------------------------

    default:

    	break;

    }

}

 

 

 

void _PutTft8Bit_640480(U32 x,U32 y,U32 c)

{

    if(x<SCR_XSIZE_TFT_640480 && y<SCR_YSIZE_TFT_640480)

        frameBuffer8BitTft640480[(y)][(x)/4]=( frameBuffer8BitTft640480[(y)][x/4]

        & ~(0xff000000>>((x)%4)*8) ) | ( (c&0x000000ff)<<((4-1-((x)%4))*8) );

}

 

 

void _PutTft16Bit_640480(U32 x,U32 y,U32 c)

{

    if(x<SCR_XSIZE_TFT_640480 && y<SCR_YSIZE_TFT_640480)

        frameBuffer16BitTft640480[(y)][(x)/2]=( frameBuffer16BitTft640480[(y)][x/2]

        & ~(0xffff0000>>((x)%2)*16) ) | ( (c&0x0000ffff)<<((2-1-((x)%2))*16) );

}

 

 

 

void _PutTft24Bit_640480(U32 x,U32 y,U32 c)

{

    if(x<SCR_XSIZE_TFT_640480 && y<SCR_YSIZE_TFT_640480)

        frameBuffer24BitTft640480[(y)][(x)]=( frameBuffer24BitTft640480[(y)][(x)]

        & (0x0) | ( c&0xffffff00)); // | ( c&0x00ffffff)); LSB

}

 

 

 

 

void _PutTft8Bit_800600(U32 x,U32 y,U32 c)

{

    if(x<SCR_XSIZE_TFT_800600 && y<SCR_YSIZE_TFT_800600)

        frameBuffer8BitTft800600[(y)][(x)/4]=( frameBuffer8BitTft800600[(y)][x/4]

        & ~(0xff000000>>((x)%4)*8) ) | ( (c&0x000000ff)<<((4-1-((x)%4))*8) );

}

 

/*此处为实验所使用的函数*/

void _PutTft16Bit_800600(U32 x,U32 y,U32 c)	//需要16位存储一个点的状态(即颜色信息)

{

  if(x<SCR_XSIZE_TFT_800600 && y<SCR_YSIZE_TFT_800600)//判断x,y是否在屏幕有效范围内

     /*数组的一个单元为一个U32型(即unsigned int)(U32在Def.h中定义了),32位*/

/*因此保存整个屏幕像素点的信息,可以用一个单元保存两个点,存储空间压缩一半*/

/*以下每两个点存储在数组的一个单元位置中,如[y][4/2]和[y][5/2]同时存储在[y][2]

,以低16位和高16位区分这两个像素点信息*/

frameBuffer16BitTft800600[(y)][(x)/2]=( frameBuffer16BitTft800600[(y)][x/2]

        & ~(0xffff0000>>((x)%2)*16) ) | ( (c&0x0000ffff)<<((2-1-((x)%2))*16) );

/*先&是对即将要存储像素点信息的那16位进行清零(避免影响后来c值的正确性),位置(低16位还是高16位)根据模2的结果来定*/

/*c&0x0000ffff是保留c的低16位(使用的就是16位颜色模式),<<到的位置和前面清零的位置是一致的(前面是从左到右移位,后面是从右往左移位,要移到相同的位置,移的位数是互补的,所以有左移时的(2-1-((x)%2))*16))*/

}

 

 

 

 

 

/*void Glib_FilledRectangle(int x1,int y1,int x2,int y2,int color)

{

    int i;

 

    for(i=y1;i<=y2;i++)

Glib_Line(x1,i,x2,i,color);

}

*/

 

 

// LCD display is flipped vertically

// But, think the algorithm by mathematics point.

//  --+--   <-8 octants  mathematical cordinate

//   八分法画直线

void Glib_Line(int x1,int y1,int x2,int y2,int color)

{

int dx,dy,e;

dx=x2-x1;

dy=y2-y1;

    

if(dx>=0)

{

if(dy >= 0) // dy>=0

{

if(dx>=dy) // 1/8 octant

{

e=dy-dx/2;

while(x1<=x2)

{

PutPixel(x1,y1,color);

if(e>0){y1+=1;e-=dx;}

x1+=1;

e+=dy;

}

}

else	// 2/8 octant

{

e=dx-dy/2;

while(y1<=y2)

{

PutPixel(x1,y1,color);

if(e>0){x1+=1;e-=dy;}

y1+=1;

e+=dx;

}

}

}

else	   // dy<0

{

dy=-dy;   // dy=abs(dy)

 

if(dx>=dy) // 8/8 octant

{

e=dy-dx/2;

while(x1<=x2)

{

PutPixel(x1,y1,color);

if(e>0){y1-=1;e-=dx;}

x1+=1;

e+=dy;

}

}

else	// 7/8 octant

{

e=dx-dy/2;

while(y1>=y2)

{

PutPixel(x1,y1,color);

if(e>0){x1+=1;e-=dy;}

y1-=1;

e+=dx;

}

}

}

}

else //dx<0

{

dx=-dx;	//dx=abs(dx)

if(dy >= 0) // dy>=0

{

if(dx>=dy) // 4/8 octant

{

e=dy-dx/2;

while(x1>=x2)

{

PutPixel(x1,y1,color);

if(e>0){y1+=1;e-=dx;}

x1-=1;

e+=dy;

}

}

else	// 3/8 octant

{

e=dx-dy/2;

while(y1<=y2)

{

PutPixel(x1,y1,color);

if(e>0){x1-=1;e-=dy;}

y1+=1;

e+=dx;

}

}

}

else	   // dy<0

{

dy=-dy;   // dy=abs(dy)

 

if(dx>=dy) // 5/8 octant

{

e=dy-dx/2;

while(x1>=x2)

{

PutPixel(x1,y1,color);

if(e>0){y1-=1;e-=dx;}

x1-=1;

e+=dy;

}

}

else	// 6/8 octant

{

e=dx-dy/2;

while(y1>=y2)

{

PutPixel(x1,y1,color);

if(e>0){x1-=1;e-=dy;}

y1-=1;

e+=dx;

}

}

}

}

}

 

 

/*清除屏幕*/

void Glib_ClearScr(U32 c, int type)

{

    //Very inefficient function.

    int i,j;

    if((type==MODE_TFT_1BIT_800600)|(type==MODE_TFT_8BIT_800600)|(type==MODE_TFT_16BIT_800600))

    if((type&0x4000)&&(type&0x400))

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

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

        PutPixel(i,j,c);

    //else

}

 

/*****************************************************************************

// Function name	: Glib_disp_hzk16

// Description	    : 在LCD的(x,y)坐标处以colour颜色显示s中的汉字

// Return type	: void

// Argument         : int x : x坐标

// Argument         : int y : y坐标

// Argument         : char *s : 待显示字符串

// Argument         : int colour : 显示颜色

*****************************************************************************/

void Glib_disp_hzk16(int x,int y,char *s,int colour)

{

char buffer[32];	/* 32字节的字模缓冲区	*/

 	int i,j,k;

 	unsigned char qh,wh;

 	unsigned long location;

 

 	while(*s)

  	{	/*计算机汉字信息是以机内码存储,区位码=机内码-0xa0a0*/

   	qh=*s-0xa0;	/* 计算区码	*/

   	wh=*(s+1)-0xa0;	/* 计算位码	*/

   	location=(94*(qh-1)+(wh-1))*32L;	/* 计算字模在文件中的位置,区和位从1开始	*/

/*一个区94个汉字,一个汉字字模32字节*/

   	memcpy(buffer, &__HZK16X16__[location], 32);	// 获取汉字字模,存储在buffer

for(i=0;i<16;i++)	/* 每一行	*/

{

    	for(j=0;j<2;j++)	/* 一行两个字节	*/

{

     	for(k=0;k<8;k++)	/* 每个字节按位显示	*/

{	/*buffer是一维数组,一个单元一个字节即8位*/

      	if(((buffer[i*2+j]>>(7-k)) & 0x1) != 0)//对一个单元中的每一位进行判断

       	PutPixel(x+8*(j)+k,y+i,colour); /* 显示一位	*/

}

}

}//到这里处理完一个中文字符的显示

   	s+=2;	/*一个汉字需两个char,这里指下一个汉字	*/

   	x+=16;	/*定位在原x往后16个像素点的位置,指汉字间距	*/

  	}

}

/*****************************************************************************

// Function name	: lcd_disp_ascii16x8

// Description	    : 在LCD的(x,y)坐标处以colour颜色显示s中的ASCII字符

// Return type	: void

// Argument         : int x : x坐标

// Argument         : int y : y坐标

// Argument         : char *s : 待显示字符串

// Argument         : int colour : 显示颜色

*****************************************************************************/

void Glib_disp_ascii16x8(int x,int y,char *s,int colour)

{

char buffer[16];	/* 16字节的字模缓冲区	*/

 	int i,j,k;

 	unsigned long location;

 	unsigned char  a;

 

 	while(*s)

  	{

   

   	a=*s;

 	location=(a)*16L;	/*(a)是ascii表示的,ascii头文件中按ascii排序,

无需经历像汉字的转换,直接计算出位置即可*/

   	memcpy(buffer, &__ASCII8X16__[location], 16);	/* 在ascii.h中获取英文字模*/

for(i=0;i<16;i++)	/* 每一行	*/

{

    

     	for(k=0;k<8;k++)	/* 每个字节按位显示	*/

{

      	if(((buffer[i]>>(7-k)) & 0x1) != 0)/*分别判断每一位*/

       	PutPixel(x+k,y+i,colour); /* 显示一位	*/

}

}

   	s+=1;	/* 下一个char	*/

   	x+=16;	/* 字符间距,隔16个像素点再显示下一个char	*/

  	}

}

 

/*Lcd_Init函数*/

void Lcd_Init(int type)

{

    switch(type)

    {

    case MODE_TFT_16BIT_800600:

frameBuffer16BitTft800600=(U32 (*)[SCR_XSIZE_TFT_800600/2])LCDFRAMEBUFFER;

   	rLCDCON1=(CLKVAL_TFT_800600<<8)|(MVAL_USED<<7)|(3<<5)|(12<<1)|0;

        // TFT LCD panel,16bpp TFT,ENVID=off//设置每像素位BPP模式为16bpp TFT

rLCDCON2=(VBPD_800600<<24)|(LINEVAL_TFT_800600<<14)|(VFPD_800600<<6)|(VSPW_800600);

rLCDCON3=(HBPD_800600<<19)|(HOZVAL_TFT_800600<<8)|(HFPD_800600);

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

rLCDCON5=(1<<11)|(1<<10)|(1<<9)|(1<<8);//设置RGB5:6:5模式

//BPP24BL:x,FRM565:o,INVVCLK:x,INVVLINE:o,INVVFRAME:o,INVVD:x,

//INVVDEN:x,INVPWREN:x,INVLEND:x,PWREN:x,ENLEND:x,BSWP:x,HWSWP:x

rLCDSADDR1=(((U32)frameBuffer16BitTft800600>>22)<<21)|M5D((U32)frameBuffer16BitTft800600>>1);

rLCDSADDR2=M5D( ((U32)frameBuffer16BitTft800600+(SCR_XSIZE_TFT_800600*LCD_YSIZE_TFT_800600*2))>>1 );

rLCDSADDR3=(((SCR_XSIZE_TFT_800600-LCD_XSIZE_TFT_800600)/1)<<11)|(LCD_XSIZE_TFT_800600/1);

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

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

rTPAL=0; // Disable Temp Palette

 

    break;

 

    default:

    break;

    }

}

/*Lcd_EnvidOnOff函数*/

void Lcd_EnvidOnOff(int onoff)

{

    if(onoff==1)

rLCDCON1|=1; // ENVID=ON

    else

rLCDCON1 =rLCDCON1 & 0x3fffe; // ENVID Off

}    

/*Lcd_PowerEnable函数*/

void Lcd_PowerEnable(int invpwren,int pwren)

{

    //GPG4 is setted as LCD_PWREN

    rGPGUP=rGPGUP&(~(1<<4))|(1<<4); // Pull-up disable

    rGPGCON=rGPGCON&(~(3<<8))|(3<<8); //GPG4=LCD_PWREN

    //Enable LCD POWER ENABLE Function

    rLCDCON5=rLCDCON5&(~(1<<3))|(pwren<<3);   // PWREN

    rLCDCON5=rLCDCON5&(~(1<<5))|(invpwren<<5);   // INVPWREN

}    

实验总结:

wq

这次led显示实验,我们组制作了一副简易的山水画,先还是老问题,机器连接是硬伤。然后我们就开始在机器上作图了,这次我们的图上文字(包括汉字和英文)是采取绝对定位的形式,直接给出像素坐标来显示的;而图形部分(三角形的山,原形的月亮)是利用屏幕尺寸和图形比例来相对定位显示的。

 

yy:

这次led显示实验,因为机器连接问题,所以我们是两个组共用一台机器来做的,因此每个人接触机器的时间变少了。所以在这次实验中,我做的更多的不是编写代码,而是阅读代码,尽管这次实验的代码阅读起来也比较有意思,但是我还是衷心希望学校的机器能不要再出这么多问题

zhy:

这次led显示实验,由我设计了一副简易的山水图——《心怀沧月》,因为没带自己的电脑,只有先用PPT设计,然后经过测量计算得出各个线条的连接点,最后带入代码画出图 。图中主要有三角形和矩形以及圆形,汉字与英文。其中三角形、矩形:给相对点画线;三角形为山,本意用泥土色,深绿色,白色逐层渐变,却未实现;大矩形为海,蓝色渐变,实现。圆形:八分法画圆,利用圆的对称特性提高画圆效率;淡黄色涂色,实现。最后,我发现有其他组非常聪明,用PS软件,先画一幅完整的图,PS上不仅提供了点的坐标还有颜色的十六进制值,用于设计和代码实现均方便许多。

cxy:

这次lcd实验让我学到了不少东西。以前觉得在电脑上画图片很容易,现在发现从底层实现画图其实根本不容易。尤其是在画月亮的时候,使用八分法画圆画出来没有什么问题,但是在填充完颜色之后,问题就出现了,圆圈中有缝隙没有被填充上颜色。尝试修改了很多次才去除了中间的缝隙。

lg:

这次实验是我们和另外一个组合作的,说是合作,其实效率太低,这让我想到了《人月神话》,

资源就那么多,单纯的增加人员,收效不大反而更小,小小的团队如此,何况真正开发的团队。但这次实验还是了解了英文汉字在屏幕中是如何显示的,汉字和英文在计算机是以什么形式存储的,机内码和区位码转换,八分法画圆。而且比较深的感受是,对硬件的操作多数是直接对寄存器内存进行读写。

猜你喜欢

转载自blog.csdn.net/cinderella___/article/details/80463847
今日推荐