linux下的lcd显示一个数组的内容,ARM裸板实现LCD显示

/* LCDCON1'BIT 0 : 设置LCD控制器是否输出信号 */

LCDCON1 &= ~(1<<0);

}

/*======================================================================================*/

4.6.从结构体变量获取LCD重要参数

代码如下:

/*获得结构体LCD参数函数*/

void get_lcd_params(unsigned int *fb_base, int *xres, int *yres, int *bpp)

{

*fb_base = lcd_4_3_params.fb_base;

*xres = lcd_4_3_params.xres;

*yres = lcd_4_3_params.yres;

*bpp = lcd_4_3_params.bpp;

}

4.7.写测试函数

有了上面的准备工作,从现在开始就显示简单一点了,刚开始写测试代码,为了显得简单一点,让整个屏幕显示出同一种颜色、

如何做呢?

直接往frambuffer填入颜色数值就行了。且设置bpp = 16,那么一个颜色的数据就占用两个字节。

代码如下:

/*LCD测试函数*/

void lcd_test(void)

{

unsigned int fb_base;

int xres, yres, bpp;

int x, y;

unsigned short *p;

/*初始化LCD*/

lcd_init();

/*获得参数*/

//这个函数获取得到的数值是在lcd_test里面使用的

get_lcd_params(&fb_base,&xres,&yres,&bpp);

/*判断bpp的数值*/

if (bpp == 16)

{

/* 让LCD输出整屏的红色 */

/* 565: 0xf800 */

p = (unsigned short *)fb_base;

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

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

*p++ = 0xf800;

/* green */

p = (unsigned short *)fb_base;

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

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

*p++ = 0x7e0;

/* blue */

p = (unsigned short *)fb_base;

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

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

*p++ = 0x1f;

/* black */

p = (unsigned short *)fb_base;

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

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

*p++ = 0;

}

}

接着在主函数中调用这个测试函数,如下:

int main()

{

while(1)

{

/*lcd测试函数*/

lcd_test();

}

return 0;

}

4.8.修改Makefile

在这里增加了lcd.c和lcd.h需要把它添加到编译的项目,如下:

all: start.o sdram_init.o interrupt.o nand_flash.o main.o  led.o uart.o   execption.o  timer.o lib1funcs.o my_printf.o  string_utils.o lcd.o

arm-linux-ld -T lcd.lds  $^ libgcc.a -o lcd.elf

arm-linux-objcopy -O binary -S lcd.elf lcd.bin

arm-linux-objdump -D lcd.elf > lcd.dis

%.o : %.c

arm-linux-gcc -march=armv4 -c -o $@ $<

%.o : %.S

arm-linux-gcc -march=armv4 -c -o $@ $<

clean:

rm *.bin *.o *.elf *.dis

4.9.编译下载

把代码上传到Linux系统编译,下载lcd.bin文件到开发版,复位之后,屏幕依次红绿蓝刷屏。

备注:此部分代码命令为:LCD显示01

5.画点函数实现

5.1.新建两个函数,drawpoint.c和drawpoint.h

1).编写drawpoint.c函数

在这个文件中需要用到一些,参数比如,分辨率,bpp,以及frambuffer的地址,因此,写一个函数来获取,然后保存在这个文件的全局变量中,以便这个文件调用,如下:

/* 获得LCD参数,static表示对外界这些变量是不可见的*/

static unsigned int fb_base;

static int xres, yres, bpp;

void drawpoint_get_lcd_params(void)

{

/*获得的参数保存在drawpoint.c的局部变量中,对外界不可见*/

get_lcd_params(&fb_base, &xres, &yres, &bpp);

}

在这里需要注意一个问题,RGB颜色都是32位的

3d5f4b4505de71d21c9e1b49a5c6dfcc.png

但是如果使用16bpp的话,颜色数据才两个字节,因此需要把32位的颜色数据转换为16位,且16bpp时数据组成格式是RGB565

把32bpp的颜色数据转换为16bpp

函数如下:

/* rgb: 0x00RRGGBB */

unsigned short convert32bppto16bpp(unsigned int rgb)

