ARM-Linux学习 第二天

文件指针的学习

第一天中液晶屏显示颜色 成功了,但在我实验的时候有个问题。就是液晶屏只有一个颜色,不会循环播放。
后面百度后,原因是:当使用open()打开一个文件的时候,文件指针指向文件最开始的位置,每向文件写入一个字节,文件指针向文件的结尾移动一个位置。当液晶屏写入满屏红色数据的时候,文件指针执行文件的结束,此时再写入数据,数据就写到显存外面了,液晶屏显示的颜色就不会变化了。

指针超出解决方案

1.写入满屏颜色数据后,关闭文件。下次写入数据再打开。

void main()
{
	while(1)
	{
		1.open()//打开液晶屏
		2.write()//写入红色
		3.close()//关闭液晶屏

		1.open()//打开液晶屏
		2.write()//写入蓝色
		3.close()//关闭液晶屏
	}
}

2.使用lseek()函数移动文件指针
头文件有:#include <sys/types.h> 和 #include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);
参数说明:

   		int fd ---- file descriptor文件描述符,也就是需要移动文件指针的文件,open()的返回值
        off_t offset ---- 移动文件指针的字节数
		int whence ---- 移动文件指针的基准位置
   		SEEK_SET---从文件头开始移动文件指针
          			The offset is set to offset bytes.

   		SEEK_CUR----从文件当前位置开始移动文件指针
          			The offset is set to its current location plus offset bytes.

   		SEEK_END----从文件结束位置开始移动文件指针
         			 The offset is set to the size of the file plus offset bytes.

将lcd文件指针移动到文件最开始
lseek(fd_lcd, 0, SEEK_SET);

单色显示会出现花屏

原因和解决方法

原因:当使用 write() 系统调用函数向液晶屏的设备文件写入数据时,整个过程涉及到应用程序和Linux内核之间的数据传递。write() 函数本质上是一个系统调用,系统调用的开销较大,尤其是在频繁写入数据时,效率会非常低。因此,这种方式在传输大量数据时可能会导致显示效果不佳,如出现花屏现象。

方法:使用Linux系统中的内存映射函数,向Linux内核中的显存映射到应用程序中,得到应用程序中显存的首地址,通过该地址访问显存,这样提高数据传输效率。

内存映射

如果使用内存映射就需要将800*480的像素点全部填满。
#include <sys/mman.h>

   void *mmap(void *addr, size_t length, int prot, int flags,
              int fd, off_t offset);

参数说明:
void addr ---- 需要映射的内存中显示的首地址,如果使用NULL,系统自动获取
size_t length ---- 需要映射的内存的大小,显存的大小800
480*4
int prot ----- 映射后内存的访问属性,一般为PROT_READ|PROT_WRITE
int flags ---- 映射后显存的标志,MAP_SHARED—映射后的显存多个进程都可以访问
off_t offset ---- 映射内存的偏移量,一般为0;
返回值
void *----在应用程序中,得到映射后的显存的首地址,通过改地址就可以访问显存了。

显示各类国旗

int lcd_flag(int country){
    int fd_lcd;
    int *lcd_buf;
    int color[] = {black,red, yellow, blue, green, white}; 
    size_t len = SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(int); 

    fd_lcd = open("/dev/fb0", O_RDWR);
    if (fd_lcd == -1)
    {
        perror("open lcd ");
        return -1;
    }

    printf("fd_lcd = %d\n", fd_lcd);
    lcd_buf = (int *)mmap(0, len, PROT_WRITE | PROT_READ, MAP_SHARED, fd_lcd, 0);
    switch(country){
        case 1:
             for (int j = 0; j <3 ; j++)
            {
                for (int i = 160 *800*(j); i <  160 *800*(j+1) ; i++)
                    {
                        lcd_buf[i] = color[j];
                    }
                    sleep(1);
            }
            break;
        case 2:
            for(int i = 0;i<800*480;i++){
                 lcd_buf[i] = color[5];
            }
        break;
        case 3:
            for (int i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; i++) {
                lcd_buf[i] = color[5];
            }
            int xx=400,yy=240;
            for(int i=0;i<480;i++){
                for(int j=0;j<800;j++){
                    if((xx-j)*(xx-j)+(yy-i)*(yy-i)<=144*144){
                        lcd_buf[i*800+j]= color[1];
                    }
                }
            }
        break;

    }
    munmap(lcd_buf, len);
    close(fd_lcd);
    return 0;
}

LCD显示全屏bmp

1bmp图片
bmp图片是位图,是没有经过压缩的,该图片经过简单的处理,可以直接写入显存,并在液晶屏上显示。
注意bmp图片的格式,有两部分组成:
1)文件的头信息:54B
头信息的内容:可以查找资料,bmp图片的标准格式,里面包含图片的分辨率(像素点)、图片的色位(每个像素点使用多少位的数据来描述,bmp图片通常是24bits的,其中RGB各占8位)。
2)文件的颜色数据
800 * 480的bmp图:800 * 480 * 3
200 * 100的bmp图:200 * 100 * 3

图片显示翻转问题

问题:液晶屏显示的bmp图片是上下翻转的,
原因:液晶屏显示扫描的顺序:从左到右,从上到下,相当于液晶屏的原点是左上角。
bmp图片存放颜色顺序:从左到右,从下到上,相当于bmp图片的原点在左下角。
解决:
如果将液晶屏看成一个二维坐标,x是横轴,y是纵轴。如果需要图片上下翻转,则将y改成479-y。

代码如下:

int lcd_bmp(char *bmp_name)
{
    int fd_bmp = open(bmp_name, O_RDONLY);
    if (fd_bmp == -1)
    {
        perror("open bmp");
        return -1;
    }

    // BMP文件头54字节,跳过文件头读取颜色数据
    lseek(fd_bmp, 54, SEEK_SET);
    char bmp_buf[800 * 480 * 3]; // BMP颜色数据
    read(fd_bmp, bmp_buf, sizeof(bmp_buf));
    close(fd_bmp);

    int fd_lcd = open("/dev/fb0", O_RDWR);
    if (fd_lcd == -1)
    {
        perror("open lcd");
        return -1;
    }

    int *lcd_base = NULL; // 每个像素点占用内存是4B
    lcd_base = (int *)mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd_lcd, 0);
    if (lcd_base == MAP_FAILED)
    {
        perror("mmap");
        close(fd_lcd);
        return -2;
    }
    int n=0;
    for(int y=0;y<480;y++)
	for(int x=0;x<800;x++,n++)
    {
		*(lcd_base+800*(479-y)+x) =  (bmp_buf[3*n+2]<<16) | (bmp_buf[3*n+1] <<8) | (bmp_buf[3*n]<<0);
    }


    munmap(lcd_base, 800 * 480 * 4);
    close(fd_lcd);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值