您的位置 首页 应用

根据ARM9的LCD程序编写

人机交互是嵌入式系统必须具有的功能。比较简单的人机交互有按键、LED、蜂鸣器,稍微复杂的有7段数码管和点阵。但如今这些都不能满足人们…

人机交互是嵌入式体系有必要具有的功用。比较简单的人机交互有按键、LED、蜂鸣器,略微
杂乱的有7 段数码管和点阵。但现在这些都不能满意人们的需求了,所以又出现了LCD
触摸屏技能。s3c2440 具有LCD 和触摸屏接口,能够很好的衔接LCD 和触摸屏。这篇文章
首要介绍TFT 型LCD 的用法。
要想正确运用LCD,有必要留意两点:1、时序;2、显现缓存区。
1、时序
LCD 一般需求三个时序信号:VSYNC、HSYNC 和VCLK。VSYNC 是笔直同步信号,在每
进行一个帧(即一个屏)的扫描之前,该信号就有用一次,由该信号能够确认LCD 的场频,
即每秒屏幕改写的次数(单位Hz)。HSYNC 是水平同步信号,在每进行一行的扫描之前,
该信号就有用一次,由该信号能够确认LCD 的行频,即每秒屏幕从左到右扫描一行的次数
(单位Hz)。VCLK 是像素时钟信号。
s3c2440 处理LCD 的时钟源是HCLK,经过寄存器LCDCON1 中的CLKVAL 能够
调整VCLK 频率巨细,它的公式为:
VCLK=HCLK÷[(CLKVAL+1)×2]
例如,HCLK 的频率为100MHz,要想驱动像素时钟信号为6.4MHz 的LCD 屏,则经过上
式核算CLKVAL 值,成果CLKVAL 为6.8,取整后(值为6)放入寄存器LCDCON1 中相
应的方位即可。由于CLKVAL 进行了取整,因而咱们把取整后的值代入上式,从头核算
VCLK,得到VCLK=7.1MHz。
按理说,关于一个已知尺度(即水平显现尺度HOZVAL 和笔直显现尺度LINEVAL 已知)
的LCD 屏,只需确认了VCLK 值,行频和场频就应该知道了。但这样还不可的,由于在每
一帧时钟信号中,还会有一些与屏显现无关的时钟出现,这就给确认行频和场频带来了必定
的杂乱性。如在HSYNC 信号先后会有水平同步信号前肩(HFPD)和水平同步信号后肩
(HBPD)出现,在VSYNC 信号先后会有笔直同步信号前肩(VFPD)和笔直同步信号后
肩(VBPD)出现,在这些信号时序内,不会有有用像素信号出现,别的HSYNC 和VSYNC
信号有用时,其电平要坚持必定的时刻,它们别离叫做水平同步信号脉宽HSPW 和笔直同
步信号脉宽VSPW,这段时刻也不能有像素信号。因而核算行频和场频时,必定要包含这些
信号。HBPD、HFPD 和HSPW 的单位是一个VCLK 的时刻,而VSPW、VFPD 和VBPD 的
单位是扫描一行所用的时刻。在s3c2440 中,一切的这些信号(VSPW、VFPD、VBPD、
LINEVAL、HBPD、HFPD、HSPW 和HOZVAL)都是实践值减1 的成果。这些值是经过寄
存器LCDCON2、LCDCON3 和LCDCON4 来装备,只需把这些值装备成与所要驱动的LCD
中相关内容的数据共同即可。例如,咱们所要显现的LCD 屏巨细为320×240,因而HOZVAL
=320-1,LINEVAL=240-1。水平同步信号的脉宽、前肩和后肩别离为30、20 和38,则
HSPW=30-1,HFPD=20-1,HBPD=38-1;笔直同步信号的脉宽、前肩和后肩别离为
3、12 和15,则VSPW=3-1,VFPD=12-1,VBPD=15-1。
下面咱们就详细核算一下行频(HSF)和场频(VSF):
HSF=VCLK÷[(HSPW+1)+(HSPD+1)+(HFPD+1)+(HOZVAL+1)]
=7.1÷408=17.5kHz
VSF=HSF÷[(VSPW+1)+(VBPD+1)+(VFPD+1)+(LINEVAL+1)]
=17.5÷270=64.8Hz
在有些情况下,s3c2440 的LCD 时钟信号的默许极性与所操控的LCD 时钟信号的极性相反,
这时能够经过寄存器LCDCON5 的相关位来改动某些时钟信号的极性。
2、显现缓存区
只需把所要显现的数据放入显现缓存区内,就能够在屏幕上出现内容。该缓存区是
咱们自己编程时拓荒的一段内存区。一般咱们是经过界说一个与屏幕尺度巨细相同的二维数
组来拓荒该空间的,这样操控屏幕内容会便利一些,如当屏幕的尺度为320×240 时,能够
界说该缓存区为LCD_BUFFER[240][320]。由于s3c2440 支撑16 位和24 位的非调色板真彩
色的TFT 型LCD 形式,而24 位色彩形式是用32 位数据来表明的,所以前面界说的那个二
维数据的数据类型应该是半字整型或全字整型的。例如,在24 位色彩形式下,咱们想要在
尺度巨细为320×240 屏幕的中心处设置为白色像素,则:LCD_BUFFER[120][160]=0xffffffff。
在s3c2440 中,寄存器LCDSADDR1 和LCDSADDR2 用于设置显现缓存区,即把
咱们界说的那个二维数组告知s3c2440。其间LCDBANK 的9 位数据指定LCD 的BANK,
即显现缓存区的第30 位到第22 位地址;LCDBASEU 的21 位数据指定了LCD 的基址,即
显现缓存区开端地址的第21 位到第1 位;LCDBASEL 的21 位数据指定了LCD 的尾址,即
显现缓存区完毕地址的第21 位到第1 位。例如,咱们想要在尺度为320×240 的屏幕上显现
24 位色彩, 界说的显现缓存区数组为LCD_BUFFER[240][320] , 则LCDBANK 等于
LCD_BUFFER 的第30 位到第22 位数据值(由于LCD_BUFFER 表明的便是数组的首地址),
LCDBASEU 等于LCD_BUFFER 的第21 位到第1 位数据值,由所以用32 位数据表明24 为
色彩,因而每个像素值是4 个字节,所以LCDBASEL 等于(LCD_BUFFER+(240×320×4))
成果的第21 位到第1 位的数据值。别的寄存器LCDSADDR3 有两个内容:OFFSIZE 和
PAGEWIDTH。OFFSIZE 用于虚拟屏幕的偏移长度,假如咱们不运用虚拟屏幕,就把它置为
0;PAGEWIDTH 界说了视口的宽,单位是半字,如在上面的比如中,PAGEWIDTH 应该为
320×32÷16。
下面咱们给出一段详细的TFT 型LCD 显现的实例,其间,屏幕的巨细为320×240,所设置
的色彩为24 位真彩色形式。
#define U32 unsigned int
#define M5D(n) ((n) & 0x1fffff) //用于设置显现缓存区时,取低21 位地址
#define rGPCCON (*(volatile unsigned *)0x56000020) //Port C control
#define rGPCDAT (*(volatile unsigned *)0x56000024) //Port C data
#define rGPCUP (*(volatile unsigned *)0x56000028) //Pull-up control C
#define rGPDCON (*(volatile unsigned *)0x56000030) //Port D control
#define rGPDDAT (*(volatile unsigned *)0x56000034) //Port D data
#define rGPDUP (*(volatile unsigned *)0x56000038) //Pull-up control D
#define rGPGCON (*(volatile unsigned *)0x56000060) //Port G control
#define rGPGDAT (*(volatile unsigned *)0x56000064) //Port G data
#define rGPGUP (*(volatile unsigned *)0x56000068) //Pull-up control G
#define rLCDCON1 (*(volatile unsigned *)0x4d000000) //LCD control 1
#define rLCDCON2 (*(volatile unsigned *)0x4d000004) //LCD control 2
#define rLCDCON3 (*(volatile unsigned *)0x4d000008) //LCD control 3
#define rLCDCON4 (*(volatile unsigned *)0x4d00000c) //LCD control 4
#define rLCDCON5 (*(volatile unsigned *)0x4d000010) //LCD control 5
#define rLCDSADDR1 (*(volatile unsigned *)0x4d000014) //STN/TFT Frame buffer start
address 1
#define rLCDSADDR2 (*(volatile unsigned *)0x4d000018) //STN/TFT Frame buffer start
address 2
#define rLCDSADDR3 (*(volatile unsigned *)0x4d00001c) //STN/TFT Virtual screen
address set
#define rLCDINTMSK (*(volatile unsigned *)0x4d00005c) //LCD Interrupt mask
#define rTCONSEL (*(volatile unsigned *)0x4d000060) //LPC3600 Control — edited by
junon
#define LCD_WIDTH 320 //屏幕的宽
#define LCD_HEIGHT 240 //屏幕的高
//笔直同步信号的脉宽、后肩和前肩
#define VSPW (3-1)
#define VBPD (15-1)
#define VFPD (12-1)
//水平同步信号的脉宽、后肩和前肩
#define HSPW (30-1)
#define HBPD (38-1)
#define HFPD (20-1)
//显现尺度
#define LINEVAL (LCD_HEIGHT-1)
#define HOZVAL (LCD_WIDTH-1)
//for LCDCON1
#define CLKVAL_TFT 6 //设置时钟信号
#define MVAL_USED 0 //
#define PNRMODE_TFT 3 //TFT 型LCD
#define BPPMODE_TFT 13 //24 位TFT 型LCD
//for LCDCON5
#define BPP24BL 0 //32 位数据表明24 位色彩值时,低位数据有用,高8 位
无效
#define INVVCLK 0 //像素值在VCLK 下降沿有用
#define INVVLINE 1 //翻转HSYNC 信号
#define INVVFRAME 1 //翻转VSYNC 信号
#define INVVD 0 //正常VD 信号极性
#define INVVDEN 0 //正常VDEN 信号极性
#define PWREN 1 //使能PWREN 信号
#define BSWP 0 //色彩数据字节不交流
#define HWSWP 0 //色彩数据半字不交流
//界说显现缓存区
volatile U32 LCD_BUFFER[LCD_HEIGHT][LCD_WIDTH];
//延时程序
void delay(int a)
{
int k;
for(k=0;k;
}
//制作屏幕布景色彩,色彩为c
void Brush_Background( U32 c)
{
int x,y ;
for( y = 0 ; y < LCD_HEIGHT ; y++ )
{
for( x = 0 ; x < LCD_WIDTH ; x++ )
{
LCD_BUFFER[y][x] = c ;
}
}
}
//画实心圆,色彩为c。圆心在屏幕中心,半径为80 个像素
void Draw_Circular(U32 c)
{
int x,y ;
int tempX,tempY;
int radius = 80;
int SquareOfR = radius*radius;
for( y = 0 ; y < LCD_HEIGHT ; y++ )
{
for( x = 0 ; x < LCD_WIDTH ; x++ )
{
if(y<=120 && x<=160)
{
tempY=120-y;
tempX=160-x;
}
else if(y<=120&& x>=160)
{
tempY=120-y;
tempX=x-160;
}
else if(y>=120&& x<=160)
{
tempY=y-120;
tempX=160-x;
}
else
{
tempY = y-120;
tempX = x-160;
}
if ((tempY*tempY+tempX*tempX)<=SquareOfR)
LCD_BUFFER[y][x] = c ;
}
}
}
void Main(void)
{
//装备LCD 相关引脚
rGPCUP = 0x00000000;
rGPCCON = 0xaaaa02a9;
rGPDUP = 0x00000000;
rGPDCON=0xaaaaaaaa;
rLCDCON1=(CLKVAL_TFT<<8)|(MVAL_USED<<7)|(PNRMODE_TFT<<5)|(BPPMODE_TF
T<<1)|0;
rLCDCON2=(VBPD<<24)|(LINEVAL<<14)|(VFPD<<6)|(VSPW);
rLCDCON3=(HBPD<<19)|(HOZVAL<<8)|(HFPD);
rLCDCON4=(HSPW);
rLCDCON5 = (BPP24BL<<12) | (INVVCLK<<10) | (INVVLINE<<9) |
(INVVFRAME<<8) | (0<<7) | (INVVDEN<<6) | (PWREN<<3) |(BSWP<<1) | (HWSWP);
rLCDSADDR1=(((U32)LCD_BUFFER>>22)<<21)|M5D((U32)LCD_BUFFER>>1);
rLCDSADDR2=M5D( ((U32)LCD_BUFFER+(LCD_WIDTH*LCD_HEIGHT*4))>>1 );
rLCDSADDR3=LCD_WIDTH*32/16;
rLCDINTMSK|=(3); // 屏蔽LCD 中止
rTCONSEL = 0; //无效LPC3480
rGPGUP=rGPGUP&(~(1<<4))|(1<<4); //GPG4 上拉电阻无效
rGPGCON=rGPGCON&(~(3<<8))|(3<<8); //设置GPG4 为LCD_PWREN
rGPGDAT = rGPGDAT | (1<<4) ; //GPG4 置1
rLCDCON5=rLCDCON5&(~(1<<3))|(1<<3); //有用PWREN 信号
rLCDCON5=rLCDCON5&(~(1<<5))|(0<<5); //PWREN 信号极性不翻转
rLCDCON1|=1; //LCD 敞开
while(1)
{
//黑色布景,白色实心圆
Brush_Background(0x0);
Draw_Circular(0xffffff);
delay(5000000);
//白色布景,黑色实心圆
Brush_Background(0xffffff);
Draw_Circular(0x0);
delay(5000000);
//蓝色布景,黄色实心圆
Brush_Background(0xff);
Draw_Circular(0xffff00);
delay(5000000);
//绿色布景,品色实心圆
Brush_Background(0xff00);
Draw_Circular(0xff00ff);
delay(5000000);
//赤色布景,青色实心圆
Brush_Background(0xff0000);
Draw_Circular(0xffff);
delay(5000000);
//青色布景,赤色实心圆
Brush_Background(0xffff);
Draw_Circular(0xff0000);
delay(5000000);
//品色布景,绿色实心圆
Brush_Background(0xff00ff);
Draw_Circular(0xff00);
delay(5000000);
//黄色布景,蓝色实心圆
Brush_Background(0xffff00);
Draw_Circular(0xff);
delay(5000000);
}
}

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/274517.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部