{

int r = (rgb >> 16)& 0xff;

int g = (rgb >> 8) & 0xff;

int b = rgb & 0xff;

/* rgb565 */

r = r >> 3;

g = g >> 2;

b = b >> 3;

return ((r<<11) | (g<<5) | (b));

}

接着实现画点函数,这个函数有三个参数,x,y代表坐标,第三个参数,代表这个点的颜色color

代码如下:

/* color : 32bit, 0x00RRGGBB

*

*/

void fb_drawpoint(int x, int y, unsigned int color)

{

unsigned char  *pc;  /* 8bpp */

unsigned short *pw;  /* 16bpp */

unsigned int   *pdw; /* 32bpp */

unsigned int pixel_base = fb_base + (xres * bpp / 8) * y + x * bpp / 8;

switch (bpp)

{

case 8:

pc = (unsigned char *) pixel_base;

*pc = color;

break;

case 16:

pw = (unsigned short *) pixel_base;

*pw = convert32bppto16bpp(color);

break;

case 32:

pdw = (unsigned int *) pixel_base;

*pdw = color;

break;

}

}

在这里需要清楚画点的原理,从上面可知,画点,其实就是往frambuffer特定的地址,填入颜色数据而已。那如何去计算这个值呢?

有一个LCD的屏幕如下面简图所示:

d28fac786f061940103a669ae5f24e1e.png

这个点如何计算呢?

算出y轴的偏移,即:   先算出一行所占的字节数,然后乘于 y0行  ===》  (xres * bpp /8) *y0,此时的点就是(0,y0)点的颜色数据

加上x轴的偏移,即:(xres * bpp /8) *y0  + x0*bpp/8  ,此时的点就是(x0,y0)的颜色数据

最后加上基地址就是在内存frambuffer对应颜色数据的值了。

还有一点需要注意:决定了每个像素所占字节的大小。

6.画圆画线函数

画圆画线的基础都是画点,圆和线都是由一个个点组成的,只要有了画点的基础,实现这个功能就是算法的问题了。

代码如下:

void draw_circle(int x, int y, int r, int color)

{

int a, b, num;

a = 0;

b = r;

/*画点之前先获得LCD参数*/

drawpoint_get_lcd_params();

while(22 * b * b >= r * r) // 1/8圆即可

{

fb_drawpoint(x + a, y - b,color); // 0~1

fb_drawpoint(x - a, y - b,color); // 0~7

fb_drawpoint(x - a, y + b,color); // 4~5

fb_drawpoint(x + a, y + b,color); // 4~3

fb_drawpoint(x + b, y + a,color); // 2~3

fb_drawpoint(x + b, y - a,color); // 2~1

fb_drawpoint(x - b, y - a,color); // 6~7

fb_drawpoint(x - b, y + a,color); // 6~5

a++;

num = (a * a + b * b) - r*r;

if(num > 0)

{

b--;

a--;

}

}

}

//-----------画线。参数:起始坐标,终点坐标,颜色--------

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

{

int dx,dy,e;

/*画点之前先获得LCD参数*/

drawpoint_get_lcd_params();

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)

{

fb_drawpoint(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)

{

fb_drawpoint(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)

{

fb_drawpoint(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)

{

fb_drawpoint(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)

{

fb_drawpoint(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)

{

fb_drawpoint(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)

{

fb_drawpoint(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)

{

fb_drawpoint(x1,y1,color);

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

y1-=1;

e+=dx;

}

}

}

}

}

修改lcd_test函数,调用画点画圆函数,如下:

/*LCD测试函数*/

void lcd_test(void)

{

unsigned int fb_base;

int xres, yres, bpp;

int x, y;

unsigned short *p;

/*初始化LCD*/

lcd_init();

/*获得参数*/

//这个函数获取得到的数值是在lcd_test里面使用的

get_lcd_params(&fb_base,&xres,&yres,&bpp);

//这个函数中获取的值是在画点函数中用的,

//fb_get_lcd_params();

/*获得字体需要用的LCD参数*/

//font_init();

/*判断bpp的数值*/

if (bpp == 16)

{

/* 让LCD输出整屏的红色 */

/* 565: 0xf800 */

p = (unsigned short *)fb_base;

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

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

*p++ = 0xf800;

/* green */

p = (unsigned short *)fb_base;

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

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

*p++ = 0x7e0;

/* blue */

p = (unsigned short *)fb_base;

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

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

*p++ = 0x1f;

/* black */

p = (unsigned short *)fb_base;

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

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

*p++ = 0;

}

delay(1000000);

/* 画线 */

draw_line(0, 0, xres - 1, 0, 0xff0000);

draw_line(xres - 1, 0, xres - 1, yres - 1, 0xffff00);

draw_line(0, yres - 1, xres - 1, yres - 1, 0xff00aa);

draw_line(0, 0, 0, yres - 1, 0xff00ef);

draw_line(0, 0, xres - 1, yres - 1, 0xff4500);

draw_line(xres - 1, 0, 0, yres - 1, 0xff0780);

delay(1000000);

/* 画圆 */

draw_circle(xres/2, yres/2, yres/4, 0xff00);

delay(1000000);

}

下载烧录,就可以看到画线和画圆的效果了。

备注:这个部分的代码命名为:LCD画线画圆

7.LCD输出字符串

字符串的显示的基础也是画点,字符都是由一个个点组成了,所以在输入字符之前,我们首先需要知道字体多大。

在这里使用 8 * 16 为例(宽为8,长为16,一个字符占用16个字节的数据),那么一个字符就需要占据128像素。

查看一下点阵文件中A字符的表示方法:

总共有16个字节数据,从左至右,从上至下,如果哪个字节的位为1,则画点,A字符由16字节组成的点阵字符

1d1a1fba7d81f093637962857bce86c6.png

同理,B的点阵字符集如下:

c4b188390c1fe495e77a1e61e172f066.png

由这样的一个一个字符的点阵集组成一个数组,就构成了LCD输出字符串的基础

32396545008b08c958f2c2b9ce9abcdf.png

备注:这些点阵字符在fontdata_8x16[ ] 数组中的排序方式是以ASCII码的方式。

如果想取出字符‘A’  点阵字符集,直接使用  fontdata_8x16[ A * 16 ]

字符A的ascii码是:65

有了这个点阵数组,和这些基础知识就可以开始写程序了。

先实现一个最简单的程序,在指定的坐标显示指定的单个字符。

1)、新建文件font.c和font.h文件

写font.c文件,实现输出字符函数

思路:

比如现在想打印出 'A'字符,那我们必须在刚才那个点阵数组中,把这个字符的16字节点阵数据取出来,然后读取这16字节数据的每一个点,根据数据来决定是否画点。

代码如下

/* 根据字母的点阵在LCD上描画文字 */

void fb_print_char(int x, int y, char c, unsigned int color)

{

int i, j;

/* 根据c的ascii码在fontdata_8x16中得到点阵数据的首地址 */

unsigned char *dots = &fontdata_8x16[c * 16];

unsigned char data;

int bit;

/* 根据点阵来设置对应象素的颜色 */

for (j = y; j < y+16; j++)   //总共需要写16个字节,循环16次

{

//先取出首字节数据,然后取出下一字节数据,

data = *dots++;

//先写最高位

bit = 7;

for (i = x; i < x+8; i++)//先第一行数据,循环8次

/* 点阵字节为1,则画点,否则不画点 */

if (data & (1

bit--;

}

}

}

输出字符串函数

字符串的输出的基础是单个字符的输出。

思路:把需要输出的字符串保存在一个数组中,然后依次读取出这个字符串数组的字符,如果不为空则打印出来,碰到 "nr"就换行并回到下一行的起始位置,继续打印数据。

代码如下:

void fb_print_string(int x, int y, char* str, unsigned int color)

{

int i = 0, j;

while (str[i])  //但str[i] 不为空

{

if (str[i] == 'n')

y = y+16;

else if (str[i] == 'r')

x = 0;

else

{

fb_print_char(x, y, str[i], color);  //在指定的位置输出一个字符

c2c9ed493cd281aa86d8a6f5178c4c01.gif [1] [2] [3] 610626052e95c7fbe3d254abc769d9ad.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值